对一个数组名取地址&

对一个数组名取地址&

int a[2] = {1,2,3}; 

int main()

{  

    printf("a = %p\n", a);   

    printf("&a = %p\n", &a);  

}



本机(linux)结果输出:
a = 0x5555555
&a =0x5555555



知识点:   通常情况下,数组名是指向数组第一个元素的指针。但是有两种例外情况:

1:sizeof()  -----------------------------      返回的是这个数组所占的字节数

2:&数组名 -------------------------------  返回的是指向这个数组的指针

相比于 数组名, 数组名是指向第一个元素的指针,而&数组名是指向整个数组的指针,当然可以用元素的类型来进行强制类型转换


<think>我们正在讨论数组名取地址的问题。根据引用[2]和引用[3],数组名在大多数情况下会被视为指向数组首元素的指针常量,但在两种情况下例外:作为`sizeof`的操作数和作为取地址运算符`&`的操作数。当对数组名使用`&`时,得到的是一个指向整个数组的指针,而不是指向首元素的指针。 引用[3]指出:数组名取地址&数组名)返回的是指向数组的指针,其类型是指向整个数组的指针,而不仅仅是首元素的指针。虽然数值上(即地址值)和数组名相同,但是指针的类型不同,这会导致指针运算时的步长不同。 例如,对于一个一维数组: int arr[5]; - `arr` 的类型是 `int*`,指向首元素,所以 `arr+1` 会前进一个`int`的大小(4字节)。 - `&arr` 的类型是 `int(*)[5]`,即指向整个数组的指针,所以 `&arr+1` 会前进整个数组的大小(5*4=20字节)。 同样,对于二维数组: int a[2][3]; - `a` 的类型是 `int(*)[3]`(指向一维数组的指针),所以 `a+1` 会前进一行(3个int,12字节)。 - `&a` 的类型是 `int(*)[2][3]`(指向整个二维数组的指针),所以 `&a+1` 会前进整个数组的大小(2*3*4=24字节)。 引用[4]中的示例代码也验证了这一点。 因此,数组名取地址得到的是一个指向整个数组的指针,这个指针的类型是“指向数组的指针”,而不是指向数组首元素的指针。虽然它们的起始地址相同,但指针类型不同导致指针算术运算的步长不同。 总结: - 数组名取地址&数组名)得到的是指向整个数组的指针。 - 该指针的类型为:数组元素类型 (*)[数组大小](对于一维数组)或 数组元素类型 (*)[第一维大小][第二维大小]...(对于多维数组)。 - 该指针的值(即地址)和数组首元素的地址相同,但指针运算时会以整个数组的大小为步长。 注意:在C语言中,虽然对数组名取地址是合法的(尽管引用[2]提到早期标准可能是未定义的,但现在主流编译器都支持),但要注意其类型和运算规则。 下面我们通过一个例子来具体说明: 示例代码: ```c #include <stdio.h> int main() { int arr[5] = {1, 2, 3, 4, 5}; printf("arr = %p\n", (void*)arr); printf("&arr = %p\n", (void*)&arr); printf("arr+1 = %p\n", (void*)(arr+1)); printf("&arr+1 = %p\n", (void*)(&arr+1)); return 0; } ``` 输出可能如下(地址值会因运行环境不同而异,但差值固定): arr = 0x7ffd12345670 &arr = 0x7ffd12345670 arr+1 = 0x7ffd12345674 // 增加了4(一个int的大小) &arr+1 = 0x7ffd12345684 // 增加了20(5个int的大小,即整个数组的大小) 从输出可以看出,虽然`arr`和`&arr`的地址值相同,但`arr+1`和`&arr+1`的地址值不同,因为它们的指针类型不同,所以加1操作跳过的字节数不同。 因此,数组名取地址得到的是一个指向整个数组的指针,这个指针在数值上等于数组首元素的地址,但类型是指向整个数组的指针。</think>### 数组名取地址详解 #### 一、核心概念 1. **数组名的本质** - 数组名是**符号地址常量**,在编译时确定并存储在编译器符号表中 - 代表数组首元素的地址,类型为:`元素类型*` - 示例:`int arr[5]` 中 `arr` 的类型是 `int*`[^1][^3] 2. **取地址操作的特殊性** - `&arr` 是**指向整个数组的指针**,类型为:`元素类型(*)[数组长度]` - 虽然 `arr` 和 `&arr` 的**数值相同**(都指向数组起始地址),但**指针类型不同**,导致指针运算行为不同[^2][^3] #### 二、关键区别(以一维数组为例) ```c int arr[5] = {1,2,3,4,5}; ``` | 表达式 | 类型 | 指针运算步长 | 内存表示 | |--------|------|--------------|----------| | `arr` | `int*` | 4字节(一个int) | `[1][2][3][4][5]` | | `&arr` | `int(*)[5]` | 20字节(整个数组) | `[整个数组对象]` | #### 三、指针运算对比 ```c printf("arr = %p\n", arr); // 0x1000 printf("arr+1 = %p\n", arr+1); // 0x1004 (+4字节) printf("&arr = %p\n", &arr); // 0x1000 (同arr) printf("&arr+1 = %p\n", &arr+1); // 0x1014 (+20字节) ``` #### 四、内存模型图解 ```plaintext 内存地址: 0x1000 0x1004 0x1008 0x100C 0x1010 0x1014 ┌──────┬──────┬──────┬──────┬──────┬──────┐ arr指向 →│ arr[0]│ arr[1]│ arr[2]│ arr[3]│ arr[4]│ 下一块 │ └──────┴──────┴──────┴──────┴──────┴──────┘ ↑ ↑ ↑ &arr[0] arr+2 &arr+1 (int*) (int*) (int(*)[5]) ``` #### 五、技术本质 1. **类型系统差异** - `arr`:指向数组元素的指针(颗粒度=元素大小) - `&arr`:指向数组对象的指针(颗粒度=整个数组大小)[^3][^4] 2. **编译器实现** - 数组名不占用独立存储空间,而是编译时的符号常量 - 取地址操作是编译器提供的语法糖,实际生成指向数组元数据的指针[^2] #### 六、二维数组示例 ```c int matrix[2][3] = {{1,2,3},{4,5,6}}; printf("matrix = %p\n", matrix); // 指向第一行 printf("matrix+1 = %p\n", matrix+1); // +12字节(3*int) printf("&matrix = %p\n", &matrix); // 指向整个数组 printf("&matrix+1 = %p\n", &matrix+1); // +24字节(2*3*int) ``` #### 七、使用场景 1. **函数参数传递** ```c void process_array(int (*arr_ptr)[5]) { // 接收整个数组指针 for(int i=0; i<5; i++) printf("%d ", (*arr_ptr)[i]); } process_array(&arr); // 传递整个数组的指针 ``` 2. **类型安全检测** ```c int(*p1)[5] = &arr; // 正确 int(*p2)[3] = &arr; // 编译错误!类型不匹配 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值