C-指针数组与数组指针
Posted khrushchefox
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C-指针数组与数组指针相关的知识,希望对你有一定的参考价值。
指针数组
- 用于存放指针的数组
int a = 1, b = 2, c = 3;
int* arr[3] = &a, &b, &c;
// arr[0] == &a
// *arr[0] == a
int** p = arr;
// *p == arr[0] == &a
// p[0] == arr[0] == &a
// *(p+1) == arr[1] == &b
// **p == *arr[0] == a
// *p[0] == *arr[0] == a
// **(p+1) == *arr[1] == b
数组指针
- 用于指向整个数组的指针
int a[3];
int (*p)[3] = &a;
// p = &a;
printf("%d, %d, %d", *(*p), *(*p+1), *(*p+2));
// (*p)[0], (*p)[1], (*p)[2]
// 1, 2, 3
p, &a 代表的是整个数组的首地址,指向了整个数组
*p 是指向首元素的指针, 表示所指向数组中首个元素的地址
- 数组指针可以处理二维数组
int arr[][3] = 1, 2, 3, 4, 5, 6; // 2*3
int (*p)[3] = arr;
// 不需要对二维数组取地址, 此时数组指针指向的是二维数组中的第一个元素(数组)
printf("%d", *(*p+1)); // 2
printf("%d", *(*(p+1)+2)); // 6
printf("%d", p[1][2]); // 6
一个关于C语言的指针与二维数组的问题
自己写了段简短的代码来验证数组地址,数组内容和指针之间的关系。。
如下:
#include<stdio.h>
void main()
int zippo[4][3]= 2,4,1, 6,8,1, 1,3,1, 5,7,1;
printf(" zippo=%p, zippo+1=%p \n", zippo , zippo+1 );
printf(" *zippo=%p, *zippo+1=%p\n" , *zippo, *zippo+1);
输出结果如下:
zippo=0012FF50, zippo+1=0012FF5C
*zippo=0012FF50, *zippo+1=0012FF54
Press any key to continue
对于第一行的输出结果我有点不理解。我把zippo和zippo+1都理解成一个二级指针,那么它们分别指向一个一级指针,而一个指针本身所占的内存是4个字节,那zippo和zippo+1的地址之差不应该是一个指针所占有的内存值,也就是4吗?但是我从结果推回去相差的是12,也就是说相差了第一组数据2,4,1三个整形常量的内存值……哪位高人指点下迷津?
我要的不是答案……我想知道我那么想怎么错了。。。我的意思是,按照程序的运行结果,那不是把指针本身的地址和指针所指向的对象的地址等同起来了么?二级指针指向的应该是一级指针的地址呀,也就是4个字节……那二级指针加1为什么地址不是加了4呢?……
呵呵,厉害!也就是说应该把数组的首地址理解成一种特殊的地址类型吧,即zippo的长度是4*3*sizeof(int),*(zippo+1)的长度是3*sizeof(int),而zippo+1的长度才应该是一个普通地址长度,即4
这样定义的原因是两者本身的语义不同。引用一个表示数组的标识符(数组名)具有两重含义,一是指整个数组,二是指指向数组首个元素(而不是整个数组)的指针。具体取两种含义是上下文相关的。在定义数组、作为sizeof或一元&操作符的操作数这些左值语义上下文中,数组名表示第一种含义;其它情况下,取第二种含义。因此,C语言中在某些场合(例如参数传递)数组可以丢失长度信息,退化为对应的指针(这里的退化是指隐式地类型转换,保持数组元素和指针指向的对象的类型相同)。(如果不考虑类型,两种含义得到的值都是相等的,即数组首个元素的第一个字节在存储器地址空间中对应的整数值——地址(值),因此编译器一般以此实现数组,同时在目标代码中完全不保留数组的类型信息。)但反之无法实现。
作为以下内容的前提,LZ必须明确,被一个指针指向的是对象——即具有确定地址的一个的实体(作为一个表达式,可以是左值),而不是作为一种整数的“地址”(尽管指针的值等于被指向对象的地址)。要点在于,指针是有类型(而且和被指向的类型对应)的,类型会影响操作的具体行为。
C语言的核心语言特性没有直接支持多维数组,所谓的多维数组,只不过是元素为数组的数组。由于元素类型是数组类型的必要组成部分,因此指针类型元素的数组和一维数组类型元素的数组(通常所说的“二维数组”)是不同的(所以不是像LS说的——你“可以”,而是“必须”把二维数组看成数组的数组)。而二维数组更不是二级指针。二级指针指向的是一级指针,它的值是一级指针的地址——由于是两个不同的对象(左值),二级指针的地址和这个值自然不同(如果因为指向自身而导致值相同,则至少需要一次显式类型转换,因为一级和二级指针之间不会隐式地转换);而因为以上的数组语义的关系,二维数组可以退化成不同的指针,类型不同,但地址值相同。结合LZ的例子来讲,二维数组zippo可以退化为&zippo[0](zippo[0]是一个一维数组,&zippo[0]是指向它的指针),或者继续退化为&zippo[0][0](指向一维数组zippo[0]的首个元素zippo[0][0]的指针)这两个指针右值,而三者的值都是同一个地址。
然后是“+”的问题。这里又有一个陷阱:数组作为additivate operator(二元+和-)算术操作的操作数,它的类型会影响+和-的具体行为,满足“下标移动”的语义。从实现上来说,同指针+、-操作一样,对于一个整数,地址值的改变值是除了指针/数组外另一个整数操作数乘以sizeof(被指向的类型或元素类型)。例如,i是一个正整数,zippo是表示一个数组或者指针标识符,那么zippo + i按下标移动应该等价于&zippo[i],从实现上来看相当于(zippo的类型)((intptr_t)zippo + (intptr_t)(sizeof(*zippo) * i))(其中intptr_t是标准库定义的和在该平台下指针大小相同的整数类型)。LZ的问题中,如果zippo是二级指针,那么zippo和zippo+1的地址之差确实应该是一个(一级)指针所占存储器空间的大小(等于sizeof(intptr_t),32位平台也就是4)。但是这里zippo是二维数组,那么sizeof(*zippo)等于它的元素——一维数组的sizeof值,自然可以不是4。
====
[原创回答团]
参考资料:原创
参考技术A #include <stdio.h>int main()
int array[4][3];
int *p1 = array[0];/*一级指针*/
int (*p2)[3] = array;/*二级指针*/
printf("%d,%d\n", array,array+1);
printf("%d,%d\n", p1,p1+1);
printf("%d,%d\n", p2,p2+1);
return 0;
//int array[4][3];可以看做int (*p[4])[3];即一个数组,每个数组元素指向某一个三int元素数组 参考技术B 二维数组啊,当然就是输出这样的结果的啊
zippo是第一行的地址
zippo+1第二行的地址
*zippo第一个元素的地址
*zippo+1第一行第二个也是整个数组第二个元素的地址
绝对是正解 参考技术C zippo是二维指针
所以 zippo+1 则zippo后移一个元素的长度 即 一维数组的长度
int [3] = 4 * 3 = 12 参考技术D 1个n*m二维数组,你可以看成是n个长度为m的一维数组组成的。
假设数组a[100][100].
a[0]表示的是数组的第零行的首地址,也即是整个二维数组的首地址。
a[1]表示的是数组的第一行的首地址。
你那程序里的加1就已经是到数组的下一行了,肯定地址需要加上整一行打大小了。 第5个回答 2010-08-05 zippo的是zippo[0][0],zippo+1 的是zippo[1][0]
以上是关于C-指针数组与数组指针的主要内容,如果未能解决你的问题,请参考以下文章