四、陣列

鹿之鱼發表於2024-03-10

第04章_陣列


本章專題脈絡

image

1、陣列的概述

1.1 為什麼需要陣列

需求分析1:

需要統計某公司50個員工的工資情況,例如計算平均工資、找到最高工資等。用之前知識,首先需要宣告50個變數來分別記錄每位員工的工資,這樣會很麻煩。因此我們可以將所有的資料全部儲存到一個容器中統一管理,並使用容器進行計算。

需求分析2:

容器的概念:

  • 生活中的容器:水杯(裝水等液體),衣櫃(裝衣服等物品),集裝箱(裝貨物等)。
  • 程式中的容器:將多個資料儲存到一起,每個資料稱為該容器的元素。

1.2 陣列的概念

  • 陣列(Array),是多個相同型別資料按一定順序排列的集合,並使用一個名字命名,並透過編號的方式對這些資料進行統一管理。

  • 陣列中的概念

    • 陣列名
    • 下標(或索引、index)
    • 元素
    • 陣列的長度

image

陣列的特點:

  • 陣列中的元素在記憶體中是依次緊密排列的,有序的。
  • 建立陣列物件會在記憶體中開闢一整塊連續的空間。佔據的空間的大小,取決於陣列的長度和陣列中元素的型別。
  • 我們可以直接透過下標(或索引)的方式呼叫指定位置的元素,速度很快。
  • 陣列,一旦初始化完成,其長度就是確定的。陣列的長度一旦確定,就不能修改
  • 陣列名中引用的是這塊連續空間的首地址。

1.3 陣列的分類

按照陣列維度分:

  • 一維陣列:儲存一組資料
  • 二維陣列:儲存多組資料,相當於二維表,一行代表一組資料。每一行長度可以不同。
  • 三維陣列、四維陣列、....

image

按照元素的資料型別分:

  • int型別陣列
  • char型別陣列
  • double型別陣列
  • ....

2、一維陣列的定義

2.1 陣列的定義方式1

陣列透過變數名後加方括號表示,方括號裡面是陣列可以容納的成員數量(即長度)。

int arr[10];  //陣列 arr ,裡面包含10個成員,每個成員都是 int 型別
#define NUM 10
int arr1[NUM];

注意,宣告陣列時,必須給出陣列的大小。

image

2.2 陣列元素的呼叫

  • 格式:陣列名[下標]

  • 陣列的下標從0開始,用“int arr[10];”定義陣列,則最大下標值為9,不存在陣列元素arr[10]。

arr[0] = 13;       //對該位置陣列元素進行賦值
int score = arr[0]; //呼叫此位置的元素值

陣列角標越界:

假設陣列有n個元素,如果使用的陣列的下標小於0,或者大於n-1,就是陣列越界訪問了,超出了陣列合法空間的訪問。

C語言不做陣列下標越界的檢查,編譯器也不一定報錯,但是編譯器不報錯,並不意味著程式就是正確!

int scores[20];
scores[20] = 51;

說明:陣列 scores 只有20個成員,因此 scores[20] 這個位置是不存在的。但是,引用這個位置並不會報錯。賦值操作會導致緊跟在 scores 後面的那塊記憶體區域被賦值(這實際是其它變數的區域),因此不知不覺就更改了其它變數的值。這很容易引發錯誤,而且難以發現。

2.3 關於長度

陣列的位元組長度

sizeof 運算子會返回整個陣列的位元組長度。

int arr[10];
printf("陣列的位元組長度為:%zd\n",sizeof(arr)); //40

陣列的長度

在定義陣列時,需要指定陣列中元素的個數,方括號中的常量表示式用來表示元素的個數,即陣列長度。

由於陣列成員都是同一個型別,每個成員的位元組長度都是一樣的,所以陣列整體的位元組長度除以某個陣列元素的位元組長度,就可以得到陣列的成員數量。

