user-0 提问: 问个数组指针的问题

回复:
user: user-1
content: 楼主没试过怎么知道结果一样？   我刚刚编了一下试了一下  结果明明不一样   请楼主先试一下在提问题  别只是从理论方面分析   毕竟编程中最重要的是实践

user: user-2
content: 楼主仔细看看23楼说的，再记住3楼说道的，就够了

user: user-3
content: 这里的问题不在数组和变量的意义 而在于，表达式解析的时候， 数组名和变量名的解析有所不同。 int a[M]; int *p; 数组名 在如下表达式中 解析为指针  *a,a++,a+1,a[i] 在如下表达式中解析为数组本身 &a,sizeof(a)  而对于指针变量 p 在如下表达式中 解析为指针 *p,p++,p+1,p[i]  在如下表达式中，依然解析为指针变量本身 &p,sizeof(p)  指针p,是个单一变量,p[0]和 p 的地址的值,通常是不同的. 数组a,是一个变量集合，&a[0],和a[0]的地址的值，总是相同的 . a 解析为指针的时候，值为&a[0],  指针变量 取地址&p,，取到的是变量p的地址 数组取地址&a,,取到的是数组a的地址 因为 a 和 a[0] 是整体和部分的关系 a[0] 又是 a的第一个元素 所以&a和 &a[0] 的位置是相同的，即地址的数值是相同 &a 和 &a[0] 不同的是，这个地址内部的数据是不同的  对于指针 p 也就是 &p[0]  是 指针p的值。 &p 是指针的地址，是存放 p的位置， 指针p 占有 sizeof(p) ，即一个指针大小的空间.  对于数组 a，在表达式通常就是&a[0]，  是 a[0] 的地址。 这个位置 需要只存放a[0]即可。  &a 是数组a 地址，是存放a 的所有元素的位置，  这里存放了a[0]~a[M-1]。  sizeof(a) =sum(sizeof(a[0])+....sizeof(a[M-1])) =sizeof(a[0])*M  char *p ="abcd"; 和  char a[]="abcd";  有所不同 前者 p  的值 是 数据存放的地址， 数据本身是无名数组（字符串字面值） 指针p 需要占用一个指针的空间。 这个无名数组，字符串另外分配存储空间， 通常是静态数据区,而且多半是常量区。  后者数据存放在 数组内部，需不需要， 无名数据，编译器根据需要决定 即便需要，也是不能确定具体位置的。 而数组占据全部数组元素，占用的空间。  假设32 Bits 系统，指针是32 Bits的 char *p ="abcd"; 和  char a[]="abcd"; 是函数内部的代码 a 是 char[5]; p 是 char * a 占用 5字节堆栈空间 p 占用4各字节的代码  无论字符串多长， 栈上p总是 4各字节 而数组a则总是需要和字符串长度一样的空间。

user: user-4
content: 同意，指针关键看指向类型，p即数组名指向数组第一个元素的地址，而&p指向的是整块数组的地址，两个地址值是相同的，sizeof(*p)＝1而sizeof(*(&p))＝4  就可以看出

user: user-5
content: 数组没问题， p和&p 对应同一地址， 只是类型不同，p 是char*， &p 是char (*)[4]

user: user-0
content: 对不起 大家  我原代码写错了  char *p = "123"; printf("%p,%p,%d\n",p,&p,*p);  纠正为 char p[] = "123"; printf("%p,%p,%d\n",p,&p,*p);

