user-0 提问: C语言指针和二位数组的问题

回复:
user: user-1
content: 5楼已经说明白了。我简单说一下重点，zipper+1是zipper这个数组第二的元素的地址，即zipper[1]的地址。 然后你用*（zipper+1），那么它的值就是zipper[1]。其实zipper[1]就是一个一维数组，它有两个int。 那么你想一下，数组名即代表它的地址。你可以这样看zipper[1]是数组名，那么即代表它的地址zipper[1]的地址。 在这里给你一个通用的公式 *（zipper+a）=  zipper[a] *（*（zipper+a）+b）= zipper[a][b]

user: user-2
content: int a[10]  a 和 &a[0]地址一样   问题性质就是这样

user: user-3
content: 顶5L，问题的关键点在于“类型”。

user: user-4
content: 电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……

user: user-0
content: 引用 5 楼 sholber 的回复:看到前几楼的发言我就觉得……。C的类型系统是摆设么？不用类型系统，有些东西仅凭地址就解释得清楚么？动辄地址地址的，说明你根本就没理解指针和数组。  首先明确一点：如果一个数组类型的表达式不是sizeof和一元&的操作数，且不是用于初始化一个数组，则它会被转换为指向数组首元素的指针。接下来：  1，zippo是一个具有4个元素的数组，元素的类型是int [2]；  2，在表达式zippo+1中，zippo隐式转换为指向其首元素的指针，元素的类型是int [2]，所以是转换为指向int [2]的指针int (*) [2]（实际上指向的位置是原数组的元素zippo [0]或者zippo [0][0]）。加1后，指针的类型不变，还是int (*) [2]，但指向的位置变了（下一个int [2]，实际上指向的位置是原数组的元素zippo [1]或者zippo [1][0]）；  3，在表达式*(zippo+1)中，zippo隐式转换为指向其首元素的指针，元素的类型是int [2]，所以是转换为指向int [2]的指针int (*) [2]（实际上指向的位置是原数组的元素zippo [0]或者zippo [0][0]）。加1后，指针的类型不变，还是int (*) [2]，但指向的位置变了（下一个int [2]，实际上指向的位置是原数组的元素zippo [1]或者zippo [1][0]）。解引用后，我们从指针int (*) [2]得到数组int [2]本身（实际上这个数组对应着原数组的元素zippo [1]或者zippo [1][0]），接着又被转换为指向其首元素的指针int *（尽管指针的类型变了，但实际上指向的位置是原数组的元素zippo [1]或者zippo [1][0]）。  这道题虽然简单，但很有价值。 大神，十分感谢，终于弄明白了，您是我见过的回答的最好的，最有说服力的。

user: user-5
content: 引用 7 楼 sholber 的回复:[quote=引用 6 楼 fly_dragon_fly 的回复:] 语法问题 ,  zippo 和*zippo就是一样的,不信你不加1试试看,  大神，既然你说从语法上来说两者一样，那么请你从语法上来说说，zippo和类型和*zippo的类型各是什么。类型一样就样，类型不同就不一样。你说说。[/quote] %d就决定后面不管什么都是当做int, zippo 的类型是int(*)[2], *zippo 类型是int *, &zippo类型是int (*)[4][2], 它们地址还是一样, 除了认为是语法问题,那么只能说c的BUG了

user: user-4
content: 仅供参考：//char (*(*x[3])())[5];//x是什么类型的变量? // //分析C语言声明，关键是搞清楚这个变量是个什么东西（函数、指针、数组）， //是函数那么剩下的就是他的参数和返回值， //是指针那剩下部分是说明他指向什么， //是数组剩下的部分就是说明数组的成员是什么类型。 //解析C语言声明规则： //从左侧第一个标识符开始，按照优先级进行结合。*表示是..的指针，const表示只读的，volatile表示可变的，[]表示是数组，()表示是函数。 // //x和[3]结合说明是一个大小为3的数组，该数组的每个元素为一类指针，该类指针指向一类函数，该类函数无参数，返回一类指针，该类指针指向一个大小为5的char型数组 #include <stdio.h> #include <typeinfo.h> char num[5]; char (*x00())[5] {     return # } int main() {     char (*(*x[3])())[5];//是个数组，大小为3     char (*(*x0  )())[5];//数组的元素，是个函数指针     char (*( x00 )())[5];//函数原型，参数为空，返回值为指针     char (*  x000   )[5];//返回值      x0 = x00;     x[0] = x0;     x[1] = x0;     x[2] = x0;     printf("typeid(x).name() is %s\n",typeid(x).name());     return 0; } //typeid(x).name() is char (* (__cdecl**)(void))[5]

