数组名a,&a,&a[0]的关系
c语言吧
全部回复
仅看楼主
level 12
landmark_csl 楼主
学习数组的时候经常被这三个货弄晕,后来查了很多资料,觉的自己明白了,在这说一下自己的理解,求各位大神指正。
首先说一下,当我们定义了一个变量的时候,比如int x;x的类型是int,那么当我们定义数组的时候比如 int a[3];a的类型是什么,int?No,int是数组元素的类型,不是数组的类型,觉的是int[3],但C语言里没有这种类型,但我们可以用typedef int A[3]; A b;那么这个b和a完全一样都是包含三个整数的整型数组。所以说a的类型是A(int[3],数组类型),所以当我们用sizeof(a)来测试a的空间的时候得到12个字节,当我们&a的时候得到数组a(整体)地址,&a+1会移动到数组后面。这和普通变量一样。所以数组名和普通变量名在这点上类似。这是我对数组的理解,不知道对不对。接下来说下a和&a[0]的关系
2013年01月07日 05点01分 1
level 12
landmark_csl 楼主
接前文,我们知道数组是同类型元素的**,但数组不能整体存取,只能一个一个元素存取,所以凡是在(除&和sizieof)表达式里出现的数组名a都代表数组首元素地址,也就是&a[0],比如说*a就是a[0],因为[]下标运算符就代表*(a+0),所以a[0]也可以写成0[a](这纯粹是语法上,不建议写这种怪摸样的东东),在这里*a,也就是*(a+0),也即a[0];那么当我们定义了一个指针int *p; 可以p = a;因为在这个表达式里a就代表&a[0],&a[0]就是一个整型地址,自然可以赋值给p。p++会移动到4个字节,所以当p=a后p也可以做数组名用,比如说p[1]等价于*(p+1)。但p和数组名有根本上的不同,p是变量,可以更改,而且其只能指向一个整型变量,不代表整个数组,所以sizeof(p)是4,&p表示p的地址而不是整个数组的地址,&p+1往后移动4字节。而数组名a代表有两层语义:
1. a表示一个数组,sizeof(a)等于数组长度*4,&a代表整个数组的地址,&a+1移动到数组后面。
2.在存取数组元素的时候a表示数组首元素的地址,所以a[2]表示*(a+2)表示数组第三个元素
至于说数组名是常指针或是常量,我觉的都不靠谱,没有说明数组名的本质。其表现为常量是因为数组不能整体赋值,常指针就更不靠谱,因为数组名并没有本身的地址。
2013年01月07日 05点01分 2
level 12
landmark_csl 楼主
欢迎各位大神指正
2013年01月07日 05点01分 3
level 6
楼主,你好:
你的以上说法不够准确。
1.int a;int b[3];变量a占用4个字节的存储空间,而变量名a本身并不占用存储空间,数组名b也是如此,它也不占用存储空间,不确切的说,数组名b是对12个存储空间的统称(变量名、数组名在C语言编译时起作用,编译完成后就不存在了)。
2013年01月07日 06点01分 5
对呀,我没否认,你用变量名的时候就是引用那4个字节,数组名的话要分情况的
2013年01月07日 06点01分
回复 landmark_csl :还有变量a,a也是名字也不占用空间
2013年01月07日 06点01分
@landmark_csl 我认为a是个指针[乖] 而且他是有地址的也存在存储空间比如说printf("%d",a);打印的结果就是a中存储的内容
2015年03月07日 09点03分
level 6
2.直接对数组名进行引用(如:int *p = a)时,数组名的数据类型是int*类型,而非a[3]类型(注意:数组名本身并不占用存储空间)。
3.C语言非常强调数据的类型!!其实你所研究的问题的区别就是数据类型不同而已。
C语言认为,对数组名取地址和直接引用数组名不是一回事儿。他们区别如下:
对数组名取地址,数据类型:int (*)[3]
直接引用数组名,数据类型: int*
&a[0]的数据类型:int *
OK,解答完毕!
2013年01月07日 06点01分 6
那你又如何解释 int (*p)[3] = a; sizeof(p)等于4,但sizeof(a)的话等于12呢
2013年01月07日 06点01分
数组名的数据类型是int*,那就是说数组名和普通指针没什么区别了?,那为什么他不占用空间呢?给个理由,不能人云亦云啊
2013年01月07日 06点01分
我觉的你根本就没搞清楚数组a是个啥东西,a是个导出类型,整型的导出类型,数组名代表的既是变量又是类型,因为int a[3]本身就是一种数据类型,否则typedef int a[3];又如何解释呢?
2013年01月07日 06点01分
回复 landmark_csl :a指数组,整个数组的大小是12,而p是指针,p的大小是4。注意:int (*p)[3] = a和sizeof(a)这两个a不是一码事儿。前一个a是对数组的引用,它是一个地址,而后一个是sizeof操作数a,a指整个数组。[酷]
2013年01月07日 06点01分
level 12

