数组中的元素和元素地址是两个不同的概念:
- 数组元素:数组中每个数据的值,如整数、字符等。
- 数组元素地址:每个元素在内存中的存储地址。
例如,有一个5个元素的整数数组a:
a = {1, 2, 3, 4, 5}
那么:
- 数组元素是:1, 2, 3, 4, 5
- 数组元素地址根据元素在数组中的位置不同而不同,通常以a[0]、a[1]...a[n-1]表示,这里是:
a[0]: 元素1的地址
a[1]: 元素2的地址
a[2]: 元素3的地址
a[3]: 元素4的地址
a[4]: 元素5的地址
数组名a本身也代表这个数组的起始地址,即a[0]的地址。
在C++中,我们可以通过两种方式访问数组元素和元素地址:
1. 通过下标访问元素:
cpp
a[0] = 1; // 访问第一个元素,值为1
a[3] = 4; // 访问第四个元素,值为4
2. 通过指针访问元素地址:
cpp
int *p = a; // p指向数组a的起始地址
*p = 1; // 通过解引用指针访问第一个元素,值为1
*(p + 3) = 4; // 通过指针加上偏移量访问第四个元素,值为4
上面两种访问方式看似不同,但本质上都是通过数组的元素地址来读取和修改元素值。
数组元素和元素地址的关系是:
- 数组名代表数组起始地址,每个元素地址都可以计算出来
- 我们通过元素地址访问对应的元素
- 元素地址由数组名和元素下标共同决定
a[0]可以代表数组a的第一个元素,也可以代表这个元素的地址,这取决于它 being used在什么上下文中。
当a[0]出现在赋值语句的左侧时,它代表第一个元素:
a[0] = 5; // 表示给数组a的第一个元素赋值5
当a[0]出现在取值语句中时,它可以代表第一个元素的值:
x = a[0]; // x得到数组a的第一个元素的值
- 如果该函数的参数类型是元素类型(如int),那么a[i]表示元素值
func(a[0])相当于func(元素值),它传递的实际上是数组a的第一个元素的值。
- 如果该函数的参数类型是指针类型(如int*),那么a[i]表示元素地址
当函数期望指针参数时,func(a[0])和func(&a[0])形式上可以传递同样的实参。但func(a[0])会多进行一次自动转换,这可能影响效率或产生意外结果。为了健壮性和效率,通常推荐func(&a[0])的直接传址方式。
1.
func(a[0])中,a[0]首先表示数组第一个元素的值。在函数调用时,由于函数期望的参数是指针,所以a[0]会被自动转换为指针,最终传递给函数的是数组第一个元素的地址。
2. func(&a[0])直接就传递第一个元素的地址,没有自动转换的过程。
所以,从形式上来说,这两个调用会传递同样的实参(第一个元素地址)给函数。
数组名arr:
1. 表示整个数组,它的值是第一个元素的地址
2. 可以理解为数组占用的内存块的起始和结束地址
3. 我们可以通过sizeof(arr)得到整个数组占用的内存大小
4. 可以将整个数组作为函数参数传递,实际传递的是起始地址和占用大小
&arr[0]:
1. 表示数组首元素的地址,它的值是第一个元素的实际内存地址
2. 只能访问第一个元素,若要访问整个数组只能通过其他方法(指针运算、数组下标等)
3. 无法直接得到整个数组的大小,需要结合数组长度使用
4. 只能将第一个元素的地址作为函数参数传递
所以,这两者的主要区别是:
arr代表整个数组,&arr[0]仅代表第一个元素。
arr可以直接得到数组大小和将整个数组传参,&arr[0]不能。
* 简单的说,就是数组名出现在赋值符号“=”左边的就是左值,出现的右边的就是右值。
a作为右值时代表的意义和 &a[0]的意义是一样的, 代表 数组首元素的首地址 ,而不是数组的地址。注意:这里只是“当作”,并没有一个地方来存储这个地址。
* a不能作为左值
!!!编译器会认为数组名作为左值代表的是a的首元素的首地址,但是这个地址开始的一块内存是一个整体,我们只能访问数组的某个元素,而无法把数组数组当做一个整体来进行访问。所以,我们可以把a[i]当左值,无法把a当左值。也可以这么理解:a的内部是由很多小部分组成,我们只能通过访问这些小部分来达到访问
a的目的。
数组名代表数组首元素的地址,并不代表数组中的全部元素。因此用数组名作函数实参时,不是把实参数组的值传递给形参,而只是将实参数组首元素的地址传递给形参。形参可以是数组名,也可以是指针变量,它们用来接收实参传来的地址。如果形参是数组名,它代表的是形参数组首元素的地址。在调用函数时,将实参数组首元素的地址传递给形参数组名。这样,实参数组和形参数组就共占同一段内存单元
声明形参数组并不意味着真正建立一个包含若干元素的数组,在调用函数时也不对它分配存储单元,只是用array[]这样的形式表示array是一维数组名,以接收实参传来的地址。因此array[]中方括号内的数值并无实际作用,编译系统对一维数组方括号内的内容不予处理。形参一维数组的声明中可以写元素个数,也可以不写。C++实际上只把形参数组名作为一个指针变量来处理,用来接收从
实参传过来的地址
如果用二维数组名作为实参和形参,在对形参数组声明时,必须指定第二维(即列)的大小,且应与实 参的第二维的大小相同。第一维的大小可以指定,
``` #include<stdio.h> #include<string.h> int main() { //char
a[5]={'1','2','3','4'}; char a[5]="1234"; struct {int a;int b;} st ;
st.a =1; st.b=2; puts(a);
//:1234 printf("%d\n",sizeof(a)); //:5
printf("%d\n",sizeof(a[0])); //:1 printf("%d\n",sizeof(&a[0]));
//:4 printf("%p\n",(&a[0])); //:0x28cc7b
printf("%p\n",(&a[0]+1)); //:0x28cc7c printf("%p\n",(a));
//:0x28cc7b printf("%p\n",(a+1)); //:0x28cc7c
printf("%p\n",(&a)); //:0x28cc7b printf("%p\n",(&a+1));
//:0x28cc80 printf("%d\n",sizeof(st)); //:8
printf("%p\n",&st); //:0x28cc70 printf("%d\n",st.a);
//:1 printf("%d\n",st.b); //:2
memset(&st,0,sizeof(st)); printf("%d\n",st.a);
//:0 printf("%d\n",st.b); //:0 //memset(a,0,sizeof(a));
//memset(&a,0,sizeof(a)); memset(&a[0],0,sizeof(a)); puts(a); }
```