四、數(shù)組
第04章_數(shù)組
本章專題脈絡(luò)

1、數(shù)組的概述
1.1 為什么需要數(shù)組
需求分析1:
需要統(tǒng)計(jì)某公司50個(gè)員工的工資情況,例如計(jì)算平均工資、找到最高工資等。用之前知識(shí),首先需要聲明50個(gè)變量來(lái)分別記錄每位員工的工資,這樣會(huì)很麻煩。因此我們可以將所有的數(shù)據(jù)全部存儲(chǔ)到一個(gè)容器中統(tǒng)一管理,并使用容器進(jìn)行計(jì)算。
需求分析2:
容器的概念:
- 生活中的容器:水杯(裝水等液體),衣柜(裝衣服等物品),集裝箱(裝貨物等)。
- 程序中的容器:將多個(gè)數(shù)據(jù)存儲(chǔ)到一起,每個(gè)數(shù)據(jù)稱為該容器的元素。
1.2 數(shù)組的概念
-
數(shù)組(Array),是多個(gè)
相同類型數(shù)據(jù)按一定順序排列的集合,并使用一個(gè)名字命名,并通過(guò)編號(hào)的方式對(duì)這些數(shù)據(jù)進(jìn)行統(tǒng)一管理。 -
數(shù)組中的概念
- 數(shù)組名
- 下標(biāo)(或索引、index)
- 元素
- 數(shù)組的長(zhǎng)度

數(shù)組的特點(diǎn):
- 數(shù)組中的元素在內(nèi)存中是依次緊密排列的,有序的。
- 創(chuàng)建數(shù)組對(duì)象會(huì)在內(nèi)存中開辟一整塊
連續(xù)的空間。占據(jù)的空間的大小,取決于數(shù)組的長(zhǎng)度和數(shù)組中元素的類型。 - 我們可以直接通過(guò)下標(biāo)(或索引)的方式調(diào)用指定位置的元素,速度很快。
- 數(shù)組,一旦初始化完成,其長(zhǎng)度就是確定的。數(shù)組的
長(zhǎng)度一旦確定,就不能修改。 - 數(shù)組名中引用的是這塊連續(xù)空間的首地址。
1.3 數(shù)組的分類
按照數(shù)組維度分:
- 一維數(shù)組:存儲(chǔ)一組數(shù)據(jù)
- 二維數(shù)組:存儲(chǔ)多組數(shù)據(jù),相當(dāng)于二維表,一行代表一組數(shù)據(jù)。每一行長(zhǎng)度可以不同。
- 三維數(shù)組、四維數(shù)組、....

按照元素的數(shù)據(jù)類型分:
- int類型數(shù)組
- char類型數(shù)組
- double類型數(shù)組
- ....
2、一維數(shù)組的定義
2.1 數(shù)組的定義方式1
數(shù)組通過(guò)變量名后加方括號(hào)表示,方括號(hào)里面是數(shù)組可以容納的成員數(shù)量(即長(zhǎng)度)。
int arr[10]; //數(shù)組 arr ,里面包含10個(gè)成員,每個(gè)成員都是 int 類型
#define NUM 10
int arr1[NUM];
注意,聲明數(shù)組時(shí),必須給出數(shù)組的大小。