//陣列中元素的個數:
int arrLen = sizeof(arr) / sizeof(arr[0]);
int a[10];
printf("陣列的位元組長度為:%zu\n", sizeof(a));   // 40
printf("陣列每個元素的位元組長度為:%zu\n", sizeof(int)); // 4
printf("陣列的長度為:%zu\n", sizeof(a) / sizeof(int)); // 10

複習: sizeof 返回值的資料型別是 size_t ,所以 sizeof(a) / sizeof(a[0]) 的資料型別也是size_t 。在 printf() 裡面的佔位符,要用 %zd 或 %zu 。

注意:陣列一旦宣告/定義了,其長度就固定了,不能動態變化

2.4 陣列的遍歷

將陣列中的每個元素分別獲取出來,就是遍歷。for迴圈與陣列的遍歷是絕配。

舉例1:宣告長度為10的int型別陣列,給陣列元素依次賦值為0,1,2,3,4,5,6,7,8,9,並遍歷陣列所有元素

int main() {

    int arr[10];
    
    //給陣列中的每個元素賦值
    for (int i = 0; i < sizeof(arr)/sizeof(int); i++) { //對陣列元素arr[0]~arr[9]賦值
        arr[i] = i;
    }
    //遍歷陣列中的元素
    printf("遍歷陣列中的元素:\n");
    for (int i = 0; i < sizeof(arr)/sizeof(int); i++) { //輸出arr[0]~arr[9]共10個陣列元素
        printf("%d ", arr[i]);
    }
    printf("\n");
    return 0;
}

2.5 陣列的其它定義方式

定義方式2:(定義方式1在2.1節講的)

陣列可以在宣告時,使用大括號,同時對每一個成員賦值。

int arr[5] = {22, 37, 90, 48, 95};

變形形式1:C 語言允許省略方括號裡面的陣列成員數量,這時根據大括號裡面的值的數量,自動確定陣列的長度。

int arr[3] = {10,20,30};
// 等同於
int arr[] = {10,20,30};  //陣列 arr 的長度,將根據大括號裡面的值的數量,確定為 3

變形形式2:

對陣列部分元素賦初值:如果大括號裡面的值,少於陣列的成員數量,那麼未賦值的成員自動初始化為 0 。

int arr[5] = {10, 20, 30};
// 等同於
int arr[5] = {10,20,30, 0, 0};

變形方式3

將整個陣列的每一個成員都設定為零,最簡單的方式如下

int a[100] = {0};

錯誤方式:

使用大括號賦值時,大括號裡面的值不能多於陣列的長度,否則編譯時會報錯。

int arr[3] = {1,2,3,4};  // 報錯

定義方式3:陣列初始化時,可以指定為哪些位置的成員賦值。

int arr[15] = {[2] = 10, [5] = 20, [14] = 30};  //非角標2、5、14的位置自動賦值為0

//等同於
int arr[15] = {[5] = 20, [14] = 30, [2] = 10}; //指定位置的賦值可以不按角標從小到大的順序

變形形式1:指定位置的賦值與順序賦值,可以結合使用。

int arr[15] = {1, [5] = 10, 11, [10] = 20, 21}; //角標0、5、6、10、11的位置被賦值

變形形式2:省略成員數量時,如果同時採用指定位置的賦值,那麼陣列長度將是最大的指定位置再加1。

int arr[] = {[2] = 6, [9] = 12};  //此時陣列的長度是10

3、一維陣列記憶體分析

3.1 陣列記憶體圖

針對於如下程式碼:

int a[5] = {1,2,3,4,5};

對應的記憶體結構:

image

說明:

1)陣列名,記錄該陣列的首地址 ,即 a[0]的地址。

2)陣列的各個元素是連續分佈的, 假如 a[0] 地址是0x1122,則a[1]地址= a[0]的地址+int位元組數(4) = 0x1122 + 4 = 0x1126,後面 a[2] 地址 = a[1]地址 + int 位元組數(4) = 0x1126 + 4 = 0x112A,依次類推...