user: user-0
content: 是我前面弄错的  是这样的 不是*p 是P[]   看一下这位的答案    引用 12 楼 gy429476195 的回复:运行着看了下，用下面的例子可能更清楚： #include <stdio.h> #include <stdlib.h>  int main() { 	int a[20]; 	int *b = a; 	printf("sizeof(a)=%d\nsizeof(&a)=%d\nsizeof(b)=%d\n",sizeof(a),sizeof(&a),sizeof(b)); 	printf("%p,%p,%p\n",a,&a,b); 	char *p = "12345"; 	printf("%p,%p,%d\n",p,&p,*p); 	printf("sizeof(p)=%d\nsizeof(&p)=%d\nsizeof(*p)=%d\n",sizeof(p),sizeof(&p),sizeof(*p)); 	char c[] = "12345"; 	char *d = c; 	printf("%p,%p,%p,%d\n",c,&c,d,*d); 	printf("sizeof(c)=%d\nsizeof(&c)=%d\nsizeof(d)=%d\n",sizeof(c),sizeof(&c),sizeof(d)); 	return 0; } 运行结果如下：  再来张内存的结果：  可以看到变量的内存地址从A7C、A8C再到AA4，AA4开始的cc是数组a的地址，而sizeof的不同为我们说明了&和*的作用就是取首地址，这点对于字符数组一样的，我们看到的三个A7C就是这样，至于字符指针p和&p，首先一点，它们都是取地址，但地址内容不一致，p是008A5898，&p是001BFA8C，很明显p指向的是系统为字符串常量分配的地址，而&p为取该指针的地址，因此是系统在给变量分配地址时给了&p一个地址，这也就是&p和其他变量的地址在一块的原因。    	printf("%p,%p,%p,%d\n",c,&c,d,*d); 这里的C 和&C 的确是在同一个地址

user: user-0
content: 引用 9 楼 u013047378 的回复:  用的是fedora6系统 和 gcc编译器   查看了进程的maps 可以看到 p也就是"123"指向的是内存的代码区（只读常量区），而指针是变量 ，存放在栈区 我觉得不可能两者地址会一样 ，这是我个人的见解和程序。  你这个*p 和P[]  是完全不一样的的东西  *p = "123"   这里的123存放在代码区  P指向代码区 P[] = "123"是开辟了4个CHAR类型的空间是存放在栈空间的  空间的首地址就是P  这4个空间存放的“123\0”

user: user-6
content: 他们本质是不一样的  p是数组元素的首地址  p+1则是下一个元素的地址（不越界请客下）  若对数组名取地址  那么p就是数组的地址（数组的地址在数值上和数组首元素的地址一样） 但是他们的步长是不一样的 p+1则是指向（p+数组大）处

user: user-7
content: 引用 19 楼 zhao4zhong1 的回复:计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 多用小脑和手，少用大脑、眼睛和嘴，会更快地学会编程！ 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步Debug版对应汇编一行！ 单步Debug版对应汇编千行不如单步Release版对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  想要从本质上理解C指针，必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针，原本看似复杂的东西就会变得非常简单！ 指针即地址。“地址又是啥？”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认：  有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物；  而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。  不要企图依赖输出指针相关表达式...的值【比如printf("%p\n",...);或者cout<<...】来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=(void *)(...);】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 （Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。） 想要从本质上理解C指针，必须学习C和汇编的对应关系。” 不是一回事！  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  十字链表交换任意两个节点C源代码（C指针应用终极挑战）http://download.csdn.net/detail/zhao4zhong1/5532495     汇编哪家强，当然 AT&T

user: user-8
content: 计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 多用小脑和手，少用大脑、眼睛和嘴，会更快地学会编程！ 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步Debug版对应汇编一行！ 单步Debug版对应汇编千行不如单步Release版对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  想要从本质上理解C指针，必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针，原本看似复杂的东西就会变得非常简单！ 指针即地址。“地址又是啥？”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认：  有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物；  而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。  不要企图依赖输出指针相关表达式...的值【比如printf("%p\n",...);或者cout<<...】来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=(void *)(...);】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 （Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。） 想要从本质上理解C指针，必须学习C和汇编的对应关系。” 不是一回事！  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  十字链表交换任意两个节点C源代码（C指针应用终极挑战）http://download.csdn.net/detail/zhao4zhong1/5532495

