1
ProjectAmber 2015-11-03 21:51:15 +08:00
虽然内容一样,但是类型不同啊。就和 int 和 float 二进制一样,表示的数可不一样。
|
2
zackkson1991 2015-11-03 21:52:47 +08:00
一楼说的正确。这时候已经类型是不一样了。也就是每次你访问的时候,抓取内存的方式不一样了。
|
3
colatin 2015-11-03 22:01:10 +08:00
f(x)=x^2
f(x)=x^3 即使 x 的值相同, f(x)的值也会不同。不知道这个类比是否恰当。 |
4
aholic 2015-11-03 22:11:36 +08:00
int i = 1;
int *p = (int*)(i); i 和 p 的“值”也是一样的。 但是作为 int 来解读,它就是 1 作为 int*来解读,他就是一个指向 0x1 的指针 |
5
feiyuanqiu 2015-11-03 22:14:18 +08:00
*array 得到的是 array[0][0] 的地址
*array[0] 得到的是 array[0][0] 的值 |
6
ru20150601 OP @ProjectAmber
@zackkson1991 @colatin 不是,三位,可能我表达的不清楚。,是这样的,这个例子当中呢, 他们输出的是指针的值。我看的英文版的也不知道中文术语是不是这样说的,我直接说代码吧: printf("array =%p array[0]= %p",array,array[0] ); 书中的例子,这两个输出出来是一样的。这完全讲不通啊 如果 array==array[0] 那么 *array == *array [0] array[0][0]=13 //而 *array [0] ==array [0][0] 那么 array==13 ? =====================================分割线============================ 我的意思是, array[0][0]是一个变量, array[0]是指向变量的指针, array 是指针的指针,这两个怎么可能相等? |
7
ru20150601 OP |
8
c742435 2015-11-03 22:21:43 +08:00
指针的值是其指向的内存地址,都是指向同一个内存地址,为啥不等?
谁跟你说 array 是指针的指针。 |
9
patrickstar 2015-11-03 22:28:45 +08:00
你还是找本靠谱的书看看,看看 C 指针这本书,好像是这个名字
array 是一个 int**,而 array[0]是一个 int* |
10
patrickstar 2015-11-03 22:36:36 +08:00
你看看 "Pointers on C" 这本书,中文名叫啥子忘了!
array 和 array[0]的指针值确实一样,都等于 &array[0][0],即第一个元素的地址,但是*array 和 *array[0]是两个概念了,*array 任然是一个指针,这时候任然=&array[0][0], 而*array[0]= array[0][0] |
11
patrickstar 2015-11-03 22:44:18 +08:00
运行一下子程序就明白了:
#include <stdio.h> #include <stdlib.h> int main(int argc,char* argv[]) { int a[4][2]; for(int *p = a[0],i = 0; i < 8; i++) *(p+i) = (i+1)*(i+1); printf("array = %p\n",a); // = &a[0][0] printf("array[0] = %p\n",a[0]); // = &a[0][0] printf("*array = %p\n",*a); //*a is a pointer=&a[0][0] printf("*array[0] = %d\n",*a[0]); //*a[0] is int return EXIT_SUCCESS; } |
12
harry890829 2015-11-03 22:45:54 +08:00
这是一个二维指针,所以 array[0]其实也是指针啊……
如果 char sz[8]写成 sz ,你知道是指 sz 数组的第一个元素的地址 那么 int array[4][2]写成, array[0]你也应该知道这是一个指针啊, array 和 array[0]这两个都是指向了这个二维数组的第一个元素的地址 |
13
ru20150601 OP @patrickstar
好吧,我刚刚也实际运行代码测试过了,确认不是教材错了我就放心了。正在看的是 c primer plus ,这个例子也是这本书里的,这本书写的很细,猛的出来一个这么反直觉的东西,竟然没有解释,一句话就带过了,把我害苦了。 |
14
htfy96 2015-11-03 22:53:11 +08:00 1
@patrickstar
@harry890829 @ru20150601 array[0]并不是一个指针,而就是一个叫做 int[2]的类型 printf("%lu", sizeof(a[0])); 之所以常常能把 a[0]看作一个指针用,是因为这里发生了隐性的 decay |
15
canautumn 2015-11-03 23:00:53 +08:00
C 语言就是这么规定的,记住就行了。可以看看『征服 C 指针』,记得里边讲 C 语言指针的设计只是尽量合理(尽量符合直觉),但有些和直觉矛盾之处是很难解决的,只好记住。
|
16
halfcoder 2015-11-03 23:06:20 +08:00
楼主从 C 数组的内存模型上来思考就容易理解了。 int array[4][2]作为一个总共拥有 8 个 int 元素的数组,不管是 array 也好还是 array[0]也罢,都是指向的第一个元素,其地址当然是一致的。至于类型不一样,那只是外部表示而已,即使 array 变成更高维的数组,其类型发生巨大变化,结论也是一致的。
|
17
Zhang 2015-11-03 23:19:03 +08:00
c 语言规定的,数组的名称就是第 0 个元素的地址!
|
18
CRVV 2015-11-03 23:23:35 +08:00 2
array 是一个 2 维数组, array[0] 是一个 1 维数组,类型都不一样,值怎么个一样法?
但是 C/C++里面的数组比较特殊,数组类型的变量会被编译器转成指向首元素的指针 (注一下,这个问题上,有些人认为数组名就是一个指针(而不是被转成指针),比如楼上的回帖,也包括楼主的教材) 所以下面是我认为的正确的理解方式(也就是 "C++ Primer" 的内容),要搞懂这个问题需要了解两件事: 1 、在你使用数组名这个变量时,它通常被转换成了首元素的指针,所以 array 被转成了 &array[0] 2 、数组只是一个连续的内存区域,用来存数组里的元素。数组的内存地址就是数组首元素的内存地址(但是,作为两个指针,它们的类型不同) 用 printf 输出来的是内存地址,所以 array -> &array[0] -> &array[0][0], array[0] -> &array[0][0] 三个箭头分别是,数组被转成首元素地址,数组的地址和数组首元素的地址相等,数组被转成首元素地址 结论是, 如果你用 printf 输出 array 和 array[0],输出的东西是相等的,但这两个变量的类型不同,不应该拿来比较 以下和回答无关 “教材中说, array 的值和 array[0]的值是一样的” “* array 得到的是一个内存地址值 long int ” 看到这两行内容,我觉得你这本教材应该扔掉了 |
19
ru20150601 OP @CRVV 谢谢长文答复。我看的是 c primer plus ,这两句话不是原文,是我根据自己的理解描述的。因为不知道有这个背景。
|
20
CRVV 2015-11-03 23:57:47 +08:00
|
21
inevermore 2015-11-04 00:00:45 +08:00
array 和 array[0]都可以看做指针,指向的内存起始位置相同,所以他们的值是相同的。
但是他们的类型不同。 |
22
Reficul 2015-11-04 00:10:30 +08:00 via Android
把一个二维数组看成一个矩阵, array 指向整个矩阵, array[0]指向矩阵的第一行。指针指向元素起始位置,那么 array 和 array[0]自然都是指向同一个位置,即元素 array[0][0]的内存地址。
但是仅仅是数值相同,他们的类型是不一样的。指针每+1 不是简单的地址+1 ,而是会自动匹配对应类型大小相加的,所以 array[a][b] == *(*(array+a)+b)。 30 天自制操作系统那本书的作者甚至认为数组的写法 A[i]是*(A+i)的一个语法糖。 |
23
ru20150601 OP 谢谢大家的回复,我明白怎么回事了。
应该是我理解有误,一开始,我是这样理解的: 1 : array 和 pointer 是同一回事,区别仅仅在于 array 是一个内存地址定值,而 pointer 是一个内存地址变量。类似于变量 char c 和定量 'c' 。 2 : 2 维 array 是一个 array 的 array 。也就是一个指针的指针 。(或者说是一个地址值的地址值)。所以 array 本身的值是一个地址,而在这个地址所存的是 array[0]的值。而 array[0]的值是一个地址,这个地址存储的是 array[0][0]的值。 3 :所以*array 和 *array[0]分别是一个是内存的地址而另一个是此处所存储的值,不可能相同。 我先把这个理解记录下来,希望将来再回来看一下,能看明白到底什么地方出了问题。 |
24
ru20150601 OP 额,上面第三点写错了,是 array 和 array[0]。
|
25
mimzy 2015-11-04 00:55:36 +08:00
@CRVV 楼主看的是 C Primer Plus 那个帖子说的是 C++ Primer Plus 在此指出一下 不能冤枉前者……
|
26
CRVV 2015-11-04 01:06:22 +08:00
|
27
xufang 2015-11-04 01:09:20 +08:00
看完回帖,实在憋不住说一句,一聊到 C 遇见, V2EX 上小学生就像韭菜一样涌现出来。
|
28
Valyrian 2015-11-04 04:25:14 +08:00
都别他妈扯淡了, int[][]和**int 不是一回事
楼主运行一下这个: int a[2][4]; printf("%p\n", a[0]); printf("%p\n", a); 还有这个 int a[2][4]; printf("%p\n", a[1]); printf("%p\n", &a[0][4]); //故意越界 这两个值打出来是一样的!!!!!!!!!!!!! 多维 array 在内存里一维的,比如 int a[2][4],在内存里就是长度为 8 的一整块,不存在中间那个保存每一行起点的数组!!!你用高维语法访问的时候会自动帮你算他在一维中的位置,比如 a[1][2],一维中的位置就是 1 * 4 + 2 = 6 ,访问时会自动帮你算! 如果你少访问一个或多个维度,比如 a[1],那么程序就帮你算成 1*4+0=4 ,(并且不 dereference ,返回地址)。越界也没有关系, a[0][4]会算成 0*4+0=4 ,(并且 dereference ,返回值)。这就是为什么上面 a[1]和&a[0][4]是相同的! 当然你的二维数组也可以用**int 来存,这样你访问的时候, a[1],会先访问一个中间数组,这个数组包含每一行开始的位置,元素的类型是*int ,然后 a[1][2]是去这一行找第二个元素 C 语言规定了指针可以用数组的语法来访问,导致很多人混淆 t[]和*t 。他们在一维的时候确实完完全全一样,高维就不一样了 |
29
yuchting 2015-11-04 09:09:45 +08:00
再学汇编吧,学汇编你就懂了。
其实汇编没有啥一维二维的, if else for 啥的那都是 C 语言抽象出来的,真的到了底层就只有 jump ( goto )啦, compare 啊什么的,全是指针,只不过偏移量不一样而已。 你从 C 语言去理解指针的本质,还是有些角度不对,就像你从细菌的角度去理解病毒、从中医角度理解细胞结构一样。 学汇编可能也有不明白的,比如你要是问为啥 CPU 会判断?为啥会懂 1+3=4 ?继续学吧,学计算机结构和数字电路外加 EDA 什么的,操作完可编程芯片的那个啥手动输入指令,手动拨 CPU 频率运算的实验。 你就基本上全明白了。 |
30
bengol 2015-11-04 09:27:11 +08:00 via Android
哪有什么二维指针
|
31
firstway 2015-11-04 10:39:24 +08:00
米尺见过吧,上面也有厘米刻度。
那么,第一厘米和第一米的起始点是一样的。 懂了吗? |
32
monkeymonkey 2015-11-04 12:34:49 +08:00
a[i]其实是 syntactic sugar, 语法糖, 等价于 *(a + i)。
在二维数组中 array 是[指针]的指针,这个[指针]可以是[数组指针],也可以是[指针数组]的头地址。 array[0] 是指针,等价于 *(array + 0) array[0][0] 是数值,等价于 *( *(array + 0) + 0) 1. 在用一维数组模拟的二维数组里( 即在栈上声明 array[3][4]这种,空间连续) array 的值是等于 array[0], 并等于 &array[0][0]的值,都是同一个地址,但是含义不同。 第一个指向一个二维数组,第二个指向一个一维数组,第三个指向一个元素的地址。 *array 等于 *(array +0) 等价于 array[0] ,其实是对一个指针指针进行取内容操作,得到一个指针,这个指针指向一个一维数组。 *array[0] 等于 *(*(array+0)) 等于*(*(array+0)+0) 等价于 array[0][0],对一个指针进行取内容操作,得到一个元素的内容。 2. 假如你在堆上申请一个指针数组表示的二维数组 不是一维模拟二维,空间可以不连续。而是申请很多一维的数组,再把这些数组的头地址放在一个指针数组里。 那么 array 的值,**一定**不等于 array[0],一个是指向[指针数组]的指针,一个是指向[数组]的指针。 但是 array[0]的值是等于 &array[0][0]的,但是依旧,它们的含义不同,后者是指向元素的地址。 3. 假如你用 int (*array) [m] = (int (*)[m])malloc(m * n * sizeof(int)) 这种,是第三种情况。 和情况 1 有点像,一维模拟二维,空间连续,但是是在堆上。情况 1 在栈上模拟。 此时 array 的值等于 array[0]等于 &array[0][0]的值,但是含义不同。 array 此时的类型是 [数组指针]数组的开始地址,有点绕。 是一个类型为 int [m] 的指针。 对比之下, array[0]则是一个 类型为 int 的指针。 array + 1 其实在一维空间里走了 m 步,每步 4 字节。 array[0] 指向一个数组,&array[0][0]指向元素的地址。 *array 等于 *(array + 0) 等价于 array[0] 会得到第一个数组的指针。 *(array + 1)等价于 array[1] 会得到第二个数组的指针。 一句话总结,地址相同,但含义不同,因此取内容得到的类型也不同。 |
33
monkeymonkey 2015-11-04 12:40:08 +08:00
C 语言里语法糖很多, 比如 for 就是 while 的语法糖, ptr->x 是 (*ptr).x 的语法糖, a[i]是 *(a + i)的语法糖。
|
34
monkeymonkey 2015-11-04 12:52:43 +08:00
http://biancheng.dnbcw.info/c/66493.html
楼主你什么时候把这篇文章搞懂了,就会 C 语言了。 但是一般正常人不会这么写 233 。 就跟正常人不会写 ++i++这种语句一样。 |
35
leechung 2015-11-05 22:59:25 +08:00
一个 2 维的指针, int array [4] [2],教材中说, array 的值和 array[0]的值是一样的,是同一个地址值。这个我不能理解。* array 得到的是一个内存地址值 long int ,而* array[0]则是一个 int 。怎么可能会相同呢?
------------------------------------------------------------------------------------------------------------- 首先, C 中不存在 2 维指针。维度是针对数组而言的; 其次,“值”这个术语在 C 标准文档中有明确的含义,粗略地说,值是对象的内容。值得注意的是, C 标准文档不使用“变量”一词,而是使用“对象”,但这个对象和面向对象设计语言中的对象不是一回事。 再次,基于以上概念的界定,那么,因为标识符 array 指示一个数组类型的对象,所以,“ array 的值”实际上指的是数组对象 array 的值,也就是整个数组的内容;“ array[0]的值”指的是数组 array 的元素,也就是子对象 array[0]的内容。显然,它们的值是不一样的。 |