3.2 注意事項

C 語言規定,陣列變數一旦宣告,陣列名指向的地址就不可更改。因為宣告陣列時,編譯器會自動為陣列分配記憶體地址,這個地址與陣列名是繫結的,不可更改。

因此,當陣列定義後,再用大括號重新賦值,是不允許的。下面的程式碼會報錯。

錯誤舉例1:

int nums[5];
nums = {22, 37, 3490, 18, 95}; // 使用大括號賦值時,必須在陣列宣告時賦值,否則編譯時會報錯。

錯誤舉例2:

int nums[5] = {1, 2, 3, 4, 5};
nums = {6, 7, 8, 9, 10}; // 報錯

錯誤舉例3:

int ints[100];
ints = NULL; //報錯

這也導致不能將一個陣列名賦值給另外一個陣列名。

int a[5] = {1, 2, 3, 4, 5};
// 寫法一
int b[5] = a; // 報錯
// 寫法二
int b[5];
b = a; // 報錯

上面兩種寫法都會更改陣列 b 的地址,導致報錯。

3.3 變長陣列

陣列宣告的時候,陣列長度除了使用常量,也可以使用變數或表示式來指定陣列的大小。這叫做變長陣列(variable-length array,簡稱 VLA)。

方式1:

int n = 10;
int arr[n];

變長陣列的根本特徵是陣列長度只有執行時才能確定。它的好處是程式設計師不必在開發時,隨意為陣列指定一個估計的長度,程式可以在執行時為陣列分配精確的長度。

任何長度需要執行時才能確定的陣列,都是變長陣列。比如,

int i = 10;
int a1[i];
int a2[i + 5];
int a3[i + k];

注意:變長陣列在C99標準中被引入,在C11標準中被標記為可選特性。某些編譯器可能不支援變長陣列,或者可能有特定的限制和行為。

方式2:

如果你的編譯器版本不支援變長陣列,還可以考慮使用動態記憶體分配(使用malloc()函式 )來建立動態大小的陣列。

分配:

int length = 5;
int *arr = (int *)malloc(length * sizeof(int));

釋放:

free(arr);

4、一維陣列的應用

4.1 數值型陣列特徵值統計

這裡的特徵值涉及到:平均值、最大值、最小值、總和等

舉例1:定義一個int型的一維陣列,包含10個元素,然後求出陣列中的最大值,最小值,總和,平均值,並輸出出來。

int main() {
    int arr[10] = {34, 54, 2, 32, 54, 57, 3, 32, 87, 43};

    int max = arr[0];//用於記錄陣列的最大值
    int arrLen = sizeof(arr) / sizeof(int);//獲取陣列中元素的個數
    for (int i = 1; i < arrLen; i++) {
        if (max < arr[i]) {
            max = arr[i];
        }
    }
    printf("最大值為:%d\n", max);

    //獲取陣列的最小值
    int min = arr[0];
    for (int i = 1; i < arrLen; i++) {
        if (min > arr[i]) {
            min = arr[i];
        }
    }
    printf("最小值為:%d\n", min);

    //獲取陣列的總和
    int sum = 0;
    for (int i = 0; i < arrLen; i++) {
        sum += arr[i];
    }
    printf("總和為:%d\n", sum);

    //獲取陣列的平均值
    int avg = sum / arrLen;
    printf("平均值為:%d\n", avg);


    return 0;
}

舉例2:評委打分

分析以下需求,並用程式碼實現:

(1)在程式設計競賽中,有10位評委為參賽的選手打分,分數分別為:5,4,6,8,9,0,1,2,7,3

(2)求選手的最後得分(去掉一個最高分和一個最低分後其餘8位評委打分的平均值)

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); //記錄陣列長度
    for(int i = 0;i < arrLen;i++){
        if(max < scores[i]){
            max = scores[i];
        }

        if(min > scores[i]){
            min = scores[i];
        }

        sum += scores[i];
    }
    //計算平均分
    double avg = (double)(sum - max - min) / (arrLen - 2);

    printf("選手去掉最高分和最低分之後的平均分為:%.2lf\n" , avg);

    return 0;
}