user: user-6
content: 引用 6 楼 fly_dragon_fly 的回复:语法问题 ,  zippo 和*zippo就是一样的,不信你不加1试试看,  大神，既然你说从语法上来说两者一样，那么请你从语法上来说说，zippo和类型和*zippo的类型各是什么。类型一样就样，类型不同就不一样。你说说。

user: user-5
content: 语法问题 ,  zippo 和*zippo就是一样的,不信你不加1试试看,

user: user-6
content: 看到前几楼的发言我就觉得……。C的类型系统是摆设么？不用类型系统，有些东西仅凭地址就解释得清楚么？动辄地址地址的，说明你根本就没理解指针和数组。  首先明确一点：如果一个数组类型的表达式不是sizeof和一元&的操作数，且不是用于初始化一个数组，则它会被转换为指向数组首元素的指针。接下来：  1，zippo是一个具有4个元素的数组，元素的类型是int [2]；  2，在表达式zippo+1中，zippo隐式转换为指向其首元素的指针，元素的类型是int [2]，所以是转换为指向int [2]的指针int (*) [2]（实际上指向的位置是原数组的元素zippo [0]或者zippo [0][0]）。加1后，指针的类型不变，还是int (*) [2]，但指向的位置变了（下一个int [2]，实际上指向的位置是原数组的元素zippo [1]或者zippo [1][0]）；  3，在表达式*(zippo+1)中，zippo隐式转换为指向其首元素的指针，元素的类型是int [2]，所以是转换为指向int [2]的指针int (*) [2]（实际上指向的位置是原数组的元素zippo [0]或者zippo [0][0]）。加1后，指针的类型不变，还是int (*) [2]，但指向的位置变了（下一个int [2]，实际上指向的位置是原数组的元素zippo [1]或者zippo [1][0]）。解引用后，我们从指针int (*) [2]得到数组int [2]本身（实际上这个数组对应着原数组的元素zippo [1]或者zippo [1][0]），接着又被转换为指向其首元素的指针int *（尽管指针的类型变了，但实际上指向的位置是原数组的元素zippo [1]或者zippo [1][0]）。  这道题虽然简单，但很有价值。

user: user-7
content: 引用 10 楼 ant2012 的回复:二维数组的物理存储结果实际上是一维的，zippo和*zippo是同一个值，在编译链接后他们会生成相同的二进制代码，可以查看其汇编代码就可以发现，他们底层是等价的 值一样，类型不一样。 所谓指针，就是带有类型的地址。

user: user-7
content: 5楼的分析，很精确

user: user-8
content: 二维数组的物理存储结果实际上是一维的，zippo和*zippo是同一个值，在编译链接后他们会生成相同的二进制代码，可以查看其汇编代码就可以发现，他们底层是等价的

user: user-9
content: 个人理解，仅供楼主参考： 在vs或vc上二维数组是按行存储的（在matlab上二维数组是按列存储的，两者不同） zippo是一个指向指针的指针（二维指针），所以zippo表示一个地址，*zippo也表示一个地址。   #include <stdio.h> int main(void) { 	int zippo[4][2] = { 		                1, 2, 					    3, 4, 					    5, 6, 					    7, 8, 					  }; 	printf("%d\n",zippo); 	printf("%d\n",*zippo);     //第1个数的存储地址  	printf("%d\n",*zippo+1); //第2个数的存储地址  	printf("%d\n",zippo+1); 	printf("%d\n",*(zippo+1)); //第3个数的存储地址  	printf("%d\n",*(zippo+1)+1); //第4个数的存储地址  	printf("%d\n",zippo+2); 	printf("%d\n",*(zippo+2));   //第5个数的存储地址  	printf("%d\n",*(zippo+2)+1); //第6个数的存储地址  	printf("%d\n",zippo+3); 	printf("%d\n",*(zippo+3));   //第7个数的存储地址  	printf("%d\n",*(zippo+3)+1); //第8个数的存储地址  	printf("%d\n",**zippo);         //输出1 	printf("%d\n",*(*zippo+1));	    //输出2 	printf("%d\n",**(zippo+1));	    //输出3 	printf("%d\n",*(*(zippo+1)+1)); //输出4 	printf("%d\n",**(zippo+2));     //输出5 	printf("%d\n",*(*(zippo+2)+1)); //输出6 	printf("%d\n",**(zippo+3));     //输出7 	printf("%d\n",*(*(zippo+3)+1)); //输出8 }

user: user-10
content: zippo+1 是  zippo[1] 的地址 *(zippo+1) 是  zippo[1][0] 的地址 从起始位置上来说，二者是一样的

user: user-11
content: zippo ＝ zippo[0] 我个人理解死zippo[0]并不代表一个真正的物理空间，他们指向的是相同空间

user: user-12
content: *（zippo+1）是首地址的值，（zippo+1）不也一样么