指针数组和数组指针的总结指针数组本质是数组 只是数组的每个元素是指针数组指针本质是指针变量 只是保存的是数组的首元素二维数组的分析案例int arr[3][4]*arr2:第0行 第2列的列地址arr[1]:*(arr1)第1行第0列的列地址arr[0]2:*(arr0)2 arr2:第2行的行地址**arr:**arr *(arr0)0) arr[0][0]数组指针 和 二维数组 的关系void test01() { int arr[3][4]{{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int i0,j 0; //数组指针 本质是指针变量 int (*p)[4] arr; printf(%d\n,sizeof(p)); //在32位为4,64位为8 // sizeof(*p) 计算的是整个一维数组的大小4个int * 4字节 16字节。 for(i0;i3;i) { for(j0;j4;j) { //printf(%d,*(*(pi)j)); printf(%d ,p[i][j]); } printf(\n); } return; }任何维度的数组 在物理存储上 都是一维的通过一维数组访问二维void test01() { int arr[3][4]{{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int i0; int *p arr;//arr[0][0] //遍历数组 for(i0;i3*4;i) { printf(%d ,*(pi));//*(pi)p[i] } return; }多级指针1级指针变量 保存 0级指针变量普通变量的地址2级指针变量 保存 1级指针变量普通变量的地址3级指针变量 保存 2级指针变量普通变量的地址n级指针变量 保存 n-1级指针变量普通变量的地址指针作为函数的参数如果想在函数内部修改外部变量的值 就需要将外部变量的地址传递给函数以指针变量作为函数的参数案例形参无法改变实参----指针作为函数参数来修改实参void my_swap(int a,int b) { int tmp ; tmp a; a b;; b tmp; //仅仅是修改形参 对外部的实参无影响 } void test01() { int data110;data220; pintf(data1%d,data2%d\n,data1,data2);//10,20 //如果传递的是值 函数内部 无法修改 外部变量值 my_swap(data1,data2); pintf(data1%d,data2%d\n,data1,data2);//10,20并没有交换data1和data2的数据 return; }无法修改实参 因此需将data1和data2的地址传递到函数void my_swap(int *p1,int *p2) { int tmp *p1; *p1 *p2; *p2 tmp; } void test01() { int data110,data220; pintf(data1%d,data2%d\n,data1,data2);//10,20 //函数内部 修改外部变量的值 需传递外部变量的地址 my_swap(data1,data2);//对变量取地址 则 整个表达式的类型 是自身的类型* int * pintf(data1%d,data2%d\n,data1,data2);//2010 }案例在函数内部给p更改指向给p赋值---传递p的地址#includestdio.h //宏展开的本质是替换 void my_swap(int **tmp_p) { static int num 100; //*tmp_p num;//pnum; *tmp_p num; } void test01() { int *p NULL; //函数内部 修改外部变量的值 需传递外部变量的地址 my_swap(p);//对变量取地址 则 整个表达式的类型 是自身的类型* int * printf(*p %d\n,*p);//10,20并没有交换data1和data2的数据 } int main(int argc, char *argv[]) { test01(); return 0; }一维数组名作为函数的参数1.如果函数内部想操作读、写外部数组的元素将外部数组的数组名传递给函数2.一维数组作为函数的形参 会被优化成一级指针变量案例#includestdio.h //void my_swap(int arr[5],int n) //一维数组 作为函数的形参会被优化成 指针变量 void my_swap(int *arr,int n) { int i 0; for(i 0;in;i) { scanf(%d,arri); } } void my_print_array(int *arr,int n) { int i 0; for(i 0;in;i) { printf(%d ,*(arri));//arr[i] } } void test01() { //arr作为类型 代表的是数组的总大小 //arr作为地址 代表的是数组的首元素地址 int arr[5]{0}; int n sizeof(arr)/sizeof(arr[0]); //定义一个函数 给arr获取键盘输入 my_swap(arr,n); printf(\n); //定义一个函数 遍历数组元素 my_print_array(arr,n) ; } int main(int argc, char *argv[]) { test01(); return 0; }二维数组名作为函数的参数1.如果函数内部想操作读、写外部数组的元素将外部数组的数组名传递给函数2.二维数组名 作为函数的形参 会被优化成 数组指针intarr[5]--------int*pintarr[3][4]------int(*p)[4]int arr[3][4][5]------int (*p)[4][5]int arr[[3][4][5][6]----int (*p)[4][5][6]#includestdio.h //void my_swap(int arr[5],int n) //二维数组 作为函数的形参会被优化成 数组指针int *arr 【4】 void my_print_two_array(int (*arr)[4],int row,int col) { int i 0; int j 0; for(i 0;irow;i) { for(j0;jcol;j) { printf(%d ,arr[i][j]); } } } void test01() { int arr[3][4]{1,2,3,4,5,6,7,8,9,10,11,12}; int row sizeof(arr)/sizeof(arr[0]); int col sizeof(arr[0])/sizeof(arr[0][0]); my_print_two_array(arr,row,col); printf(\n); } int main(int argc, char *argv[]) { test01(); return 0; }指针作为函数的返回值1.函数不要返回普通局部变量的地址#includestdio.h int* get_addr(void) { int num 1000; return num;//不要返回普通局部变量地址 } void test01() { int *p NULL; p get_addr(); printf(*p%d\n,*p);//不确定 } int main(int argc, char *argv[]) { test01(); return 0; }2.解决上述问题用 static修饰int num------static int num 1000;静态变量 函数结束 不会被释放函数名 代表的是函数的入口地址#includestdio.h int my_add(int a,int b) { return ab; } void test01() { //定一个指针变量 保存该函数的入口地址 //函数指针 本质是指针变量 保存的是函数的入口地址 int (*p)(int,int)NULL; printf(%p\n,my_add); //my_add代表的是函数的入口地址 p my_add; printf(%p\n,p); //函数调用函数入口地址 printf(%d\n,my_add(10,20)); printf(%d\n,p(100,200)); //对函数指针变量 取*无意义 } int main(int argc, char *argv[]) { test01(); return 0; }案例用函数指针作为形参#includestdio.h int my_add(int a,int b) { return ab; } int my_sub(int a,int b) { return a-b; } int my_mul(int a,int b) { return a*b; } //定义一个函数 实现上述功能 int test01(int a,int b,int (*p)(int ,int )) { return p(a,b); } int main(int argc, char *argv[]) { printf(%d\n,test01(10,20,my_add)); printf(%d\n,test01(10,20,my_sub)); printf(%d\n,test01(10,20,my_mul)); return 0; }动态内存分配malloc和free函数malloc#includestdlib.h void *malloc(unsigned int num_size) //形参num_size需要申请空间大小的字节数 //返回值 //成功返回空间的起始地址 //失败NULL //特点 //1.对于malloc的返回值为void *类型 一般要强制类型转换 //2.malloc申请的空间 内容不确定 一般使用memset进行清空 //3.多次调用malloc 第一次和第二次申请的地址不一定连续free函数void free(void *addr); //释放堆区空间案例从堆区申请int型空间#includestdio.h #includestdlib.h int test01() { int *addr NULL; addr (int *)malloc(sizeof(int));//强转从堆区申请一个int if(addr NULL)//申请失败 { printf(malloc err\n); return; } printf(*addr %d\n,*addr);//不确定 //对堆区空间清0 memset(addr,0,sizeof(int)); printf(*addr %d\n,*addr);//0 //对addr的空间进行写或读操作 *addr 1000;//写 printf(*addr %d\n,*addr);//读 //释放堆区空间 空间使用权限的回收 对空间内容是否清0不确定 free(addr); } int main(int argc, char *argv[]) { test01(); return 0; }案例从堆区申请一个数组 数组的大小由用户决定---动态决定#includestdio.h #includestdlib.h int test01() { int n 0; int i 0; //1.获取用户大小 printf(请输入元素个数); scanf(%d,n); int *addr NULL; //2.根据大小从堆区申请空间 addr (int *)malloc(n*sizeof(int));//强转从堆区申请一个int if(addr NULL)//申请失败 { perror(malloc);//错误输出 return; } //对堆区空间清0 memset(addr,0,n*sizeof(int)); for(i0;in;i) { scanf(%d,addri); } for(i0;in;i) { printf(%d ,addr[i]); } //释放堆区空间 空间使用权限的回收 对空间内容是否清0不确定 free(addr); } int main(int argc, char *argv[]) { test01(); return 0; }案例 从堆区申请一个数组 数组的大小由用户决定---函数版本#includestdio.h #includestdlib.h int get_n(void) { int n 0; printf(请输入元素个数); scanf(%d,n); return n ; } int* get_arr(int n) { int *ret NULL; ret (int *)malloc(n*sizeof(int)); if(ret NULL)//申请失败 { perror(malloc);//错误输出 return NULL; } return ret; } void my_input_array(int *arr,int n) { int i 0; //将arr指向的空间清零 memset(arr,0,n*sizeof(int)); printf(请输入); for(i0;in;i) { scanf(%d,arri); } } void my_print_array(int *arr,int n) { int i 0; for(i0;in;i) { printf(%d ,arr[i]); } } int test01() { int *arr NULL; int n 0; int i 0; //1.获取用户大小 n get_n(); printf(%d\n,n); //2.定义函数 给arr申请堆区地址 arr get_arr(n); if(arr NULL)//申请失败 { perror(malloc);//错误输出 return; } //对空间读写操作 my_input_array(arr, n); my_print_array(arr, n); //释放堆区空间 空间使用权限的回收 对空间内容是否清0不确定 free(arr); } int main(int argc, char *argv[]) { test01(); return 0; }calloc函数案例#includestdio.h #includestdlib.h int test01() { int n 0; int i 0; //1.获取用户大小 printf(请输入元素个数); scanf(%d,n); int *addr NULL; //2.根据大小从堆区申请空间 // addr (int *)malloc(n*sizeof(int));//强转从堆区申请一个int addr (int *)calloc(n,sizeof(int));//自动清0 不需要使用memset if(addr NULL)//申请失败 { perror(malloc);//错误输出 return; } //对堆区空间清0 // memset(addr,0,n*sizeof(int)); for(i0;in;i) { scanf(%d,addri); } for(i0;in;i) { printf(%d ,addr[i]); } //释放堆区空间 空间使用权限的回收 对空间内容是否清0不确定 free(addr); } int main(int argc, char *argv[]) { test01(); return 0; }realloc动态追加或减少空间一定要记住 保存他的返回值arr relloc(arr,40);#includestdio.h #includestdlib.h #includestring.h//memset int test01() { int n 0; int *addr NULL; int i 0; int n_new 0; //1.获取用户大小 printf(请输入元素个数); scanf(%d,n); addr (int *)calloc(n,sizeof(int));//自动清0 不需要使用memset if(addr NULL)//申请失败 { perror(malloc);//错误输出 return; } for(i0;in;i) { scanf(%d,addri); } for(i0;in;i) { printf(%d ,addr[i]); } //追加5个元素 printf(请输入新增的元素个数\n); scanf(%d,n_new); addr (int *)realloc(addr,(nn_new)*sizeof(int)); printf(请输入新增的%d个int数据\n,n_new); for(in;i(nn_new);i) { scanf(%d,addri); } for(i0;i(nn_new);i) { printf(%d ,addr[i]); } //释放堆区空间 空间使用权限的回收 对空间内容是否清0不确定 free(addr); } int main(int argc, char *argv[]) { test01(); return 0; }