一、指针是什么?
- 含义:内存被划分为一个个小的内存单元,每个内存单元都有一个编号,编号也称为地址,地址在C语言中被称为指针。
指针(地址)需要存储起来,存储在变量中,这个变量就被称为指针变量。
int a=10; int* pa=&a;
比如要存储变量a到pa里,&a就是a的地址,pa就是指针变量,还要说明pa的类型是int*。
- 指针的大小:在32位平台上是4个字节,在64位平台上是8个字节
二、字符指针
顾名思义是用来存放字符的地址
2.1 字符指针的两种使用方法
在初阶指针,学习了字符指针的一般使用方式:
#include<stdio.h> //字符指针 int main() { char ch= "w"; char* pc =&ch; pc = "a"; return 0; }
方法思路:改变ch的字符,可以直接用ch来改,但是字符指针pc的好处就是可以代替ch去改,把ch的地址存到pc,pc就可以通过地址找到ch,改变ch的字符,有种借刀杀人的意思。
本章继续学习另一种使用方法
int main() { //创建arr字符数组,用abcdef给arr初始化 //相当于在内存中创建数组,里面放了[a b c d e f \0] char arr[] = "abcdef"; //在x86环境下,p指针是4个字节,abcdef是放不完的 //不是把abcdef放进p指针 //思路:给p一个地址,向后打印字符串 //就是是把首元素a的地址赋给p,让p找到字符串的起始位置 //注意:字符串是常量字符串,不能被改,在*左边加上const,限制p不能改字符串 const char* p ="abcdef"; //打印字符串,要指定格式%s,还要给p一个起始地址,从这个地址向后打印字符串 printf("%s\n", p); //给p解引用,打印字符串的首字符a printf("%c", *p); return 0; }
三、指针数组
是数组,是存放指针的数组
类比:
- 整型数组:存放整型的数组
- 字符数组:存放字符的数组
int main() { int arr[10];//存放整型数组 int* arr[10];//存放整型指针数组 char* arr[5];//一级字符指针数组 char* arr[6];//二级字符指针的数组 return 0; }
四、数组指针
4.1数组指针的定义
是指针,是指向数组变量的指针,存放数组变量的地址的指针变量
类比:
- 整型指针:指向整型变量的指针,存放整形变量的地址的指针变量
- 字符指针:指向字符变量的指针,存放字符变量的地址的指针变量
指针数组和数组指针的区别
int* p1[10];
p1是数组,元素有10个,每个元素的类型是int*
int(* p2)[10];
p2和*结合,p2是指针,p2外边是数组int[10],说明p2指向的是数组,所以p2是数组指针变量
4.2 &数组名 VS 数组名
数组名的理解
int main() { //arr和&arr[0]的地址一样 //说明数组名是数组首元素的地址 int arr[10] = { 0 }; printf("%p\n", arr); printf("%p\n", &arr[0]); printf("%d\n", sizeof(arr)); printf("%p\n", &arr); return 0; }
两个例外
1.sizeof(数组名),这里的数组名不是数组首元素的地址, 而是代表整个数组,sizeof(数组名)计算整个数组的大小, 单位是字节
2.&数组名,这里的数组名表示整个数组,&数组名取出的是整个数组的地址 单纯打印出来和首元素地址一样,没有区别,但调试起来发现它们的类型不一样
验证第二点:
int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; printf("%p\n", arr); printf("%p\n", arr + 1);//跳过一个元素,4个字节 printf("%p\n", &arr[0]); printf("%p\n", &arr[0] + 1);//跳过一个元素,4个字节 printf("%p\n", &arr); printf("%p\n", &arr + 1);//跳过整个数组,40个字节 return 0; }
4.3 数组指针的使用方法
- 普通的二维数组传参
void print(int arr[4][5], int r, int c)//数组,行,列接收 { int i = 0; for (i = 0; i < r;i++)//第i行 { int j = 0; for (j = 0; j < c; j++)//循环打印第i行的每个元素 { printf("%d ", arr[i][j]); } printf("\n");//换行 } } int main() { int arr[4][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7, 4,5,6,7,8 }; print(arr, 4, 5); return 0; }
- 用数组指针传参
思路:
void print(int(*p)[5], int r, int c)//用数组指针,行,列接收 { int i = 0; for (i = 0; i < r; i++)//第i行 { int j = 0; for (j = 0; j < c; j++)//循环打印第i行中的每个元素 { //p是数组第一行的地址,相当于首元素的地址,p+i是找到数组第i行的地址 //*(p+i) 是找到第i行中的每一个元素的地址 //*(p+i)+j 是找到第i行第j列的地址 //*(*(p + i) + j) 是给地址解引用,找到第i行第j列的那个元素 printf("%d ", *(*(p + i) + j)); } printf("\n");//换行 } } int main() { int arr[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7 }; print(arr,3,5);//把数组,行,列传过去 return 0; }
五、数组参数,指针参数
5.1 一维数组传参
- 一维数组传参可以是数组,也可以是指针
- 形式上两种都可以,但本质上数组传参就是指针传参,只不过写成数组更直观
void test1(int arr[5], int sz) { } void test2(int* p, int sz) { } int main() { int arr[5] = { 0 }; test1(arr,5); test2(arr, 5); return 0; }
5.2二维数组传参
二维数组传参可以是数组,也可以是指针
void test3(char arr[3][5], int r, int c)//行可以省略,[3][5]可以写成[][5],但不能像数组指针那样写成[5] { } void test4(char(*p)[5], int r, int c)//行可以省略,[3][5]可以写成[5] { } int main() { char arr[3][5] = { 0 };//char或int初始化都是0 test3(arr, 3, 5); test4(arr, 3, 5); return 0; }
需要注意的是:
可以用数组指针传参,也可以用数组传参,但是不能用指针数组传参
错误写法:用指针数组传参:void test (int* arr[5])
5.3一级指针传参
void print(int* p, int sz) { int i = 0; for (i = 0; i < sz; i++) { printf("%d ", *(p+i)); } } int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int* p = arr;//把首元素的地址赋给指针p int sz = sizeof(arr) / sizeof(arr[0]);//计算数组大小 print(p, sz);//传一级指针p和数组的大小给函数 return 0; }
思考:
当一个函数的的参数部分是一级指针时,函数可以接收什么参数?
void test(char* p) { } int main() { return 0; }
思路: 传的实参类型要跟形参类型完全匹配上。
char ch = '2';
//单引号里面只能放一个任何类型的字符test(&ch);
//传字符变量的地址char* ptr = &ch;
//把ch的地址取出来放进ptr里test(ptr);
//ptr是char类型的,参数也用char类型的指针接收它char arr[] = "abcdef";
//字符数组test(arr);
//传字符数组的首元素地址,参数用char*类型接收
5.4二级指针传参
void test(int **ptr)//用二级指针接收 { } int main() { int n = 10; int* p = &n; //把n的地址放进指针变量p里,p是一级指针 int** p1 = &p; //对一级指针p取地址赋给p1,p1是二级指针 test(p1); //第一种传参 //传二级指针p1,因为p的地址赋给了p1 test(&p); //第二种传参 //传p的地址,因为p接收了n的地址,再传p的地址,&p就是二级指针 return 0; }
思考:
当一个函数的的参数部分是二级指针时,函数可以接收什么参数?
void test(char** ptr) { } int main() { char n = 'a'; return 0; }