问题:
比如,现在有一维数组定义如下:
int arr[5]={1,2,3,4,5};
我们都知道 数组名arr是代表数组首元素的地址即arr[0]的地址。
那在数组名前面加上取地址符&,即&arr,打印出的地址同样也是arr[0]的地址。
比如
printf("arr=%x\n&arr=%x\n&arr[0]=%x\n", arr, &arr, &arr[0]);
假设 现在有一个数组指针定义如下:
int (*p)[5]=NULL;
p=&arr;// 这样赋值就不会报错。
p=arr; // 但是这样赋值就会报错。&arr与arr的指向的地址相等的,那么为什么还会报错呢?
假设,现在再定义一个二维数组如下:
int arr2[4][5]={...};
p=arr2; // 而这样就不会报错。
p=&arr2; // 报错。
麻烦解释下 “数组名”与“&数组名”分别在一维、二维或更多维数组里的区别和作用? 最好能给出它们在内存,组织的原理或示意图。
谢谢大家。
回答:
作者:
比如,现在有一维数组定义如下:
int arr[5]={1,2,3,4,5};
我们都知道 数组名arr是代表数组首元素的地址即arr[0]的地址。 我很想知道,为什么成千上万的初学者,非得要纠结数组名,以及数组地址的问题。另:数组名代表数组首元素的地址,这个荒唐啊。
那在数组名前面加上取地址符&,即&arr,打印出的地址同样也是arr[0]的地址。
比如
printf("arr=%x\n&arr=%x\n&arr[0]=%x\n", arr, &arr, &arr[0]);
假设 现在有一个数组指针定义如下:
int (*p)[5]=NULL;
p=&arr;// 这样赋值就不会报错。
p=arr; // 但是这样赋值就会报错。&arr与arr的指向的地址相等的,那么为什么还会报错呢?
这正是我恶心数组名和数组地址之类措辞的原因。因为,只用类型即可解释一切与数组有关的问题。标准说,对于表达式&E,若E的类型是T,则表达式&E的结果是指向T的指针。因为arr是数组,故&arr的结果是指向数组的指针。
标准又说,除非做为运算符sizeof和一元&的操作数,数组类型的标识符将被转换为指向其首元素的指针。因此,p=arr中,arr会被转换为指向其首元素的指针。因为元素的类型是int,故表达式arr转换后的类型是int *,与运算符=的左操作数p的类型不兼容。
假设,现在再定义一个二维数组如下:
int arr2[4][5]={...};
p=arr2; // 而这样就不会报错。
p=&arr2; // 报错。
arr2是一个数组,其元素类型也是数组。从前面说的,arr2被转换为指向其首元素的指针,也就是指向数组的指针(元素类型也是数组嘛),即int (*) [5]与p的类型兼容。相应地,&arr2的结果是指向数组的指针int (*) [4][5],尽管也是指向数组的指针,但与p的类型不兼容。
麻烦解释下 “数组名”与“&数组名”分别在一维、二维或更多维数组里的区别和作用? 最好能给出它们在内存,组织的原理或示意图。
以C中,不存在二维数组和多维数组。所谓的二维数据,就是元素类型是数组的数组(这个过程可以递归进行)。如果用多维数组来理解和解释,反而更迷糊。
谢谢大家。
“
标准又说,除非做为运算符sizeof和一元&的操作数,数组类型的标识符将被转换为指向其首元素的指针。
”
其中,数组类型的标识符改为“数组类型的表达式”。考虑如下声明:
1
|
struct
t {
int
a [22];
float
f;} t [3];
|
则表达式
1
|
t [0].a
|
是数组类型的表达式。它会被转换为指向其首元素的指针:
1
|
int
* p = t [0].a;
|
摘录自:https://bbs.youkuaiyun.com/topics/391002768?page=1
回答特别简单易懂,一下子就让我 茅塞顿开。