4.2 陣列的複製

由於陣列名是指標,所以複製陣列不能簡單地複製陣列名。

int a[3] = {10,20,30};
int* b;
b = a;

上面的寫法,結果不是將陣列 a 複製給陣列 b ,而是讓 a 和 b 指向同一個陣列。

正確方式1:使用迴圈

這是複製陣列最簡單的方法,將陣列元素逐個進行復制。比如,將陣列 a 的成員逐個複製給陣列 b。

#include <stdio.h>

#define LENGTH 3

int main() {
    int a[LENGTH] = {10, 20, 30};
    int b[LENGTH];

    // 複製陣列 a 到陣列 b
    for (int i = 0; i < LENGTH; i++) {
        b[i] = a[i];
    }

    // 列印陣列 b 的內容
    printf("複製後的陣列 b:");
    for (int i = 0; i < LENGTH; i++) {
        printf("%d ", b[i]);
    }
    printf("\n");

    return 0;
}

正確方式2:使用 memcpy() 函式

memcpy() 函式定義在標頭檔案 string.h 中,直接把陣列所在的那一段記憶體,再複製一份。3個引數依次為:目標陣列源陣列以及要複製的位元組數

#include <stdio.h>
#include <string.h>

#define LENGTH 3

int main() {
    int a[LENGTH] = {10, 20, 30};
    int b[LENGTH];

    // 使用 memcpy 函式複製陣列 a 到陣列 b
    memcpy(b, a, LENGTH * sizeof(int));

    // 列印陣列 b 的內容
    printf("複製後的陣列 b:");
    for (int i = 0; i < LENGTH; i++) {
        printf("%d ", b[i]);
    }
    printf("\n");

    return 0;
}

兩種方式對比:

下面是對兩種方式進行比較的一些要點:

  1. 迴圈複製:
    • 優點:簡單直觀,容易理解和實現。不需要引入額外的標頭檔案。
    • 缺點:需要編寫迴圈程式碼來遍歷陣列並逐個賦值,相對而言可能稍顯繁瑣。不適用於複製大型陣列或複雜資料結構。
  2. memcpy函式複製:
    • 優點:使用標準庫提供的函式,可以實現快速且高效的記憶體複製。適用於大型陣列或複雜資料結構的複製。可以直接複製位元組數,不需要遍歷陣列。
    • 缺點:需要包含 <string.h> 標頭檔案。對於簡單的陣列複製,可能有些過於繁重

4.3 陣列元素的反轉

實現思想:陣列對稱位置的元素互換。

方式1:

image

程式碼實現

