数组指针/指针数组和一/二级指针

数组指针和指针数组

二级指针的作用详解

首先确定优先级:()>[]>*,另外数组指针,类比整型指针,表示指向数组的指针;指针数组,类比整型数组,表示元素为指针的数组。

数组指针

int (*p)[n] 首先()优先级高,它是一个指针,指向一个整型数组。n为数组的长度,当p+1时需要跨越n个整型数据的长度,通常用来表示二维数组及二维数组的函数传参。

一维数组赋值给数组指针时,需要取数组地址或对其进行强制转换,另外相当于二维数组中只有一个行元素,p3+1的地址没有意义,*(p3+1)也无法显示。

1 char a[5] = { 'A', 'B', 'C', 'D' };
2 char(*p3)[5] = &a;
3 char(*p4)[5] = (char (*)[5])a;

 二维数组赋值给数组指针时,具体间接访问格式,可以参考上一篇博文指针和数组的关系

 1 # include <stdio.h>
 2 int main(void)
 3 {
 4     int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
 5     int i, j;
 6     int (*p)[4] = a;  //记住这种定义格式
 7     for (i=0; i<3; ++i)
 8     {
 9         for (j=0; j<4; ++j)
10         {
11             printf("%-2d\x20", *(*(p+i)+j));  /*%-2d中, '-'表示左对齐, 如果不写'-'则默认表示右对齐;2表示这个元素输出时占两个空格的空间*/
12         }
13         printf("\n");
14     }
15     return 0;
16 }

二维数组元素地址赋值给一维指针,对元素进行访问时需要跨越n个整型数据的长度,即p + i*N +j == &a[i][j]

 1 # include <stdio.h>
 2 int main(void)
 3 {
 4     int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
 5     int i, j;
 6     int *p = &a[0][0];  //把a[0][0]的地址赋给指针变量p
 7     for (i=0; i<3; ++i)
 8     {
 9         for (j=0; j<4; ++j)
10         {
11             printf("%-2d\x20", *(p+i*4+j));
12         }
13         printf("\n");
14     }
15     return 0;
16 }

 

指针数组

 int *p[n] 首先[]优先级高,它是一个数组,前面为int*,表示数组的元素为整型指针,也可表示为int **p, 这里执行p+1时,则p指向下一个数组元素,这样赋值是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量,可以用来存放变量地址。

其中C中处理字符串和链表数据结构中用该数据类型较多,涉及到二级指针时也容易出问题。

 1 int a = 1;
 2 int b = 2;
 3 int *p[2];
 4 p[0] = &a;
 5 p[1] = &b;
 6 
 7 printf("%p\n", p[0]); //a的地址
 8 printf("%p\n", &a); //a的地址
 9 printf("%p\n", p[1]); //b的地址
10 printf("%p\n", &b); //b的地址
11 printf("%d\n", *p[0]); //p[0]表示a的地址,则*p[0]表示a的值
12 printf("%d\n", *p[1]); //p[1]表示b的地址,则*p[1]表示b的值
13 
14 
15 //将二维数组赋给指针数组
16 int *pp[3]; //一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2],所以要分别赋值
17 int c[3][4];
18 for (int i = 0; i < 3; i++)
19     pp[i] = c[i];

数组指针是一个指针变量,占有内存中一个指针的存储空间;

指针数组是多个指针变量,以数组的形式存储在内存中,占有多个指针的存储空间。

指向二维数组时,指针数组和数组指针访问数组元素时完全相同,但函数传参时,只能用数组指针,原因参见指针和数组的关系

int a[2][3] = { { 0, 1, 2 }, { 3, 4, 5 } }; //2行3列的二维整型数组
int(*p)[3]; //数组指针,指向含有3个元素的一维数组
int *q[2]; //指针数组,一个数组内存放2个指针变量

p = a;
q[0] = a[0];
q[1] = a[1];

//输出第1行第2列的值
printf("%d\n", a[1][2]); //5

printf("%d\n", *(p[1] + 2)); //5
printf("%d\n", *(*(p + 1) + 2)); //5
printf("%d\n", (*(p + 1))[2]); //5
printf("%d\n", p[1][2]); //5

printf("%d\n", *(q[1] + 2)); //5
printf("%d\n", *(*(q + 1) + 2)); //5
printf("%d\n", (*(q + 1))[2]); //5
printf("%d\n", q[1][2]); //5

一级指针和二级指针

 在进行函数指针传参时,编译器总是要为函数的每个参数制作临时副本(即形参为实参的副本),在调用的时候,实参和形参是不同的内存空间,只是,这个内存空间存放的指针指向的是同一块地址 ,所以形参在函数执行中可以访问实参指向的内存空间,但是形参的指向的改变(即形参所指向的内存空间与实参不同)并不能影响实参,但改变形参所指向的空间的值时(改变形参指向的内存空间的值),实参指向会改变。

一级指针的作用:在函数外部定义一个值m,在函数内对m进行赋值改变,函数结束后对值m生效。一级指针不管形参、实参都指向值m的地址,对一级指针进行解引用时都是访问m的地址空间,然后访问m,因此若改变形参指向的空间的值(即改变了m的值),则实参也会改变。

二级指针作用:在函数外部定义一个指针p,在函数内给指针赋值,函数结束后对指针p生效。二级指针不管形参、实参都指向指针p,对二级指针进行解引用时都是先访问指针p的地址空间,再访问指针p,因此若改变形参指向的空间的值(即改变了指针p的值),则实参也会改变。

如果用了二级指针,但不想改变外部的指针p,可以在函数内部对二级指针指向的空间的值做一个拷贝。

 1 void  my_malloc(char **s)  
 2 {  
 3     *s=(char*)malloc(100);  
 4 }  
 5  
 6 void  main()  
 7 {  
 8     char  *p=NULL;  
 9     my_malloc(&p);
10     //do something
11     if(p)
12         free(p);  
13 }  

这里给指针p分配内存,do something,然后free(p),如果用一级指针,那么就相当于给一个p的拷贝s分配内存,p依然没分配内存,用二级指针之后,才对p分配了内存。

应用上面的二级指针的例子

 1 void getstring_(char **p){
 2     //char *p;
 3     *p = malloc(100);
 4     memset(*p, 0, 100);
 5     strcpy(*p, "hello");
 6 }
 7 
 8 void test_(){
 9     char *ret = NULL;
10     getstring_(&ret);
11     printf("%s\n", ret);
12 }
13 
14 int main(){
15     test_();
16 
17     system("pause");
18     return 0;
19 }

 

posted @ 2018-12-13 21:03  两猿社  阅读(10497)  评论(1编辑  收藏  举报