第十二章、数组
前面我们研究了基础数据类型和指针类型,这一章我们来学习更高级的数据类型数组。
在前面我们所书写的程序中,声明一个变量只能保存一个数据,比如要保存一个人的年龄信息通常这样来声明变量 int age = 35;。但当数据量比较多的时候,比如说现在有 1000 个人的年龄信息需要保存,如果我们创建 1000 个变量,这对于程序的书写,变量的命名,程序的维护和修改都带来极大的困难。那解决此问题最好的办法是使用 数组。
数组(Array) 是一系列相同类型变量顺序存储的集合。它允许将一系列具有相同数据类型的数据顺序的排列在内存中,使用统一的名称对这段内存内的数据进行访问和修改。也就是说数组中的所有成员的数据类型都是相同的。
数组按着维度分类分为一维数组、二维数组和多维数组。这一节我们先来学习一维数组。
1. 一维数组
一维数组声明的语法
数据类型 数组名[整数表达式] = {初始值1, 初始值2, ...}, ...;
说明:
- 前面的数据类型是数组内各个成员(也称为数据元素)的数据类型,不是数组的数据类型。
- 数组名必须是标识符。
- 数组名是一个常量,不能使用赋值语句对其进行赋值操作。
- 中括号内整数表达式是数组内数据元素的个数,有时也称为数组长度。数组长度必须是大于等于零的整数。
- 中括号内数组长度一般使用整数常量表达式。
- 在
C89版本的编译器中,此整数表达式必须是编译时能确定的整数常量值。 - 在
C11版本的编译器中,此整数表达式可以是动态运行得到的结果,此种方法创建的数组也称为变长数组,且变长数组必须在栈内创建(不能是全局变量或静态局部变量)。 - 在
C99版本的编译器中,部分编译器如:GCC、Clang支持变长数组,MSVC 不支持变长数组。
- 在
= {初始值1, 初始值2, ...}是数组的初始化列表,此部分可以省略不写,如果不给定初始化列表,数组内的数据元素的值可能是任意值。- 初始化列表 必须是用一对大括号(
{})括起来的表达式列表,初始化列表内表达式计算结果的类型需要能够隐式类型转化为数据元素的数据类型或者同数据元素的数据类型一致。 - 如果 初始化列表 内表达式的个数小于数据元素的个数,则后面其余的数据补充 零值。
- 中括号内整数表达式可以省略不写,如果不写整数表达式则编译器使用初始化列表来推断数组内数据元素的个数。
- 整数表达式 和 初始化列表 不能同时丢失,否则编译器则因无法确定数据元素个数而报错。
, ...表达式后面还可以声明变量,指针,数组等其它变量。- 数组有自己的数据类型,对于一维数组的数据类型是
数据类型[元素个数],如:int arr[100]的类型是int[100]。
示例:
// filename: 1d_array.c
#include <stdio.h>
int main(int argc, char *argv[]) {
// 声明含有 5 个数据元素的数组,每个数组内的数据类型是 int 类型。
int arr1[5]; // 数组的类型是 int[5]。
// 声明一个含有 5 个字符型数据的数组,第一个数据是 'a', 其它都是 '\0'
char arr2[5] = {'a'}; // 数组的类型是 char[5]。
// 声明一个含有两个短整型数据的数组。元素个数为 2。
short arr3[] = {100, 200}; // 数组的类型是 short int[2]。
// 声明含有 3 个 int 型指针的数组
int * arr4[3] = {}; // 三个空指针,数组的类型是 int*[3]。
printf("sizeof(arr1): %ld\n", sizeof(arr1));
printf("sizeof(arr2): %ld\n", sizeof(arr2));
printf("sizeof(arr3): %ld\n", sizeof(arr3));
printf("sizeof(arr4): %ld\n", sizeof(arr4));
return 0;
}
运行结果如下:
weimingze@mzstudio:~$ gcc -o 1d_array 1d_array.c
weimingze@mzstudio:~$ ./1d_array
sizeof(arr1): 20
sizeof(arr2): 5
sizeof(arr3): 4
sizeof(arr4): 24
由运行结果可知,数组占用的空间是 数据元素的个数 ✖️ 每个数据元素占用的内存长度。
变长数组示例
// filename: vla.c
#include <stdio.h>
int main(int argc, char *argv[]) {
int element_count = 0;
printf("please input student count: ");
scanf("%d", &element_count);
int scores[element_count];
printf("sizeof(scores): %ld\n", sizeof(scores));
return 0;
}
运行结果如下:
weimingze@mzstudio:~$ gcc -o vla vla.c
weimingze@mzstudio:~$ ./vla
please input student count: 10
sizeof(scores): 40
使用变长数组需要注意以下问题:
- 不是所有的编译器都能使用变长数组,为了程序的可移植性,尽可能少使用变长数组。
- 变长数组只能在栈上声明,也就是说只能在函数内部声明且不可以是静态局部变量(后面会讲)。
- 变长数组由于在栈上运行,因此可能会因数组个数的不确定导致栈溢出,导致程序运行不稳定。
实验:
- 尝试写程序声明变长数组,看你的编译器是否支持变长数组的编译。
- 运行上述
vla.c编译后的程序,输入一个比较大的数字,查看运行结果。