本篇文章我们再来一起讨论指针和数组的使用,很多同学在一块都有比较大的欠缺,所以这里专门用一篇文章来进行讲解。
在 C 语言中,数组的首元素的地址和数组本身的地址是有区别的。
数组是由一系列连续的元素组成的,可以将其视为相同数据类型的元素在内存中的连续存储空间。数组名代表了整个数组的首地址。
在C语言中,arr、&arr、&arr[0]都涉及数组的地址和指针的概念。
arr:arr是数组的名称,它代表整个数组的首地址。在大多数情况下,将数组名arr视为指向数组第一个元素的指针。由于数组元素在内存中是连续存储的,因此arr可以被隐式转换为指向首元素的指针。
&arr:&arr是取整个数组的地址的表达式。它返回的是数组的指针,指针类型为指向该数组的指针。这意味着&arr表示整个数组在内存中的位置。
&arr[0]:&arr[0]是取数组第一个元素的地址的表达式。也就是说,它返回的是数组中第一个元素的指针。与arr相同,&arr[0]也可以被视为指向首元素的指针。
下面是一个示例代码,展示了arr、&arr和&arr[0]的使用:
#include
int main(void) {
int arr[5] = {1, 2, 3, 4, 5};
printf("arr: %p\n", arr);
printf("&arr: %p\n", &arr);
printf("&arr[0]: %p\n", &arr[0]);
return 0;
}
输出结果示例:
arr: 0x7ffeed06b3b0
&arr: 0x7ffeed06b3b0
&arr[0]: 0x7ffeed06b3b0
在示例代码中,我们声明了一个包含5个整数的数组arr,并使用printf函数分别打印了arr、&arr和&arr[0]的地址。
注意到,arr、&arr和&arr[0]都打印出了相同的地址,即数组的首地址。这是因为数组在内存中是连续存储的,所以它们都代表了同一个地址,即数组的首地址。
数组名和指针常量不是完全相同的东西,尽管它们在某些情况下可以具有相似的行为。
数组名:数组名不是指针常量。在大多数情况下,将数组名视为指向数组第一个元素的指针。这意味着数组名可以被隐式转换为指向首元素的指针。然而,数组名是一个常量表达式,它代表整个数组的首地址,并且不允许进行赋值操作。
指针常量:指针常量是一个具有固定值的指针,不能为其赋予新的地址值。指针常量在声明时被初始化,并且在其生命周期内不能更改。指针常量使用const关键字进行声明,表明指针指向的内存地址是常量,不可修改。
虽然数组名和指针常量在某些情况下可以互相替代使用,但它们是不同的概念。数组名代表整个数组的首地址,可以用作指针,但不具备指针常量的不可修改性质。指针常量是一个不可更改的指针,它指向一个固定的内存地址。
需要注意的是,虽然数组名和指针常量不同,但在很多上下文中,它们可以交替使用,例如作为函数参数、数组下标访问等。这是由于C语言在许多情况下会自动将数组名转换为指针,以便使用数组的元素。
在这种情况下,arr + 1 的意义是将指针 arr 增加一个数组元素的大小,然后得到指向数组第二个元素的指针。结果是一个指向数组第二个元素的指针。
具体来说,假设 arr 是一个 int 类型的数组,每个 int 类型占用 4 个字节。那么,arr + 1 会使指针的值增加 4 个字节的偏移量,指向数组的下一个元素。
以下是一个示例代码,展示了 arr 和 arr + 1 的结果:
#include
int main(void) {
int arr[5] = {1, 2, 3, 4, 5};
printf("arr: %p\n", arr);
printf("arr + 1: %p\n", arr + 1);
return 0;
}
arr: 0x7ffeed06b3b0
arr + 1: 0x7ffeed06b3b4
易错点:
这里说了数组名可以当作指针常量,那么我们就不能对数组名进行自加操作。
这是一个错误的例子:
#include
int main()
{
int arr[5] = { 1, 2, 3, 4, 5 };
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d\n", *arr++);
}
return 0;
}
本篇文章就介绍到这里,下一篇文章我们继续讲解指针和数组的知识。