13. C语言 -- 数组

本博客主要内容为 “小甲鱼” 视频课程《带你学C带你飞》【第一季】 学习笔记,文章的主题内容均来自该课程,在这里仅作学习交流。在文章中可能出现一些错误或者不准确的地方,如发现请积极指出,十分感谢。
也欢迎大家一起讨论交流,如果你觉得这篇文章对你有所帮助,记得评论、点赞哦 ~(。・∀・)ノ゙

1. 数组的含义

  一言以蔽之,数组就是存储一批同类型数据的地方。

2. 定义数组

  在 c 语言中往往需要先定义再使用,数组的定义方式如下

类型 数组名[常量表达式]
// 举例说明
int a[6]; // 定义一个整型数组,总共存放6个元素
char b[24]; // 定义一个字符型数组,总共存放24个元素
double c[3]; // 定义一个双精度浮点型数组,总共存放3个元素

在定义数组时,需要在数组名后边紧跟着一对方括号,其中用常量表达式来指定数组中元素的个数。因为只有告诉编译器元素的个数,编译器才能申请对应大小的内存给它存放。

  现在回顾一下最开始的时候讲过的一个问题,上边的几个类型,都占用多少个字节的内存?如下图所示
13. C语言 -- 数组_第1张图片

回顾《4. C语言 – 数据类型和取值范围》中的 2.3 节的内容可以知道,int 型占 4 个字节,char 型占 1 个字节,double 型占 8 个字节。所以上面所定义的三个号数组都占据 24 个字节~

3. 数组的初始化

  在定义数组的同时对其各个元素进行赋值,称之为数组的初始化,主要有以下五种方式

  (1) 将数组中首位初始化为某个数值,其余位置初始化为 0

int a[10] = {0}; // 将数组中所有元素初始化为0

在这种方式中有一点需要注意,其中 {0} 并不是将数组内的所有元素初始化为 0 的含义,而是数组中的第一个元素的值为 0,剩余元素值为 0 的意思。因此通过 int a[10] = {3} 的数组,实际上只有第一个数字为 3 ,其余数字均为0。

  (2) 只给一部分元素赋值,未被赋值的元素自动初始化为 0

// 表示为前边 6 个元素赋值,后边 4 个元素系统自动初始化为 0
int a[10] = {1, 2, 3, 4, 5, 6}; 

所以第一种方法实际上是着一种方法的特例。
  (3) 如果是赋予不同的值,那么用逗号分隔开即可

int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};

  (4) 只给出各个元素的值,而不指定数组的长度

int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};

  (5) 指定初始化的元素

// 编译的时候记得加上–std=c99选项
int a[10] = {[3] = 3, [5] = 5, [8] = [8]}; 

C99 增加了一种新特性——指定初始化的元素。这样就可以只对数组中的某些指定元素进行初始化赋值,而未被赋值的元素自动初始化为 0。

3.1 区分两种初始化方法

  在上面的初始化方法中,要注意区分第二种和第四种初始化的方法。其中第二种初始化的方法已经指定了数组的长度,因此即使只给出前面一部分的数字,也会自动补充后面的数字;但是第四种方法是通过 {} 给出元素自动确定数组的长度。比如说下面这两种初始化的方式

// 长度为10 ,指定前六个元素,后面的自动补零
int a[10] = {1, 2, 3, 4, 5, 6}; 

// 长度为 5
int b[] = {1, 2, 3, 4, 5, 6}; 

所以如果访问 b[5] 就会发生数组越界,要么报错,要么得到一个随机数(具体是那种情况根据编译器而定)。

3.2 未初始化直接访问

  如果现在只定义了一个数组,但是没有给数组进行初始化,那么会出现什么样的情况呢,比如说下面的这段代码

#include 

int main()
{
	int a[5];
	for (int i=0; i<5; i++)
	{
		printf("%d\n",a[i]);
	}
	
	return 0;
}

会得到如下的输出

4195840
0
4195488
0
-1332944752

会得到一堆乱起八糟的数据,这是为什么呢?这主要涉及到栈结构中的数据是随机的,栈结构的内容会在后面进行介绍。