user: user-9
content: 本来是挺简单的问题，文字就可解释，何必弄一堆代码…… N1570，6.3.2.1  Lvalues, arrays, and function designators (3) Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.   这就是说，一个数组类型的表达式，除非做为sizeof、_Alignof及一元&运算符的操作数，或者该表达式是一个用于初始化数据的串字面值，那么，它将被转化为指向其第一个元素的指针。 因此，对于 printf ("%p,%p,%d\n", p, & p, * p); 第一个p被转化为指向它第一个元素的指针；第二个p不转化，&p的结果是指向数组p的指针；第三个p转化为指向数组p第一个元素的指针，*p的结果是第一个元素的值。 指向数组p的指针和指向数组p首元素的指针，具有相同的值。

user: user-10
content: 运行着看了下，用下面的例子可能更清楚： #include <stdio.h> #include <stdlib.h>  int main() { 	int a[20]; 	int *b = a; 	printf("sizeof(a)=%d\nsizeof(&a)=%d\nsizeof(b)=%d\n",sizeof(a),sizeof(&a),sizeof(b)); 	printf("%p,%p,%p\n",a,&a,b); 	char *p = "12345"; 	printf("%p,%p,%d\n",p,&p,*p); 	printf("sizeof(p)=%d\nsizeof(&p)=%d\nsizeof(*p)=%d\n",sizeof(p),sizeof(&p),sizeof(*p)); 	char c[] = "12345"; 	char *d = c; 	printf("%p,%p,%p,%d\n",c,&c,d,*d); 	printf("sizeof(c)=%d\nsizeof(&c)=%d\nsizeof(d)=%d\n",sizeof(c),sizeof(&c),sizeof(d)); 	return 0; } 运行结果如下：  再来张内存的结果：  可以看到变量的内存地址从A7C、A8C再到AA4，AA4开始的cc是数组a的地址，而sizeof的不同为我们说明了&和*的作用就是取首地址，这点对于字符数组一样的，我们看到的三个A7C就是这样，至于字符指针p和&p，首先一点，它们都是取地址，但地址内容不一致，p是008A5898，&p是001BFA8C，很明显p指向的是系统为字符串常量分配的地址，而&p为取该指针的地址，因此是系统在给变量分配地址时给了&p一个地址，这也就是&p和其他变量的地址在一块的原因。

user: user-11
content: 一个是指向地址，一个是本身地址，怎么可能一样呢 我也试着编译了一次，确实不一样的

user: user-12
content: p和&p的值不可能一样。

user: user-4
content: 用的是fedora6系统 和 gcc编译器   查看了进程的maps 可以看到 p也就是"123"指向的是内存的代码区（只读常量区），而指针是变量 ，存放在栈区 我觉得不可能两者地址会一样 ，这是我个人的见解和程序。

user: user-13
content: 引用 7 楼 xuminghui382 的回复:你们试过么  我用的GCC  和QT  都是一样的结果   P和&P的结果相同  不可能是一样的，但你这么一说，我真去试了下，不一样 p打印的是存放"123"的地址 &p打印的是p本身的地址，怎么会一样

user: user-0
content: 你们试过么  我用的GCC  和QT  都是一样的结果   P和&P的结果相同

user: user-13
content: 不可能会出现这样的问题，你用的是什么编译器

user: user-14
content: 引用 4 楼 plainsong 的回复:char *p = "123" 改为 char p[] = "123"; 输出才会一样，也不也仅限于数值上的相同，它们的类型是不一样的。    [quote=引用 3 楼 sinservice 的回复:] 对数组名、函数名取地址，等价于不取。  这是c的语法，是一项规定。  不要再用“数组名”、“函数名”，只有明知是错误观点还要坚持的人才创造出“xx不是yy，但xx名是yy"这种说法。数组名就是数组，函数名就是函数，名字只是用来完成人与编译器的交流的，并无其它特殊含义。  数组取地址与不取地址绝对不等价：  #include <stdio.h> #include <stdlib.h>  int main() {     int a[20];     printf("sizeof(a)=%d\nsizeof(&a)=%d",sizeof(a),sizeof(&a));     return 0; }    [/quote]     在这里sizeof不等价，在那里等价。  自己非要钻牛角尖，研究没用的规定，就去吧。