2.2 數(shù)組元素的調(diào)用
-
格式:
數(shù)組名[下標(biāo)] -
數(shù)組的
下標(biāo)從0開始,用“int arr[10];”定義數(shù)組,則最大下標(biāo)值為9,不存在數(shù)組元素arr[10]。
arr[0] = 13; //對(duì)該位置數(shù)組元素進(jìn)行賦值
int score = arr[0]; //調(diào)用此位置的元素值
數(shù)組角標(biāo)越界:
假設(shè)數(shù)組有n個(gè)元素,如果使用的數(shù)組的下標(biāo)小于0,或者大于n-1,就是數(shù)組越界訪問(wèn)了,超出了數(shù)組合法空間的訪問(wèn)。
C語(yǔ)言不做數(shù)組下標(biāo)越界的檢查,編譯器也不一定報(bào)錯(cuò),但是編譯器不報(bào)錯(cuò),并不意味著程序就是正確!
int scores[20];
scores[20] = 51;
說(shuō)明:數(shù)組 scores 只有20個(gè)成員,因此 scores[20] 這個(gè)位置是不存在的。但是,引用這個(gè)位置并不會(huì)報(bào)錯(cuò)。賦值操作會(huì)導(dǎo)致緊跟在 scores 后面的那塊內(nèi)存區(qū)域被賦值(這實(shí)際是其它變量的區(qū)域),因此不知不覺就更改了其它變量的值。這很容易引發(fā)錯(cuò)誤,而且難以發(fā)現(xiàn)。
2.3 關(guān)于長(zhǎng)度
數(shù)組的字節(jié)長(zhǎng)度
sizeof 運(yùn)算符會(huì)返回整個(gè)數(shù)組的字節(jié)長(zhǎng)度。
int arr[10];
printf("數(shù)組的字節(jié)長(zhǎng)度為:%zd\n",sizeof(arr)); //40
數(shù)組的長(zhǎng)度
在定義數(shù)組時(shí),需要指定數(shù)組中元素的個(gè)數(shù),方括號(hào)中的常量表達(dá)式用來(lái)表示元素的個(gè)數(shù),即數(shù)組長(zhǎng)度。
由于數(shù)組成員都是同一個(gè)類型,每個(gè)成員的字節(jié)長(zhǎng)度都是一樣的,所以數(shù)組整體的字節(jié)長(zhǎng)度除以某個(gè)數(shù)組元素的字節(jié)長(zhǎng)度,就可以得到數(shù)組的成員數(shù)量。
//數(shù)組中元素的個(gè)數(shù):
int arrLen = sizeof(arr) / sizeof(arr[0]);
int a[10];
printf("數(shù)組的字節(jié)長(zhǎng)度為:%zu\n", sizeof(a)); // 40
printf("數(shù)組每個(gè)元素的字節(jié)長(zhǎng)度為:%zu\n", sizeof(int)); // 4
printf("數(shù)組的長(zhǎng)度為:%zu\n", sizeof(a) / sizeof(int)); // 10
復(fù)習(xí): sizeof 返回值的數(shù)據(jù)類型是
size_t,所以 sizeof(a) / sizeof(a[0]) 的數(shù)據(jù)類型也是size_t 。在 printf() 里面的占位符,要用 %zd 或 %zu 。
注意:數(shù)組一旦聲明/定義了,其長(zhǎng)度就固定了,不能動(dòng)態(tài)變化。
2.4 數(shù)組的遍歷
將數(shù)組中的每個(gè)元素分別獲取出來(lái),就是遍歷。for循環(huán)與數(shù)組的遍歷是絕配。
舉例1:聲明長(zhǎng)度為10的int類型數(shù)組,給數(shù)組元素依次賦值為0,1,2,3,4,5,6,7,8,9,并遍歷數(shù)組所有元素
int main() {
int arr[10];
//給數(shù)組中的每個(gè)元素賦值
for (int i = 0; i < sizeof(arr)/sizeof(int); i++) { //對(duì)數(shù)組元素arr[0]~arr[9]賦值
arr[i] = i;
}
//遍歷數(shù)組中的元素
printf("遍歷數(shù)組中的元素:\n");
for (int i = 0; i < sizeof(arr)/sizeof(int); i++) { //輸出arr[0]~arr[9]共10個(gè)數(shù)組元素
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
2.5 數(shù)組的其它定義方式
定義方式2:(定義方式1在2.1節(jié)講的)
數(shù)組可以在聲明時(shí),使用大括號(hào),同時(shí)對(duì)每一個(gè)成員賦值。
int arr[5] = {22, 37, 90, 48, 95};
變形形式1:C 語(yǔ)言允許省略方括號(hào)里面的數(shù)組成員數(shù)量,這時(shí)根據(jù)大括號(hào)里面的值的數(shù)量,自動(dòng)確定數(shù)組的長(zhǎng)度。
int arr[3] = {10,20,30};
// 等同于
int arr[] = {10,20,30}; //數(shù)組 arr 的長(zhǎng)度,將根據(jù)大括號(hào)里面的值的數(shù)量,確定為 3
變形形式2:
對(duì)數(shù)組部分元素賦初值:如果大括號(hào)里面的值,少于數(shù)組的成員數(shù)量,那么未賦值的成員自動(dòng)初始化為 0 。
int arr[5] = {10, 20, 30};
// 等同于
int arr[5] = {10,20,30, 0, 0};
變形方式3:
將整個(gè)數(shù)組的每一個(gè)成員都設(shè)置為零,最簡(jiǎn)單的方式如下
int a[100] = {0};
錯(cuò)誤方式:
使用大括號(hào)賦值時(shí),大括號(hào)里面的值不能多于數(shù)組的長(zhǎng)度,否則編譯時(shí)會(huì)報(bào)錯(cuò)。
int arr[3] = {1,2,3,4}; // 報(bào)錯(cuò)
定義方式3:數(shù)組初始化時(shí),可以指定為哪些位置的成員賦值。
int arr[15] = {[2] = 10, [5] = 20, [14] = 30}; //非角標(biāo)2、5、14的位置自動(dòng)賦值為0
//等同于
int arr[15] = {[5] = 20, [14] = 30, [2] = 10}; //指定位置的賦值可以不按角標(biāo)從小到大的順序
變形形式1:指定位置的賦值與順序賦值,可以結(jié)合使用。
int arr[15] = {1, [5] = 10, 11, [10] = 20, 21}; //角標(biāo)0、5、6、10、11的位置被賦值
變形形式2:省略成員數(shù)量時(shí),如果同時(shí)采用指定位置的賦值,那么數(shù)組長(zhǎng)度將是最大的指定位置再加1。
int arr[] = {[2] = 6, [9] = 12}; //此時(shí)數(shù)組的長(zhǎng)度是10
3、一維數(shù)組內(nèi)存分析
3.1 數(shù)組內(nèi)存圖
針對(duì)于如下代碼:
int a[5] = {1,2,3,4,5};
對(duì)應(yīng)的內(nèi)存結(jié)構(gòu):

說(shuō)明:
1)數(shù)組名,記錄該數(shù)組的首地址 ,即 a[0]的地址。
2)數(shù)組的各個(gè)元素是連續(xù)分布的, 假如 a[0] 地址是0x1122,則a[1]地址= a[0]的地址+int字節(jié)數(shù)(4) = 0x1122 + 4 = 0x1126,后面 a[2] 地址 = a[1]地址 + int 字節(jié)數(shù)(4) = 0x1126 + 4 = 0x112A,依次類推...
3.2 注意事項(xiàng)
C 語(yǔ)言規(guī)定,數(shù)組變量一旦聲明,數(shù)組名指向的地址就不可更改。因?yàn)槁暶鲾?shù)組時(shí),編譯器會(huì)自動(dòng)為數(shù)組分配內(nèi)存地址,這個(gè)地址與數(shù)組名是綁定的,不可更改。
因此,當(dāng)數(shù)組定義后,再用大括號(hào)重新賦值,是不允許的。下面的代碼會(huì)報(bào)錯(cuò)。
錯(cuò)誤舉例1:
int nums[5];
nums = {22, 37, 3490, 18, 95}; // 使用大括號(hào)賦值時(shí),必須在數(shù)組聲明時(shí)賦值,否則編譯時(shí)會(huì)報(bào)錯(cuò)。
錯(cuò)誤舉例2:
int nums[5] = {1, 2, 3, 4, 5};
nums = {6, 7, 8, 9, 10}; // 報(bào)錯(cuò)
錯(cuò)誤舉例3:
int ints[100];
ints = NULL; //報(bào)錯(cuò)
這也導(dǎo)致不能將一個(gè)數(shù)組名賦值給另外一個(gè)數(shù)組名。
int a[5] = {1, 2, 3, 4, 5};
// 寫法一
int b[5] = a; // 報(bào)錯(cuò)
// 寫法二
int b[5];
b = a; // 報(bào)錯(cuò)
上面兩種寫法都會(huì)更改數(shù)組 b 的地址,導(dǎo)致報(bào)錯(cuò)。
3.3 變長(zhǎng)數(shù)組
數(shù)組聲明的時(shí)候,數(shù)組長(zhǎng)度除了使用常量,也可以使用變量或表達(dá)式來(lái)指定數(shù)組的大小。這叫做變長(zhǎng)數(shù)組(variable-length array,簡(jiǎn)稱 VLA)。
方式1:
int n = 10;
int arr[n];
變長(zhǎng)數(shù)組的根本特征是數(shù)組長(zhǎng)度只有運(yùn)行時(shí)才能確定。它的好處是程序員不必在開發(fā)時(shí),隨意為數(shù)組指定一個(gè)估計(jì)的長(zhǎng)度,程序可以在運(yùn)行時(shí)為數(shù)組分配精確的長(zhǎng)度。
任何長(zhǎng)度需要運(yùn)行時(shí)才能確定的數(shù)組,都是變長(zhǎng)數(shù)組。比如,
int i = 10;
int a1[i];
int a2[i + 5];
int a3[i + k];
注意:變長(zhǎng)數(shù)組在C99標(biāo)準(zhǔn)中被引入,在C11標(biāo)準(zhǔn)中被標(biāo)記為可選特性。某些編譯器可能不支持變長(zhǎng)數(shù)組,或者可能有特定的限制和行為。
方式2:
如果你的編譯器版本不支持變長(zhǎng)數(shù)組,還可以考慮使用動(dòng)態(tài)內(nèi)存分配(使用malloc()函數(shù) )來(lái)創(chuàng)建動(dòng)態(tài)大小的數(shù)組。
分配:
int length = 5;
int *arr = (int *)malloc(length * sizeof(int));
釋放:
free(arr);
4、一維數(shù)組的應(yīng)用
4.1 數(shù)值型數(shù)組特征值統(tǒng)計(jì)
這里的特征值涉及到:平均值、最大值、最小值、總和等
舉例1:定義一個(gè)int型的一維數(shù)組,包含10個(gè)元素,然后求出數(shù)組中的最大值,最小值,總和,平均值,并輸出出來(lái)。
int main() {
int arr[10] = {34, 54, 2, 32, 54, 57, 3, 32, 87, 43};
int max = arr[0];//用于記錄數(shù)組的最大值
int arrLen = sizeof(arr) / sizeof(int);//獲取數(shù)組中元素的個(gè)數(shù)
for (int i = 1; i < arrLen; i++) {
if (max < arr[i]) {
max = arr[i];
}
}
printf("最大值為:%d\n", max);
//獲取數(shù)組的最小值
int min = arr[0];
for (int i = 1; i < arrLen; i++) {
if (min > arr[i]) {
min = arr[i];
}
}
printf("最小值為:%d\n", min);
//獲取數(shù)組的總和
int sum = 0;
for (int i = 0; i < arrLen; i++) {
sum += arr[i];
}
printf("總和為:%d\n", sum);
//獲取數(shù)組的平均值
int avg = sum / arrLen;
printf("平均值為:%d\n", avg);
return 0;
}
舉例2:評(píng)委打分
分析以下需求,并用代碼實(shí)現(xiàn):
(1)在編程競(jìng)賽中,有10位評(píng)委為參賽的選手打分,分?jǐn)?shù)分別為:5,4,6,8,9,0,1,2,7,3
(2)求選手的最后得分(去掉一個(gè)最高分和一個(gè)最低分后其余8位評(píng)委打分的平均值)
int main() {
int scores[10] = {5,4,6,8,9,0,1,2,7,3};
int max = scores[0]; //記錄最高分
int min = scores[0]; //記錄最低分
int sum = 0; //記錄總分
int arrLen = sizeof(scores) / sizeof(int); //記錄數(shù)組長(zhǎng)度
for(int i = 0;i < arrLen;i++){
if(max < scores[i]){
max = scores[i];
}
if(min > scores[i]){
min = scores[i];
}
sum += scores[i];
}
//計(jì)算平均分
double avg = (double)(sum - max - min) / (arrLen - 2);
printf("選手去掉最高分和最低分之后的平均分為:%.2lf\n" , avg);
return 0;
}
4.2 數(shù)組的復(fù)制
由于數(shù)組名是指針,所以復(fù)制數(shù)組不能簡(jiǎn)單地復(fù)制數(shù)組名。
int a[3] = {10,20,30};
int* b;
b = a;
上面的寫法,結(jié)果不是將數(shù)組 a 復(fù)制給數(shù)組 b ,而是讓 a 和 b 指向同一個(gè)數(shù)組。
正確方式1:使用循環(huán)
這是復(fù)制數(shù)組最簡(jiǎn)單的方法,將數(shù)組元素逐個(gè)進(jìn)行復(fù)制。比如,將數(shù)組 a 的成員逐個(gè)復(fù)制給數(shù)組 b。
#include <stdio.h>
#define LENGTH 3
int main() {
int a[LENGTH] = {10, 20, 30};
int b[LENGTH];
// 復(fù)制數(shù)組 a 到數(shù)組 b
for (int i = 0; i < LENGTH; i++) {
b[i] = a[i];
}
// 打印數(shù)組 b 的內(nèi)容
printf("復(fù)制后的數(shù)組 b:");
for (int i = 0; i < LENGTH; i++) {
printf("%d ", b[i]);
}
printf("\n");
return 0;
}
正確方式2:使用 memcpy() 函數(shù)
memcpy() 函數(shù)定義在頭文件 string.h 中,直接把數(shù)組所在的那一段內(nèi)存,再?gòu)?fù)制一份。3個(gè)參數(shù)依次為:目標(biāo)數(shù)組、源數(shù)組以及要復(fù)制的字節(jié)數(shù)。
#include <stdio.h>
#include <string.h>
#define LENGTH 3
int main() {
int a[LENGTH] = {10, 20, 30};
int b[LENGTH];
// 使用 memcpy 函數(shù)復(fù)制數(shù)組 a 到數(shù)組 b
memcpy(b, a, LENGTH * sizeof(int));
// 打印數(shù)組 b 的內(nèi)容
printf("復(fù)制后的數(shù)組 b:");
for (int i = 0; i < LENGTH; i++) {
printf("%d ", b[i]);
}
printf("\n");
return 0;
}
兩種方式對(duì)比:
下面是對(duì)兩種方式進(jìn)行比較的一些要點(diǎn):
- 循環(huán)復(fù)制:
- 優(yōu)點(diǎn):
簡(jiǎn)單直觀,容易理解和實(shí)現(xiàn)。不需要引入額外的頭文件。 - 缺點(diǎn):需要編寫循環(huán)代碼來(lái)遍歷數(shù)組并逐個(gè)賦值,相對(duì)而言可能
稍顯繁瑣。不適用于復(fù)制大型數(shù)組或復(fù)雜數(shù)據(jù)結(jié)構(gòu)。
- 優(yōu)點(diǎn):
- memcpy函數(shù)復(fù)制:
- 優(yōu)點(diǎn):使用標(biāo)準(zhǔn)庫(kù)提供的函數(shù),可以實(shí)現(xiàn)
快速且高效的內(nèi)存復(fù)制。適用于大型數(shù)組或復(fù)雜數(shù)據(jù)結(jié)構(gòu)的復(fù)制。可以直接復(fù)制字節(jié)數(shù),不需要遍歷數(shù)組。 - 缺點(diǎn):需要包含
<string.h>頭文件。對(duì)于簡(jiǎn)單的數(shù)組復(fù)制,可能有些過(guò)于繁重。
- 優(yōu)點(diǎn):使用標(biāo)準(zhǔn)庫(kù)提供的函數(shù),可以實(shí)現(xiàn)
4.3 數(shù)組元素的反轉(zhuǎn)
實(shí)現(xiàn)思想:數(shù)組對(duì)稱位置的元素互換。
方式1:

代碼實(shí)現(xiàn)
int main() {
int arr[] = {1,2,3,4,5,6,7,8,9};
int size = sizeof(arr) / sizeof(arr[0]); //數(shù)組的長(zhǎng)度
printf("原始數(shù)組:");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
for(int i = 0;i < size / 2;i++){
int temp = arr[i];
arr[i] = arr[size - 1 - i];
arr[size - 1 - i] = temp;
}
printf("反轉(zhuǎn)后的數(shù)組:");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
方式2:

int main() {
int arr[] = {1, 2, 3, 4, 5,6,7,8,9};
int size = sizeof(arr) / sizeof(arr[0]); //數(shù)組的長(zhǎng)度
printf("原始數(shù)組:");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
int left = 0; // 起始指針
int right = size - 1; // 結(jié)尾指針
while (left < right) {
// 交換起始指針和結(jié)尾指針指向的元素
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
// 更新指針位置
left++;
right--;
}
printf("反轉(zhuǎn)后的數(shù)組:");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
4.4 char型數(shù)組與字符串
4.4.1 char型數(shù)組
字符型數(shù)組,顧名思義,數(shù)組元素的數(shù)據(jù)類型為字符型的數(shù)組。
一方面,可以看做普通的數(shù)組,初始化、常用操作如前所述。比如:
char arr[] = {'a','b','c','d'};
另一方面,字符型數(shù)組可以用于存儲(chǔ)字符串。
4.4.2 字符串的使用
"helloworld"
"abc"
"a"
"123"
這種由雙引號(hào)引起來(lái)的一串字符稱為字符串字面值(String Literal),簡(jiǎn)稱字符串(String)。
通常把""稱為空串,即一個(gè)不包含任意字符的字符串;而" "則稱為空格串,是包含一個(gè)空格字符的字符串。二者不能等同。
C語(yǔ)言沒有專門用于存儲(chǔ)字符串的變量類型,字符串都被存儲(chǔ)在char類型的數(shù)組中。在字符串結(jié)尾,C 語(yǔ)言會(huì)自動(dòng)添加一個(gè)'\0' 的轉(zhuǎn)義字符作為字符串結(jié)束的標(biāo)志,所以字符數(shù)組也必須以 '\0'字符結(jié)束。
聲明方式1:標(biāo)準(zhǔn)寫法
//顯式以'\0'為最后一個(gè)字符元素結(jié)束
char str[] = {'h','e','l','l','o',' ','w','o','r','l','d','\0'};
如果一個(gè)字符數(shù)組聲明如下,由于必須留一個(gè)位置給 \0 ,所以最多只能容納9個(gè)字符的字符串。
char str1[10];
聲明方式2:簡(jiǎn)化寫法
字符串寫成數(shù)組的形式,是非常麻煩的,C 語(yǔ)言提供了一種簡(jiǎn)化寫法。雙引號(hào)之中的字符,會(huì)被自動(dòng)視為字符數(shù)組。
//自動(dòng)在末尾添加'\0'字符
char str1[12] = {"hello world"}; //注意使用雙引號(hào),非單引號(hào)
//或者
char str2[12] = "hello world"; //可以省略一對(duì){}來(lái)初始化數(shù)組元素
由于字符數(shù)組的長(zhǎng)度可以讓編譯器自動(dòng)計(jì)算,所以聲明時(shí)可以省略字符數(shù)組的長(zhǎng)度:
char str1[] = {"hello world"};
//或者
char str2[] = "hello world";
雙引號(hào)里面的字符串,不用自己添加結(jié)尾字符 \0 ,C 語(yǔ)言會(huì)自動(dòng)添加。所以,代碼中數(shù)組 str1或str2的元素依次為 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0'。
字符串對(duì)應(yīng)數(shù)組的長(zhǎng)度
對(duì)應(yīng)的存儲(chǔ)為:

其中,數(shù)組由連續(xù)的存儲(chǔ)單元組成,字符串中的字符被存儲(chǔ)在相鄰的存儲(chǔ)單元中,每個(gè)單元存儲(chǔ)一個(gè)字符。所以,上述兩個(gè)數(shù)組的長(zhǎng)度不是11,而是12。
字符串的長(zhǎng)度
char nation[10]={"China"};
數(shù)組nation的前5個(gè)元素為: ′C′,′h′,′i′,′n′,′a′,第6個(gè)元素為′\0′,后4個(gè)元素也自動(dòng)設(shè)定為空字符。

注意:在計(jì)算字符串長(zhǎng)度的時(shí)候,'\0' 是結(jié)束標(biāo)志,不算作字符串內(nèi)容。
#include <stdio.h>
#include <string.h> //需要加載此頭文件
int main() {
char nation[10] = "China";
printf("%d\n", strlen(nation)); //5
}
區(qū)分:'\0'、0、'0'
字符 '\0' 不同于字符 '0' ,前者的ASCII 碼是0(二進(jìn)制形式 00000000 ),后者的 ASCII 碼是48(二進(jìn)制形式 00110000 )。
練習(xí)1:字符數(shù)組、字符串的長(zhǎng)度
char s1[50] = "hello"; //聲明1
char s2[] = "hello"; //聲明2
char s3[5] = "hello"; //聲明3
對(duì)于聲明1:賦給的元素的個(gè)數(shù)小于該數(shù)組的長(zhǎng)度,則會(huì)自動(dòng)在后面加 '\0', 表示字符串結(jié)束。所以,字符數(shù)組 s1 的長(zhǎng)度是 50 ,但是字符串“hello”的實(shí)際長(zhǎng)度只有5(不包含結(jié)尾符號(hào) '\0' ),所以后面空出來(lái)的45個(gè)位置,都會(huì)被初始化為 '\0'。
對(duì)于聲明2:字符數(shù)組 s2 的長(zhǎng)度是 6(包含結(jié)尾符號(hào) '\0' ),但是字符串“hello”的實(shí)際長(zhǎng)度只有5。
對(duì)于聲明3:賦給的元素的個(gè)數(shù)等于該數(shù)組的長(zhǎng)度,則不會(huì)自動(dòng)添加 '\0'。但字符串要求以'\0'結(jié)束,所以這種寫法是錯(cuò)誤的,要避免。
練習(xí)2:比較"x"和'x'的不同
-
書寫形式不同:字符串常量用雙引號(hào),字符常量用單引號(hào)。
-
存儲(chǔ)空間不同:在內(nèi)存中,字符常量只占用一個(gè)字節(jié)的存儲(chǔ)空間,而字符串存儲(chǔ)時(shí)自動(dòng)加一個(gè)結(jié)束標(biāo)記'\0',所以'x'占用1個(gè)字節(jié),而"x"占用2個(gè)字節(jié)。

- 二者的操作也不相同。例如,可對(duì)字符常量進(jìn)行加減運(yùn)算,字符串常量則不能。
練習(xí)3:輸出字符數(shù)組
#include <stdio.h>
int main() {
char str1[]={"China\nBeijing"};
char str2[] = "helloworld";
puts(str1);
puts(str2);
return 0;
}
【中央財(cái)經(jīng)大學(xué)2018研】若有定義和語(yǔ)句:char s[10]; s="abcd"; printf("%s\n",s);,則結(jié)果是( )。
A.輸出abcd@#$
B.輸出a
C.輸出abcd
D.編譯不通過(guò)【答案】D
【解析】在定義一維字符數(shù)組時(shí),s為數(shù)組名,指向數(shù)組首元素的地址,為地址常量,不可更改,因此語(yǔ)句s="abcd"是非法的,編譯不會(huì)通過(guò)。
5、多維數(shù)組
5.1 理解
二維數(shù)組、三維數(shù)組、...都稱為多維數(shù)組。本節(jié)主要講解二維數(shù)組,三維及以上的數(shù)組,以此類推即可。
舉例:公司有3個(gè)攻堅(jiān)小分隊(duì),每隊(duì)有6名同事,要把這些同事的工資用數(shù)組保存起來(lái)以備查看。

此時(shí)建立數(shù)組salary用于存儲(chǔ)工資,它應(yīng)當(dāng)是二維的。第一維用來(lái)表示第幾分隊(duì),第二維用來(lái)表示第幾個(gè)同事。例如用salary2,3表示角標(biāo)2對(duì)應(yīng)分隊(duì)的角標(biāo)3對(duì)應(yīng)隊(duì)員的工資。
對(duì)于二維數(shù)組的理解,可以看作是由一維數(shù)組嵌套而成的。即一維數(shù)組array1又作為另一個(gè)一維數(shù)組array2的元素而存在。
5.2 二維數(shù)組的定義方式1
定義方式1:
int a[3][4]; //二維數(shù)組
二維數(shù)組a可看成由三個(gè)一維數(shù)組構(gòu)成,它們的數(shù)組名分別為 a[0]、a[1]、a[2]。這三個(gè)一維數(shù)組各有 4 個(gè)元素,如,一維數(shù)組 a[0] 的元素為 a[0][0]、a[0][1]、a[0][2]、a[0][3]。二維數(shù)組a共有12個(gè)成員(3 x 4 = 12)。

也可以簡(jiǎn)化理解為:

二維數(shù)組,常稱為矩陣(matrix)。把二維數(shù)組寫成行(row)和列(column)的排列形式,可以形象化地理解二維數(shù)組的邏輯結(jié)構(gòu)。
三維數(shù)組如下:
int arr1[3][4][5]; //三維數(shù)組
技巧:C 語(yǔ)言允許聲明多維數(shù)組,有多少個(gè)維度,就用多少個(gè)方括號(hào),比如二維數(shù)組就使用兩個(gè)方括號(hào)。
錯(cuò)誤方式:
float a[3,4]; //在一對(duì)方括號(hào)內(nèi)不能寫兩個(gè)下標(biāo)
5.3 二維數(shù)組的內(nèi)存分析
用矩陣形式(如3行4列形式)表示二維數(shù)組,是邏輯上的概念,能形象地表示出行列關(guān)系。而在內(nèi)存中,各元素是連續(xù)存放的,不是二維的,是線性的。
C語(yǔ)言中,二維數(shù)組中元素排列的順序是按行存放的。即:先順序存放第一行的元素,再存放第二行的元素。(最右邊的下標(biāo)變化最快,第一維的下標(biāo)變化最慢)。

舉例,整型數(shù)組b[3][3]在內(nèi)存中的存放:

舉例:關(guān)于長(zhǎng)度
int b[3][3];
printf("%d\n",sizeof(b)); //36
printf("%d\n",sizeof(b)/sizeof(int)); //9
5.4 成員的調(diào)用
格式:數(shù)組名[下標(biāo)] [下標(biāo)]
跟一維數(shù)組一樣,多維數(shù)組每個(gè)維度的第一個(gè)成員也是從 0 開始編號(hào)。
舉例1:給指定索引位置的元素賦值
int arr1[3][5];
//給指定索引位置的元素賦值
arr1[0][0] = 12;
arr1[3][4] = 5;
舉例2:查看數(shù)組元素的地址
int main() {
int arr2[3][4];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
printf("&arr2[%d][%d] = %p\n", i, j, &arr2[i][j]);
}
}
return 0;
}
輸出結(jié)果如下:

5.5 二維數(shù)組其它定義方式
定義方式2:聲明與初始化同時(shí)進(jìn)行
多維數(shù)組也可以使用大括號(hào),在聲明的同時(shí),一次性對(duì)所有成員賦值。
int a[3][4] = {{1,2,3,4},
{5,6,7,8},
{9,10,11,12}};
上例中, a 是一個(gè)二維數(shù)組,這種賦值寫法相當(dāng)于將第一維的每個(gè)成員寫成一個(gè)數(shù)組。

說(shuō)明:這里的地址以十進(jìn)制數(shù)值進(jìn)行的說(shuō)明。
int main() {
int a[3][4] = {{1,2,3,4},
{5,6,7,8},
{9,10,11,12}};
printf("%p\n",a[0]); //0000006ac71ffd30
printf("%p\n",a[0] + 1); //0000006ac71ffd34
printf("%p\n",a[0] + 2); //0000006ac71ffd38
printf("%p\n",a[0] + 3); //0000006ac71ffd3c
printf("%p\n",a[0] + 4); //0000006ac71ffd40
printf("%p\n",a + 1); //0000006ac71ffd40
printf("%p\n",a[1]); //0000006ac71ffd40
printf("%p\n",a[1] + 1); //0000006ac71ffd44
return 0;
}
定義方式3:部分元素賦值
多維數(shù)組也可以僅為指定的位置進(jìn)行初始化賦值,未賦值的成員會(huì)自動(dòng)設(shè)置為“零”值 。
//指定了 [0][0] 和 [1][1] 位置的值,其他位置就自動(dòng)設(shè)為 0 。
int a[2][2] = {[0][0] = 1, [1][1] = 2};
定義方式4:使用單層大括號(hào)賦值
多維數(shù)組也可以使用單層大括號(hào)賦值。不管數(shù)組有多少維度,在內(nèi)存里面都是線性存儲(chǔ)。對(duì)于a[2][2]來(lái)說(shuō), a[0][0] 的后面是 a[0][1] ,再后面是a[1][0] ,以此類推。
int a[2][2] = {1, 0, 0, 2}; //會(huì)自動(dòng)匹配到各行各列
定義方式5:方式4的簡(jiǎn)化
在方式4的基礎(chǔ)上,如果對(duì)全部元素賦值,那么第一維的長(zhǎng)度可以不給出。
//int a[2][3] = {1, 2, 3, 4, 5, 6};
//可以寫為:
int a[][3] = {1, 2, 3, 4, 5, 6};
//也可以寫為:
int a[][3] = {{1, 2, 3},{4, 5, 6}}; //行數(shù)自然判定為2
練習(xí):下面哪些賦值操作是正確的?(都對(duì))
int arr1[3][2]={{1,2},{3,4},{5,6}}; //對(duì)應(yīng)定義方式2
int arr2[3][2]={1,2,3,4,5,6}; //對(duì)應(yīng)定義方式4
int arr3[][2]={1,2,3,4,5,6}; //對(duì)應(yīng)定義方式5
int arr4[][2]={{1,2},{3,4},{5,6}}; //對(duì)應(yīng)定義方式5
int arr5[][2]={1,2,3,4,5}; //對(duì)應(yīng)定義方式5。未顯式賦值的位置默認(rèn)賦值為0
錯(cuò)誤方式:在定義二維數(shù)組時(shí),必須指定列數(shù)(即一行中包含幾個(gè)元素)
int array[][]; //錯(cuò)誤,必須指定列數(shù)
int array[3][]; //錯(cuò)誤,必須指定列數(shù)
【武漢科技大學(xué)2019研】以下能對(duì)數(shù)組value進(jìn)行正確初始化的語(yǔ)句是( )。
A.int value[2][]={{1,1},{2,2}};
B.int value[][3]={{1,,3},{4,5,6}};
C.int value[2][3]={1,2,3,4,5,6};
D.int value[][3]={{1},{4,6,}};【答案】C
【解析】二維數(shù)組的定義必須指定列數(shù),可以不用指定行數(shù),A錯(cuò)誤;數(shù)組value為int型數(shù)組,不能給數(shù)組里面的元素賦空值,BD錯(cuò)誤,答案選C。
5.6 舉例
舉例1:獲取arr數(shù)組中所有元素的和
提示:使用for的嵌套循環(huán)即可。