4. 变长数组(VLA,variable length array)

  在 C99 标准中,数组的尺寸如果是整型常量或者整型常量表达式,或者确定他的尺寸的时候,他就不是一种长度可变的数组,相反(即指其余条件下)则是一个长度可变的数组。即在 C99 标准中,c 语言已经支持变长数组了。注意这里的变长指的是数组的长度是在运行的时候才会被决定,就是说可以用一个变量来指定组的长度。

  上面是在 C99 的标准中关于变长数组的说明,接着我们来一下,如果使用了 C99 标准中的变长数组是否可以使用 gcc 来进行编译呢?答案是可以的。因为作为编译器的扩展,gcc 在 C90 模式下和 C++ 模式下都是遵守 C99 标准的。所以 gcc 即使没有加上 -std=c99,就是他默认以 C90 标准进行编译的时候,也是遵守 C99 标准的,所以使用变长数组的时候,不用加上 -std=c99 也是可以正常运行的。

  所以下面代码是合法的

#include 

int main()
{
        int n, i;

        printf("请输入字符的个数:");
        scanf("%d", &n);

        char a[n+1]; 

        printf("请开始输入字符:");
        getchar(); // 将标准输入流中剩下的 '\n' 扔掉
        for (i = 0; i < n; i++)
        {
                scanf("%c", &a[i]);
        }
        a[n] = '\0';
        printf("你输入的字符串是:%s\n", a);

        return 0;
}

在这段代码中,我们使用了一个整型的变量 n+1 来表示数组的长度,仍然可以编译通过并执行,说明变长数组确实是可用的。

  但是在这段代码中,仍有几个部分是需要注意的。首先是数组的长度,通过第 7、8 两行可以知道输入的字符个数应该是 n 个 ,但是为什么数组的长度会定义为 n+1 呢?这主要是因为字符串都是以 '\0' 结尾的,但是 '\0' 又不可能通过用户来输入,所以要定义一个 n+1 长度的数组,然后自己在里面加入'\0' 作为字符串的结尾。

  其次我们在第 13 行加入了 getchar(); ,这主要是将标准输入流中剩下的 '\n' 扔掉。之所以 '\n' 会在输入缓冲区可以参考 《9. C 语言 – 循环结构:while语句和 do … while语句》 3.3 三种输入函数的注意事项 中的内容。读取字符时 scanf() 以 Enter 结束一次输入,不会舍弃最后的回车符。所以如果不使用 scanf() 会造成首先读入键盘缓冲区的回车符,之后再读入数组中的字符,会导致数组中的最后一个字符无法正确显示。

5. 访问数组

  数组的访问方式很直觉,即通过下标进行访问;但是比较反直觉的是,数组的小标从 0 开始,所以某个数组中第一个元素的下表是 0 而不是 1。所以在第一张图中,每一行中的数字实际上是数组的下标。

  访问数组具体方式如下

// 数组访问方式
数组名[下标]
a[0]; // 访问a数组中的第一个元素
b[1]; // 访问b数组中的第二个元素

有两点个需要注意,首先定义数组与访问数组的写法十分相似,区别在于定义数组需要申明数组内变量的类型,但是访问不需要;在访问数组的过程中要注意数组越界的问题,如下

int a[5]; // 创建一个具有五个元素的数组
a[0]; // 访问第一个元素的下标是0,不是1
a[5]; // 数组越界,因为第五个元素的下标是a[4]

当数组发生越界情况时,本身在 C语言中属于未定义行为,不同的编译器可能会有不同的对待方式。比如说在 gcc 中,会随机给越界访问的数组元素分配一个数字。

6. 循环和数组的关系

  实现一个执行10次的循环,我们通常下面的第一种写法,而不是第二种写法

// 常用
for (i = 0; i < 10; i++)
{
    ……
}
// 不常用
for (i = 1; i <= 10; i++)
{
    ……
}

这是因为我们常常需要使用循环来访问数组,而数组的下标是从 0 开始的。

  如果我们采用只给出各个元素的值,而不指定数组的长度的方法来初始化数组,比如说int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};,这个时候我们并不知道数组的长度。如果要写一个 for 循环来遍历数组中的每一个元素,应该使用下面这种方法

for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
	printf("%2d月份:%d天\n", i+1, days[i]);
}

使用这样的方法表达数组的长度是在实际开发中是很常见的技巧。

参考

[1] “小甲鱼” 视频课程《带你学C带你飞》【第一季】P17
[2] “小甲鱼” 视频课程《带你学C带你飞》【第一季】P18

欢迎大家关注我的知乎号(左侧)和经常投稿的微信公众号(右侧)
13. C语言 -- 数组_第2张图片

你可能感兴趣的:(C,从零入门C语言!!!)