觉的是int[3],但C语言里没有这种类型,
///////////////////////////////////////
明显 c语言里面有这个数据类型 你才可以用typedef 给数组类型起一个名字
2013年01月07日 06点01分 7
但你直接写int[3]是没有的
2013年01月07日 06点01分
回复 landmark_csl : printf("%d\n", sizeof(int[3]));
2013年01月07日 06点01分
回复 RichSelian :你用的是神马编译器呀,我也要一下
2013年01月07日 07点01分
回复 landmark_csl :clang
2013年01月07日 07点01分
level 6
sizeof是C语言的关键字,sizeof()不是函数,请不要用函数的思想来看待sizeof运算符噢!
sizeof(a),其中a指整个数组,求整个数组的大小,该运算结果在C源程序编译时由编译器求出,不是在程序运行时动态求解出来的,它的运算结果理所当然是12,请不要用神马a的类型来解释,再说一便,sizeof不是函数,它是C语言的一个操作符。
2013年01月07日 06点01分 8
数组名类型就是int[3],之所以能赋值给int*是因为存在隐式转换。
2013年01月07日 06点01分
回复 RichSelian :直接对数组名引用时,数组名的类型可认为就是int*嘛。。。
2013年01月07日 06点01分
回复 超级DA玩家 :按你的说法 int** b = &a; 就不可能出现类型不兼容。
2013年01月07日 06点01分
回复 RichSelian :[一楼喂熊]&a不属于直接对数组名的引用...
2013年01月07日 06点01分
level 6
记得好像:
C语言上有这么个历史:很久以前,直接使用变量名a是可以的,而对&a取地址是非法的。
后来,C语言专家们认为&a也应该是合法的,于是修改了C语言标准,认为&a合法。不过这样的话,就出问题了,a和&a含义一样还是不一样??专家们最终一拍即合,认为,直接引用a时,a的类型为指向数组成员的指针类型,对a取地址时,&a是指向整个数组的指针(也就是网上所谓的指向二维数组的指针)
2013年01月07日 06点01分 9
不能因为a是int *类型就说&a就是int**类型啊,a并不是变量,a是数组,它还是有它的特殊性的。
2013年01月07日 06点01分
&a是指向整个数组的指针(也就是网上所谓的指向二维数组的指针),是数组指针,但不是指向二维数组的指针
2013年01月07日 07点01分
level 13
@超级DA玩家
不拿编译的原话出来还让你蒙混过去了?
int a[3];int b = a;
warning: incompatible pointer to integer conversion initializing 'int' with an expression of type 'int [3]' [-Wint-conversion]
2013年01月07日 07点01分 10
你看我的结果,呵呵,编译器问题。
2013年01月07日 07点01分
level 6
tester.c: In function 'int main()':
tester.c:4:13: error: invalid conversion from 'int*' to 'int' [-fpermissive]
2013年01月07日 07点01分 11
做了隐式转换而已。
2013年01月07日 07点01分
如果a的类型是int[3],那么由于有隐式转换,出现报int*也是合里的;但如果a类型是int*,那就不可能报int[3],因为不存在指针到数组类型的隐式转换。
2013年01月07日 07点01分
还真是各执一词呀
2013年01月07日 07点01分
另然同一个变量在不同语境下类型不同这本身就是很荒谬的事。
2013年01月07日 07点01分
level 11
数组类型的表达式在除了作为&和sizeof的操作数或是一个字符串字面量初始化数组时都会转换成指向其首元素的指针.
2013年01月07日 07点01分 12
数组就是数组, 转换了而已.
2013年01月07日 07点01分
支持
2013年01月07日 07点01分
level 6
@
RichSelian
int a[10] = {1,2,3,4};
struct s = {1,2,3,4};
以上代码右边是一样的,那你如何用类型解释相同的代码初始化不同类型的变量呢?
原因只有一个,就是这个过程在编译时由编译器确定,编译器能很好的识别的。
2013年01月07日 07点01分 13
少些个变来那个b了,嘿嘿。
2013年01月07日 07点01分
{1, 2}又不是合法的表达式
2013年01月07日 07点01分
只是initializer的一部分而已
2013年01月07日 07点01分
数组和结构体都是导出类型,一个是同类型数据**,一个是不同类型数据**,都是**,{}是**初始化,当然可以
2013年01月07日 07点01分
level 8
在二维数组里他们表示同一个地址,对吧。?
2013年01月07日 08点01分 14
level 10
int a[3];
那么:a是int [3]类型的。
2013年01月07日 10点01分 16
是的
2013年01月07日 11点01分
@landmark_csl 呵呵,是 int* 类型吧
2015年03月07日 07点03分
level 12
landmark_csl 楼主
我是
lz
,a和&a的不同源于一个数组的两种语义,一般情况下,我们引用数组名是为了得到数组里的元素,这是侯数组名a被编译器用数组首元素地址替换或叫转换;在sizeof(a),a表示的是整个数组,所以是12,&a得到是整个数组的地址,这就像int b=10;int *p=&b;&b代表的变量的地址。int (*q)[3]=&a;所以q和&a是对等的,这是后&a代表的不是某个元素的地址。待会讨论一下二维数组和指针的关系
2013年01月07日 11点01分 17
level 12
landmark_csl 楼主
如果有定义 int c[3][3]; 那么c、c[0]、&c[0][0]关系又如何呢?各位有何高见?
2013年01月07日 12点01分 18
level 10
int a[5]; &a和a的类型是不一样的,前者是数组指针,其类型为int(*)[5],它是对象(数组)首地址,&a+1是下一对象的地址,即a[5]
2013年01月07日 15点01分 19
level 15
1.C语言有int[3]这种数组类型可以作为type name。出现并不违反语义规则的上下文如sizeof以及c0mpound literal。
2.https://tieba.baidu.com/p/2087082807?pid=27997722538&cid=0#27997722538
2013年01月07日 16点01分 20
你在那个标准里看到有int[3]这种类型?
2013年01月08日 01点01分
回复 landmark_csl :blog.csdn.net/supermegaboy/article/details/4855027
2013年01月08日 02点01分
回复 zczqwd :你给的这个网址,上不了,另外C99标准里并没有这种类型
2013年01月08日 03点01分
回复 landmark_csl :http://blog.csdn.net/supermegaboy/article/details/4855027。数组类型属于派生类型。
2013年01月08日 04点01分
level 12
landmark_csl 楼主
C语言里的二维数组,其实是数组的数组,也就是说二维数组其实是一个一维数组,不过这个一维数组的元素还是一个一维数组。例如可以这样定义二维数组:typedef int A[3]; A aa[3];
在这里aa[3]就是二维数组(和b[3][3]一样),所以二维数组的数组名和一维数组一样除sizeof和&外,其他表达式里都表示二维数组第一个元素(也即第一行,是个一位数组)的地址,第一个元素是一维数组,所以二维数组数组名是一个数组指针,指向整个数组(第一个元素),所以数组名aa+1,会移动到下一个元素,也即下一行。那么aa[0]和aa有什么区别呢?
2013年01月08日 01点01分 21
数组名在赋值给指针时相当于隐式转换,这是CPP里的原话,所以aa【0】和aa虽然打印出来是一样的,但是不是一个东西,aa【0】是aa的首元素,aa是指这整个数组的数组, 个人见解,有错请指出。。。[打酱油]
2013年01月08日 02点01分
类型不同
2013年01月08日 02点01分
回复 twtyypmb123 :我也是这么理解的
2013年01月08日 03点01分
回复 twtyypmb123 :不对。[]接受的操作数类型之一是指针而不是数组,这里还是有转换。
2013年01月08日 09点01分
level 12
landmark_csl 楼主
aa[0]和a有什么区别呢?aa[0]==*(aa+0). aa是数组指针,和int (*p)[3]相当,当我们给 p赋值时,需要这样 int a[3]; p= &a;如果我用数学上的等价替换的概念的话,就像:
p=aa; ==>aa[0]==>*(p+0)==>*(&a+0)==>*(&a)==>a;所以在这里aa[0]和一维数组的数组名一样。 printf("%u",sizeof(aa[0]));输出12,和一维数组的数组名一样。所以二维数组的下标运算可以解释为*(*(aa+i)+j)。
2013年01月08日 04点01分 22
1 2 尾页