int main() {
    int arr[] = {1,2,3,4,5,6,7,8,9};
    int size = sizeof(arr) / sizeof(arr[0]); //陣列的長度

    printf("原始陣列:");
    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("反轉後的陣列:");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

方式2:

image

int main() {
    int arr[] = {1, 2, 3, 4, 5,6,7,8,9};
    int size = sizeof(arr) / sizeof(arr[0]); //陣列的長度

    printf("原始陣列:");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    int left = 0; // 起始指標
    int right = size - 1; // 結尾指標

    while (left < right) {
        // 交換起始指標和結尾指標指向的元素
        int temp = arr[left];
        arr[left] = arr[right];
        arr[right] = temp;

        // 更新指標位置
        left++;
        right--;
    }

    printf("反轉後的陣列:");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

4.4 char型陣列與字串

4.4.1 char型陣列

字元型陣列,顧名思義,陣列元素的資料型別為字元型的陣列。

一方面,可以看做普通的陣列,初始化、常用操作如前所述。比如:

char arr[] = {'a','b','c','d'};

另一方面,字元型陣列可以用於儲存字串。

4.4.2 字串的使用

"helloworld"
"abc"
"a"
"123"

這種由雙引號引起來的一串字元稱為字串字面值(String Literal),簡稱字串(String)。

通常把""稱為空串,即一個不包含任意字元的字串;而" "則稱為空格串,是包含一個空格字元的字串。二者不能等同。

C語言沒有專門用於儲存字串的變數型別,字串都被儲存在char型別的陣列中。在字串結尾,C 語言會自動新增一個'\0' 的跳脫字元作為字串結束的標誌,所以字元陣列也必須以 '\0'字元結束。

宣告方式1:標準寫法

//顯式以'\0'為最後一個字元元素結束
char str[] = {'h','e','l','l','o',' ','w','o','r','l','d','\0'};

如果一個字元陣列宣告如下,由於必須留一個位置給 \0 ,所以最多隻能容納9個字元的字串。

char str1[10];

宣告方式2:簡化寫法

字串寫成陣列的形式,是非常麻煩的,C 語言提供了一種簡化寫法。雙引號之中的字元,會被自動視為字元陣列。

//自動在末尾新增'\0'字元
char str1[12] = {"hello world"};  //注意使用雙引號,非單引號
//或者
char str2[12] = "hello world";   //可以省略一對{}來初始化陣列元素

由於字元陣列的長度可以讓編譯器自動計算,所以宣告時可以省略字元陣列的長度:

char str1[] = {"hello world"};
//或者
char str2[] = "hello world"; 

雙引號裡面的字串,不用自己新增結尾字元 \0 ,C 語言會自動新增。所以,程式碼中陣列 str1或str2的元素依次為 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0'。

字串對應陣列的長度

對應的儲存為:

image

其中,陣列由連續的儲存單元組成,字串中的字元被儲存在相鄰的儲存單元中,每個單元儲存一個字元。所以,上述兩個陣列的長度不是11,而是12。

字串的長度

char nation[10]={"China"};

陣列nation的前5個元素為: ′C′,′h′,′i′,′n′,′a′,第6個元素為′\0′,後4個元素也自動設定為空字元。

image

注意:在計算字串長度的時候,'\0' 是結束標誌,不算作字串內容。

#include <stdio.h>
#include <string.h>    //需要載入此標頭檔案

int main() {
    char nation[10] = "China";
    printf("%d\n", strlen(nation));     //5
}

區分:'\0'、0、'0'

字元 '\0' 不同於字元 '0' ,前者的ASCII 碼是0(二進位制形式 00000000 ),後者的 ASCII 碼是48(二進位制形式 00110000 )。

練習1:字元陣列、字串的長度

char s1[50] = "hello";  //宣告1

char s2[] = "hello";    //宣告2

char s3[5] = "hello";   //宣告3

對於宣告1:賦給的元素的個數小於該陣列的長度,則會自動在後面加 '\0', 表示字串結束。所以,字元陣列 s1 的長度是 50 ,但是字串“hello”的實際長度只有5(不包含結尾符號 '\0' ),所以後面空出來的45個位置,都會被初始化為 '\0'。

對於宣告2:字元陣列 s2 的長度是 6(包含結尾符號 '\0' ),但是字串“hello”的實際長度只有5。

對於宣告3:賦給的元素的個數等於該陣列的長度,則不會自動新增 '\0'。但字串要求以'\0'結束,所以這種寫法是錯誤的,要避免。

練習2:比較"x"和'x'的不同

  • 書寫形式不同:字串常量用雙引號,字元常量用單引號。

  • 儲存空間不同:在記憶體中,字元常量只佔用一個位元組的儲存空間,而字串儲存時自動加一個結束標記'\0',所以'x'佔用1個位元組,而"x"佔用2個位元組。

image

  • 二者的操作也不相同。例如,可對字元常量進行加減運算,字串常量則不能。

練習3:輸出字元陣列

#include <stdio.h>

int main() {

    char str1[]={"China\nBeijing"};
    char str2[] = "helloworld";

    puts(str1);

    puts(str2);

    return 0;
}

【中央財經大學2018研】若有定義和語句:char s[10]; s="abcd"; printf("%s\n",s);,則結果是( )。
A.輸出abcd@#$
B.輸出a
C.輸出abcd
D.編譯不透過

【答案】D

【解析】在定義一維字元陣列時,s為陣列名,指向陣列首元素的地址,為地址常量,不可更改,因此語句s="abcd"是非法的,編譯不會透過。

5、多維陣列

5.1 理解

二維陣列、三維陣列、...都稱為多維陣列。本節主要講解二維陣列,三維及以上的陣列,以此類推即可。

舉例:公司有3個攻堅小分隊,每隊有6名同事,要把這些同事的工資用陣列儲存起來以備檢視。

image

此時建立陣列salary用於儲存工資,它應當是二維的。第一維用來表示第幾分隊,第二維用來表示第幾個同事。例如用salary2,3表示角標2對應分隊的角標3對應隊員的工資。

對於二維陣列的理解,可以看作是由一維陣列巢狀而成的。即一維陣列array1又作為另一個一維陣列array2的元素而存在。

5.2 二維陣列的定義方式1

定義方式1:

int a[3][4]; //二維陣列

二維陣列a可看成由三個一維陣列構成,它們的陣列名分別為 a[0]、a[1]、a[2]。這三個一維陣列各有 4 個元素,如,一維陣列 a[0] 的元素為 a[0][0]a[0][1]a[0][2]a[0][3]。二維陣列a共有12個成員(3 x 4 = 12)。

image

也可以簡化理解為:

image

二維陣列,常稱為矩陣(matrix)。把二維陣列寫成行(row)列(column)的排列形式,可以形象化地理解二維陣列的邏輯結構。

三維陣列如下:

int arr1[3][4][5]; //三維陣列

技巧:C 語言允許宣告多維陣列,有多少個維度,就用多少個方括號,比如二維陣列就使用兩個方括號。

錯誤方式:

float a[3,4];  //在一對方括號內不能寫兩個下標

5.3 二維陣列的記憶體分析

矩陣形式(如3行4列形式)表示二維陣列,是邏輯上的概念,能形象地表示出行列關係。而在記憶體中,各元素是連續存放的,不是二維的,是線性的。

C語言中,二維陣列中元素排列的順序是按行存放的。即:先順序存放第一行的元素,再存放第二行的元素。(最右邊的下標變化最快,第一維的下標變化最慢)。

image

舉例,整型陣列b[3][3]在記憶體中的存放:

image

舉例:關於長度

int b[3][3];
printf("%d\n",sizeof(b)); //36
printf("%d\n",sizeof(b)/sizeof(int)); //9

5.4 成員的呼叫

格式:陣列名[下標] [下標]

跟一維陣列一樣,多維陣列每個維度的第一個成員也是從 0 開始編號。

舉例1:給指定索引位置的元素賦值

int arr1[3][5];
//給指定索引位置的元素賦值
arr1[0][0] = 12;
arr1[3][4] = 5;

舉例2:檢視陣列元素的地址

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;
}

輸出結果如下:

image

5.5 二維陣列其它定義方式

定義方式2:宣告與初始化同時進行

多維陣列也可以使用大括號,在宣告的同時,一次性對所有成員賦值。

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

上例中, a 是一個二維陣列,這種賦值寫法相當於將第一維的每個成員寫成一個陣列。

image

說明:這裡的地址以十進位制數值進行的說明。

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:部分元素賦值

多維陣列也可以僅為指定的位置進行初始化賦值,未賦值的成員會自動設定為“零”值 。

//指定了 [0][0] 和 [1][1] 位置的值,其他位置就自動設為 0 。
int a[2][2] = {[0][0] = 1, [1][1] = 2};  

定義方式4:使用單層大括號賦值

多維陣列也可以使用單層大括號賦值。不管陣列有多少維度,在記憶體裡面都是線性儲存。對於a[2][2]來說, a[0][0] 的後面是 a[0][1] ,再後面是a[1][0] ,以此類推。

int a[2][2] = {1, 0, 0, 2};  //會自動匹配到各行各列

定義方式5:方式4的簡化

在方式4的基礎上,如果對全部元素賦值,那麼第一維的長度可以不給出。

//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}}; //行數自然判定為2

練習:下面哪些賦值操作是正確的?(都對)

int arr1[3][2]={{1,2},{3,4},{5,6}};  //對應定義方式2

int arr2[3][2]={1,2,3,4,5,6};  //對應定義方式4

int arr3[][2]={1,2,3,4,5,6};  //對應定義方式5

int arr4[][2]={{1,2},{3,4},{5,6}}; //對應定義方式5

int arr5[][2]={1,2,3,4,5};  //對應定義方式5。未顯式賦值的位置預設賦值為0

錯誤方式:在定義二維陣列時,必須指定列數(即一行中包含幾個元素)

int array[][];  //錯誤,必須指定列數
int array[3][]; //錯誤,必須指定列數

【武漢科技大學2019研】以下能對陣列value進行正確初始化的語句是(  )。
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

【解析】二維陣列的定義必須指定列數,可以不用指定行數,A錯誤;陣列value為int型陣列,不能給陣列裡面的元素賦空值,BD錯誤,答案選C。

5.6 舉例

舉例1:獲取arr陣列中所有元素的和

提示:使用for的巢狀迴圈即可。

image

#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:求二維陣列最大值以及對應的行列角標

#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("對應的行索引: %d\n", maxRow);
    printf("對應的列索引: %d\n", maxCol);

    return 0;
}