#include <stdio.h>
#define ROWS 3
#define COLS 4
int main() {
int arr[ROWS][COLS] = {{3, 5, 8},
{12, 9},
{7, 0, 6, 4}};
int sum = 0;//記錄總和
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
sum += arr[i][j];
}
}
printf("總和為%d\n", sum);
return 0;
}
舉例2:求二維數(shù)組最大值以及對(duì)應(yīng)的行列角標(biāo)
#include <stdio.h>
#define ROWS 3
#define COLS 4
int main() {
int a[ROWS][COLS] = {{1, 2, 3, 4},
{9, 8, 7, 6},
{-10, 10, -5, 2}};
int maxValue = a[0][0];
int maxRow = 0;
int maxCol = 0;
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
if (maxValue < a[i][j]) {
maxValue = a[i][j];
maxRow = i;
maxCol = j;
}
}
}
printf("最大值: %d\n", maxValue);
printf("對(duì)應(yīng)的行索引: %d\n", maxRow);
printf("對(duì)應(yīng)的列索引: %d\n", maxCol);
return 0;
}
舉例3:將一個(gè)二維數(shù)組行和列的元素互換,存到另一個(gè)二維數(shù)組中。

a[i][j] ---> b[j][i]
#include <stdio.h>
#define ROWS 2
#define COLS 3
int main() {
int a[ROWS][COLS] = {{1, 2, 3},
{4, 5, 6}};
int b[COLS][ROWS];
printf("數(shù)組 a:\n");
for (int i = 0; i < ROWS; i++) { //處理a數(shù)組中的一行中各元素
for (int j = 0; j < COLS; j++) { //處理a數(shù)組中某一列中各元素
printf("%5d", a[i][j]); //輸出a數(shù)組的一個(gè)元素
}
printf("\n");
}
for (int i = 0; i < ROWS; i++) { //處理a數(shù)組中的一行中各元素
for (int j = 0; j < COLS; j++) { //處理a數(shù)組中某一列中各元素
b[j][i] = a[i][j]; //將a數(shù)組元素的值賦給b數(shù)組相應(yīng)元素
}
}
printf("數(shù)組 b:\n"); //輸出b數(shù)組各元素
for (int i = 0; i < COLS; i++) { //處理b數(shù)組中一行中各元素
for (int j = 0; j < ROWS; j++) //處理b數(shù)組中一列中各元素
printf("%5d", b[i][j]); //輸出b數(shù)組的一個(gè)元素
printf("\n");
}
return 0;
}
運(yùn)行結(jié)果:

舉例4:二維char型數(shù)組
將"Apple"、"Orange"、"Grape"、"Pear"、"Peach"存儲(chǔ)在數(shù)組中。
char fruit[][7]={"Apple","Orange","Grape","Pear","Peach"};
對(duì)應(yīng)圖示:

舉例5:使用二維數(shù)組打印一個(gè) 10 行楊輝三角。
提示:
-
第一行有 1 個(gè)元素, 第 n 行有 n 個(gè)元素
-
每一行的第一個(gè)元素和最后一個(gè)元素都是 1
-
從第三行開始, 對(duì)于非第一個(gè)元素和最后一個(gè)元素的元素。即:
yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];

#include <stdio.h>
#define ROWS 10
int main() {
int yangHui[ROWS][ROWS];
for (int i = 0; i < ROWS; i++) {
//初始化第一列和對(duì)角線上的元素為1
yangHui[i][0] = 1;
yangHui[i][i] = 1;
//給其他位置元素賦值
for (int j = 1; j < i; j++) {
yangHui[i][j] = yangHui[i - 1][j - 1] + yangHui[i - 1][j];
}
}
// 打印楊輝三角
for (int i = 0; i < ROWS; i++) {
// 打印每行的元素
for (int j = 0; j <= i; j++) {
printf("%5d ", yangHui[i][j]);
}
printf("\n");
}
return 0;
}
【華南理工大學(xué)2018研】以下數(shù)組定義中不正確的是( )。
A.int a[2][3];
B.int b[][3]={0};
C.int c[100][100]={0};
D.int d[3][]={{1}, {1, 2, 3},{1}};【答案】D
【解析】定義二維數(shù)組時(shí)一定要指定數(shù)組的列數(shù),可以不指定數(shù)組的行數(shù),D錯(cuò)誤。

浙公網(wǎng)安備 33010602011771號(hào)