在上个系列【C 语言入门】里面,已经对数组和指针定义和使用做了初步的了解。在本文章中,将深入探索:如何使用数组来处理相同类型的批量数据。
定义:数组是具有相同数据类型,并且按照一定顺序排列的一组变量的集合。
特征:
有序性:数组元素之间具有固定的先后顺序可索引:通过数组名和下标可以唯一地确定数组中的元素数组的命名遵循《C 语言标识符的命名规则》 :
标识符由字母、数字和下划线组成第一个字母不能是数字,只能是字母或下划线区分大小写字母C 语言规定了一个标识符的字符个数。C 语言规定标识符的最大长度可达 255 个字符,只有前 32 个字符在编译时有效。在定义数组时,需要指定数组元素的个数,即数组长度。 方括号 [ ] 中的常量表达式用于表示数组元素的个数。
Example 1:使用常量表达式指定数组长度
// 定义了一个 int 型的数组,数组长度为 4,具有 4 个数组元素 int a[4]; // 数组下标是从 0 开始 // 注意: 依据上面的定义,数组 a 仅有 4 个数组元素, // 分别为:a[0]、 a[1]、 a[2]、 a[3],并不存在数组元素 a[4] a[0] = 0; /* 将数组 a 的 第 0 个 数组元素赋值为 0 */ a[1] = 1; /* 将数组 a 的 第 1 个 数组元素赋值为 1 */ a[2] = 2; /* 将数组 a 的 第 2 个 数组元素赋值为 2 */ a[3] = 3; /* 将数组 a 的 第 3 个 数组元素赋值为 3 */ a[4] = 4; /* 错误! */Example 2 :使用初始化列表指定数组长度。
// 通过对全部数组元素赋初值来指定数组长度,此时,可以不指定数组长度。 char g_A_Array[] = {0, 1, 2, 3, 4, 5}; printf("g_A_Array's length is %d\r\n", sizeof(g_A_Array));运行结果:
C 语言不允许对数组的长度做动态定义。即:常量表达式可以包括常量和符号常量,但不能包含变量。
常量表达式可以包含常量 int a[4]; // 正确 int b[1 + 3]; // 正确 常量表达式可以包含符号常量 #define ArraySize 4 int c[ArraySize]; // 正确 常量表达式不可以包含变量 int n; scanf("%d", &n); int a[n]; // 错误NOTE: 如果在被调用的函数(不包含主函数)中定义数组,数组的长度可以是变量或非常量表达式,此数组称为“可变长数组,variable-length arrays(VLAs)”。
Example:VLAs
/* 数组 a 的数组长度表达式为在调用 func 函数时形参 n 从实参得到的值 * 允许在每次调用 func 函数时,n 有不同的值 * 称数组 a 为 可变长数组,variable-length arrays (VLAs) * VLAs 为 C99 标准中新增的一项 * * 值得注意的是,Visual Studio 不支持 VLAs * 若在 Visual Studio 中使用 VLAs,会报 “error C2123:表达式的计算结果不是常量” 的错误 */ void func(int n) { int a[n]; /*正确*/ } /* 若 a 数组为静态存储方式(static), 则不能用 VLAs,即 funb 的写法是错误的 */ void funb(int n) { static int a[n]; /*错误*/ }NOTE:只能引用数组元素,而不能一次整体调用整个数组的全部元素的值。
引用数组元素的形式:
数组名[下标]Example 1 :a[0] 表示数组 a 中序号为 0 的元素。
Example 2:依次给数组 a 的元素赋值,再倒序输出数组 a 的元素。
int main() { int a[10]; // 创建数组 int i; for (i = 0; i < 10; i++) { a[i] = i; // 数组元素赋值 } for (i = 9; i >= 0; i--) { printf("a[%d] = %d\r\n", i, a[i]); } return 0; }输出结果: NOTE:数组元素的下标由 0 开始。即最后一个数组元素的下标为数组长度减 1。
一维数组的初始化:在定义数组的同时,给各数组元素赋值,这称为数组的初始化。
在定义数组时对全部数组元素进行赋初值 Example: // 花括号 {} 内的数据称为 “初始化列表” int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 只给一部分数组元素赋初值 Example:仅给 a 数组的前面 5 个元素赋初值 int main() { int a[10] = { 0, 1, 2, 3, 4 }; int i; for (i = 0; i < 10; i++) { printf("a[%d] = %d\r\n", i, a[i]); } return 0; }运行结果:
对一维数组中的全部元素值赋值为 0 方式 1: a[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};方式 2:
a[10] = {0}; 通过对全部数组元素赋初值来确定数组的元素个数,从而不指定数组长度 Example: int main() { int a[] = { 0, 1, 2, 3, 4 }; // 数组定义并初始化 int i, aLength; aLength = sizeof(a) / sizeof(int); // 获取数组长度 printf("a's Length = %d\r\n", aLength); for (i = 0; i < aLength; i++) { printf("a[%d] = %d\r\n", i, a[i]); } return 0; }输出结果:
输出结果:
二维数组常称为矩阵(matrix)。
NOTE:
行(column)列(row)Example:
a[3][4]; // 定义 3 行 4 列的数组 b[4][3]; // 定义 4 行 3 列的数组NOTE: C 语言中,二维数组中元素排列的顺序是按行排列,即在内存中,先顺序存放第 1 行的元素,再存放第 2 行的元素。同时,各个元素都是连续存放的。
Example:使用指针查看二维数组 a 的存放情况。
int main() { int a[3][4]; int i,j; int *addrOfa = &a[0][0]; printf("a:\r\n"); for (i = 0; i < 3; i++) { for (j = 0; j < 4; j++) { a[i][j] = 4*i + j; printf("a[%d][%d] = %d ,", i, j, a[i][j]); } printf("\r\n"); } printf("a's Base Address: %x\r\n", addrOfa); for (i = 0; i < (3 * 4); i++) { printf("Addr %x = %d\r\n", (addrOfa + i), *(addrOfa+i)); } getchar(); return 0; }运行结果: 通过运行结果,可得知:
在内存中,先顺序存放第 1 行的元素,再存放第 2 行的元素。各个元素都是连续存放的。二维数组元素的引用形式:
数组名[下标 col][下标 row]Example:
a[0][1] 表示数组 a 中第 0 行第 1 列的元素。 a[8][9] 表示数组 a 中第 8 行第 9 列的元素。NOTE: 二维数组的下标均从 0 开始。
Example:
int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };Example:行列置换。 源数组:
aArray = {{1, 2, 3}, {4, 5, 6}}目标数组:
bArray = {{1, 4}, {2, 5}, {3, 6}}实现代码:
#include "stdio.h" #define aLine 2 #define aColumn 3 int a[aLine][aColumn] = { { 1, 2, 3 }, { 4, 5, 6 } }; int b[aColumn][aLine]; static void OutputA(void) { int i, j; printf("a[%d][%d]={\r\n", aLine, aColumn); for (i = 0; i < aLine; i++) { printf("{"); for (j = 0; j < aColumn; j++) { printf("%d", a[i][j]); if (j != (aColumn - 1)){ printf(", "); } } printf("}"); if (i != (aLine - 1)){ printf(", "); } printf("\r\n"); } printf("}\r\n"); } static void OutputB(void) { int i, j; printf("b[%d][%d]={\r\n",aColumn , aLine); for (i = 0; i < aColumn; i++) { printf("{"); for (j = 0; j <aLine; j++) { printf("%d", b[i][j]); if (j != (aLine - 1)) { printf(", "); } } printf("}"); if (i != (aColumn - 1)) { printf(", "); } printf("\r\n"); } printf("}\r\n"); } int main(void) { int i, j; OutputA(); for (i = 0; i < aLine; i++) { for (j = 0; j < aColumn; j++) { b[j][i] = a[i][j]; } } OutputB(); }输出结果:
字符型数据是以字符的 ASCII 码形式存放在内存单元中的。C 语言中没有字符串类型,字符串是存放在字符型数组中的。
字符数组:用来存放字符数据的数组,字符数组中的一个元素存放一个字符。
char 数组名[数组长度]使用初始化列表对字符数组进行初始化,把各个字符依次赋给数组中的各个元素。 Example:把 10 个字符依次赋给 a[0] ~ a[10]。
char a[10] = {'I', ' ', 'a', 'm', ' ', 'h', 'a', 'p', 'p', 'y'};NOTE: 如果在定义字符数组时不进行初始化,则数组中的各个元素的值是不可预料的。
若花括号 {} 中提供的初值个数大于数组长度,则出现语法错误如初值个数小于数组长度,则只将这些字符赋给数组中前面的元素,其余的元素自动定为空字符,即 '\0' Example:打印字符数组 a 元素的字符值和整型值。 int main(void) { char a[10] = { 'I', ' ', 'a', 'm' }; int i; for (i = 0; i < 10; i++) { printf("a[%d] = '%c'(char), =(int)\r\n", i, a[i], a[i]); } return 0; }输出结果:
若提供的初值个数与预期的数组长度相同,则可省略数组长度,系统会自动根据初值个数确定数组长度。 Example: char a[ ] = {'I', ' ', 'a', 'm', ' ', 'h', 'a', 'p', 'p', 'y'};可以通过引用字符数组的一个元素,得到一个字符。 Example:打印已知的字符串。 Example:打印字符数组 a 元素的字符值和整型值。
int main(void) { char a[10] = { 'I', ' ', 'a', 'm' }; int i; printf("a[10] = \"%s\"\r\n", a); for (i = 0; i < 10; i++) { printf("a[%d] = '%c'(char), =(int)\r\n", i, a[i], a[i]); } getchar(); }输出结果: 在输出结果中,能发现 使用 %s 进行打印时,a 仅输出了 4个字符:‘I’, ‘ ’, ‘a’, ‘m’。这是因为 ‘\0’ (整型值为 0)是 C 语言规定的 “字符串结束标记”,也就是说在遇到字符 ‘\0’ 时,表示字符串结束,把它之前的字符组合成一个字符串。C 系统中,在用字符数组存储字符串常量时会自动加一个 ‘\0’ 作为结束字符。 在执行 printf 函数时,没输出一个字符检测一次,看下一个字符是否为 ‘\0’, 遇到 ‘\0’ 就停止输出。因此,上例子,仅输出了 I am。
