【C语言进阶剖析】27、数组的本质分析

1 数组的概念

  • 数组是相同类型的变量的有序集合

在这里插入图片描述

2 数组的大小

  • 数组在一片连续的内存空间中存储元素
  • 数组元素的个数可以显示或隐式指定

如下定义两个数组 a 和 b
在这里插入图片描述
有两个问题?

  1. a[2],a[3],a[4] 的值是多少?
  2. b 包含了多少个元素?

下面我们就来实际操作一下:

// 27-1.c
#include<stdio.h>
int main()
{
    int a[5] = {1, 2};
    int b[] = {1, 2};
    printf("a[2] = %d\n", a[2]);
    printf("a[3] = %d\n", a[3]);
    printf("a[4] = %d\n", a[4]);

    printf("sizeof(a) = %ld\n", sizeof(a));
    printf("sizeof(b) = %ld\n", sizeof(b));
    printf("count for a:  %ld\n", sizeof(a)/sizeof(int));
    printf("count for b:  %ld\n", sizeof(b)/sizeof(int));
    return 0;
}
$ gcc 27-1.c -o 27-1
$ ./27-1
a[2] = 0
a[3] = 0
a[4] = 0
sizeof(a) = 20
sizeof(b) = 8
count for a:  5
count for b:  2
  • 可以看到数组 a 只初始化了前两个元素,后面三个元素没有初始化,自动初始化为 0。
  • 数组 a 的长度为 20 字节,里面保存了 5 个 int 型的数据类型,数组 b 元素的个数被隐式初始化,根据元素的个数确定数组长度,所以数组 b 长度为 2,里面有两个 int 型的变量。
  • 求解数组长度的方法:数组长度除以单个元素长度 sizeof(a)/sizeof(a[0])
  • 如果想将数组所有元素都初始化为 0,可以这么写: int a = { 0 }; 也就是第一个元素初始化为 0,后面的默认初始化,也是 0

3 数组地址与数组名

  • 数组名代表数组首元素的地址
  • 数组的地址需要用取地址符 & 才能得到
  • 数组首元素的地址值与数组的地址值相同
  • 数组首元素的地址与数组的地址是两个不同的概念
//27-2.c
#include<stdio.h>
int main()
{
    int a[5] = { 0 };
    printf("a = %p\n", a);
    printf("&a = %p\n", &a);
    printf("&a[0] = %p\n", &a[0]);
    return 0;
}
$ gcc 27-2.c -o 27-2
$ ./27-2
a = 0x7ffc98bcb2c0
&a = 0x7ffc98bcb2c0
&a[0] = 0x7ffc98bcb2c0
  • 数组名就是数组首元素的地址,所以 a 和 &a[0] 是一样的。
  • 数组的地址指的是整个数组的地址,数值上等于数组首元素的地址,但是含义是不一样的。数组首元素的地址表示第一个元素的地址,一共只有一个元素,数组的地址表示整个数组的地址,一共有 5 个元素。这就好比是你家住小区第一户,你家的编号和小区编号一样,但是不能说整个小区都是你家。

4 数组名的盲点

  • 数组名可以看做一个常量指针
  • 数组名“指向”的是内存中数组首元素的起始位置
  • 数组名不包含数组的长度信息
  • 在表达式中数组名只能作为右值使用
  • 只有在下列场合中数组名不能被看作常量指针
    • 数组名作为 sizeof 操作符的参数
    • 数组名作为 & 运算符的参数

为了更好的区别指针与数组,下面看个例子

// 27-3.c
#include<stdio.h>
int main()
{
    int a[5] = {0};
    int b[1];
    int* p = NULL;
    p = a;
    printf("a = %p\n", a);				// 数组的地址
    printf("p = %p\n", p);				// 指针p的内容,指针p指向数组a首元素,所以p是第一个元素的地址
    printf("&p = %p\n", &p);			// 指针也是变量,也有地址
    printf("sizeof(a) = %ld\n", sizeof(a));	// 数组的大小
    printf("sizeof(p) = %ld\n", sizeof(p));	// 指针的大小

    printf("\n");

    p = b;
    printf("b = %p\n", b);
    printf("p = %p\n", p);
    printf("&p = %p\n", &p);
    printf("sizeof(b) = %ld\n", sizeof(b));
    printf("sizeof(p) = %ld\n", sizeof(p));

    //b = a;		// error
    return 0;
}
$ gcc 27-3.c -o 27-3
$ ./27-3
a = 0x7ffce8616f60
p = 0x7ffce8616f60
&p = 0x7ffce8616f50
sizeof(a) = 20
sizeof(p) = 8

b = 0x7ffce8616f5c
p = 0x7ffce8616f5c
&p = 0x7ffce8616f50
sizeof(b) = 4
sizeof(p) = 8

不管数组大小如何变化,指针永远是 8 个字节(64位系统),指针与数组完全不是一概念

5 小结

1、数组是一片连续的内存空间
2、数组的地址和数组首元素的地址意义不同
3、数组名在大多数情况下被当作常量指针处理
4、数组名其实并不是指针,不能将其等同于指针

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页