相关阅读
C语言https://blog.csdn.net/weixin_45791458/category_12423166.html?spm=1001.2014.3001.5482
指向数组的指针和指向数组首元素的指针常常被混淆,或者笼统地被称为数组指针,但它们之间是有差别的,本文就将对此进行讨论。
下面的代码首先创建了一个数组,然后创建了指向该数组的指针和指向该数组首元素的指针。
int arr[] = {0,1,2};
int *ptr0 = arr; //创建了一个int型指针,指针值为数组首元素地址
int *ptr1 = &arr[0]; //创建了一个int型指针,指针值为数组首元素地址
int (*ptr2) [3] = &arr; //创建了一个int型数组指针,指针值为整个数组的地址
上面的三个指针,其实指针值都是一样的,即三个常量arr==&arr[0]==&arr(尽管这看起来有点奇怪),那他们有什么区别呢?
- &arr[0]与arr对于编译器来说没有任何区别,因此ptr0和ptr1两个指针的各种性质都是一样的。
- &arr这个常量值虽然与其他两者相同,但是对编译器而言,它代表了整个数组的地址,因此当&arr与其他数加减时,会将其他数转化为以数组的字节数为单位的地址值,对于指针ptr2来说也是如此。
例1
int arr[] = {0,1,2};
//下面两条语句等价
int *ptr0 = arr; //创建了一个int型指针,指针值为数组首元素地址
int *ptr1 = &arr[0]; //创建了一个int型指针,指针值为数组首元素地址
int (*ptr2) [3] = &arr; //创建了一个int型数组指针,指针值为整个数组的地址
printf("arr is %p\n", arr);
printf("arr + 1 is %p\n", arr + 1);
printf("&arr[0] is %p\n", &arr[0]);
printf("&arr[0] + 1 is %p\n", &arr[0] + 1);
printf("&arr is %p\n", &arr);
printf("&arr + 1 is %p\n", &arr + 1);
printf("ptr0 is %p\n", ptr0);
printf("ptr0 + 1 is %p\n", ptr0 + 1);
printf("ptr1 is %p\n", ptr1);
printf("ptr1 + 1 is %p\n", ptr1 + 1);
printf("ptr2 is %p\n", ptr2);
printf("ptr2 + 1 is %p\n", ptr2 + 1);
输出:
arr is 000000000061FDFC
arr + 1 is 000000000061FE00
&arr[0] is 000000000061FDFC
&arr[0] + 1 is 000000000061FE00
&arr is 000000000061FDFC
&arr + 1 is 000000000061FE08
ptr0 is 000000000061FDFC
ptr0 + 1 is 000000000061FE00
ptr1 is 000000000061FDFC
ptr1 + 1 is 000000000061FE00
ptr2 is 000000000061FDFC
ptr2 + 1 is 000000000061FE08
从上面的例1可以看到arr、&arr[0]、&arr、ptr0、ptr1、ptr2的值都是相同的,但是arr、&arr[0]、ptr0、ptr1加1在编译后对地址值加了4,因为int类型占4字节的空间;&arr、ptr2加1在编译后对地址值加了12,因为数组含有三个int类型的数据,因此数组占12字节的空间。
指向数组的指针在使用多维数组时常见,如下面的例2所示。
例2
int arr[2][2] = {{0,1},{2,3}}; //创建一个多维数组
int (*ptr0) [2][2] = &arr; //创建了一个int型二维数组指针,指针值为二维数组的地址
//下面两条语句等价
int (*ptr1) [2] = arr; //创建了一个int型一维数组指针,指针值为两个数组中第一个数组的地址
int (*ptr2) [2] = &arr[0]; //创建了一个int型一维数组指针,指针值为两个数组中第一个数组的地址
int *ptr3 = arr[0]; //创建了一个int型指针,指针值为两个数组中第一个数组的首元素地址
int *ptr4 = &arr[0][0]; //创建了一个int型指针,指针值为两个数组中第一个数组的首元素地址
printf("ptr0 is %p\n", ptr0);
printf("ptr0 + 1 is %p\n", ptr0 + 1);
printf("ptr1 is %p\n", &arr[0]);
printf("ptr1 + 1 is %p\n", ptr1 + 1);
printf("ptr2 is %p\n", ptr2);
printf("ptr2 + 1 is %p\n", ptr2 + 1);
printf("ptr3 is %p\n", ptr3);
printf("ptr3 + 1 is %p\n", ptr3 + 1);
printf("ptr4 is %p\n", ptr4);
printf("ptr4+ 1 is %p\n", ptr4 + 1);
输出:
ptr0 is 000000000061FDE0
ptr0 + 1 is 000000000061FDF0
ptr1 is 000000000061FDE0
ptr1 + 1 is 000000000061FDE8
ptr2 is 000000000061FDE0
ptr2 + 1 is 000000000061FDE8
ptr3 is 000000000061FDE0
ptr3 + 1 is 000000000061FDE4
ptr4 is 000000000061FDE0
ptr4+ 1 is 000000000061FDE4
可以看到,即使ptr0、ptr1、ptr2、ptr3的值都是一样的,ptr0+1在编译后对地址值加了16(二维数组占4个字节空间),ptr1+1和ptr2+1在编译后对地址值加了8(一维数组占8个字节空间),ptr3+1在编译后对地址值加了4(int类型占4个字节空间)。
下面的例3展示了如何使用指向数组的指针和指向数组首元素的指针。文章来源:https://www.toymoban.com/news/detail-787644.html
例3
int arr[] = {0,1,2};
//下面两条语句等价
int *ptr0 = arr; //创建了一个int型指针,指针值为数组首元素地址
int *ptr1 = &arr[0]; //创建了一个int型指针,指针值为数组首元素地址
int (*ptr2) [3] = &arr; //创建了一个int型数组指针,指针值为整个数组的地址
printf("arr[0] is %d\n", ptr0[0]); //使用指向数组首元素的指针和[]打印0
printf("arr[1] is %d\n", ptr0[1]); //使用指向数组首元素的指针和[]打印1
printf("arr[2] is %d\n", ptr0[2]); //使用指向数组首元素的指针和[]打印2
printf("arr[0] is %d\n", arr[0]); //使用数组名和[]打印0
printf("arr[1] is %d\n", arr[1]); //使用数组名和[]打印1
printf("arr[2] is %d\n", arr[2]); //使用数组名和[]打印2
//一个很傻的例子,它是不必要的
printf("arr[0] is %d\n", (&arr[0])[0]); //使用首元素地址和[]打印0
printf("arr[1] is %d\n", (&arr[0])[1]); //使用首元素地址和[]打印1
printf("arr[2] is %d\n", (&arr[0])[2]); //使用首元素地址和[]打印2
//实际上还能更傻,这么做的可读性很差
printf("arr[0] is %d\n", (&((&arr[0])[0]))[0]); //奇怪地打印0
printf("arr[1] is %d\n", (&((&arr[0])[0]))[1]); //奇怪地打印1
printf("arr[2] is %d\n", (&((&arr[0])[0]))[2]); //奇怪地打印2
//尽管ptr2的值和ptr1、ptr0一样,但仍需先用*解引用才能再使用[]访问元素
printf("arr[0] is %d\n", (*ptr2)[0]); //使用指向数组的指针和[]打印0
printf("arr[1] is %d\n", (*ptr2)[1]); //使用指向数组的指针和[]打印1
printf("arr[2] is %d\n", (*ptr2)[2]); //使用指向数组的指针和[]打印2
printf("arr[0] is %d\n", ptr2[0]); //错误的
printf("arr[1] is %d\n", ptr2[1]); //错误的
printf("arr[2] is %d\n", ptr2[2]); //错误的
printf("arr[0] is %d\n", *(ptr0 + 0)); //使用指向数组首元素的指针和*打印0
printf("arr[1] is %d\n", *(ptr0 + 1)); //使用指向数组首元素的指针和*打印1
printf("arr[2] is %d\n", *(ptr0 + 2)); //使用指向数组首元素的指针和*打印2
printf("arr[0] is %d\n", *(arr + 0)); //使用数组名和*打印0
printf("arr[1] is %d\n", *(arr + 1)); //使用数组名和*打印1
printf("arr[2] is %d\n", *(arr + 2)); //使用数组名和*打印2
//尽管ptr2的值和ptr1、ptr0一样,但仍需先用*解引用才能再使用*访问元素
printf("arr[0] is %d\n", *((*ptr2) + 0)); //使用指向数组的指针和*打印0
printf("arr[1] is %d\n", *((*ptr2) + 1)); //使用指向数组的指针和*打印1
printf("arr[2] is %d\n", *((*ptr2) + 2)); //使用指向数组的指针和*打印2
printf("arr[0] is %d\n", *(ptr2 + 0)); //错误的
printf("arr[1] is %d\n", *(ptr2 + 1)); //错误的
printf("arr[2] is %d\n", *(ptr2 + 2)); //错误的
相信通过本文,读者应该对指向数组的指针和指向数组首元素的指针有了充分的认识,并可以在之后的编程中得心应手的运用指针了。文章来源地址https://www.toymoban.com/news/detail-787644.html
到了这里,关于C语言:指向数组的指针和指向数组首元素的指针的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!