舉例3:將一個二維陣列行和列的元素互換,存到另一個二維陣列中。

image

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("陣列 a:\n");
    for (int i = 0; i < ROWS; i++) { //處理a陣列中的一行中各元素
        for (int j = 0; j < COLS; j++) { //處理a陣列中某一列中各元素
            printf("%5d", a[i][j]); //輸出a陣列的一個元素
        }
        printf("\n");
    }

    for (int i = 0; i < ROWS; i++) { //處理a陣列中的一行中各元素
        for (int j = 0; j < COLS; j++) { //處理a陣列中某一列中各元素
            b[j][i] = a[i][j]; //將a陣列元素的值賦給b陣列相應元素
        }
    }

    printf("陣列 b:\n"); //輸出b陣列各元素
    for (int i = 0; i < COLS; i++) { //處理b陣列中一行中各元素
        for (int j = 0; j < ROWS; j++) //處理b陣列中一列中各元素
            printf("%5d", b[i][j]); //輸出b陣列的一個元素
        printf("\n");
    }
    return 0;
}

執行結果:

image

舉例4:二維char型陣列

將"Apple"、"Orange"、"Grape"、"Pear"、"Peach"儲存在陣列中。

char fruit[][7]={"Apple","Orange","Grape","Pear","Peach"};

對應圖示:

image

舉例5:使用二維陣列列印一個 10 行楊輝三角。

提示:

  1. 第一行有 1 個元素, 第 n 行有 n 個元素

  2. 每一行的第一個元素和最後一個元素都是 1

  3. 從第三行開始, 對於非第一個元素和最後一個元素的元素。即:

    yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];
    

image

#include <stdio.h>

#define ROWS 10

int main() {
    int yangHui[ROWS][ROWS];


    for (int i = 0; i < ROWS; i++) {
        //初始化第一列和對角線上的元素為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;
}

【華南理工大學2018研】以下陣列定義中不正確的是(  )。
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

【解析】定義二維陣列時一定要指定陣列的列數,可以不指定陣列的行數,D錯誤。

相關文章