C語言-陣列與字串

陣列

如果是需要使用到多個變數的場合,例如統計全班成績,宣告這麼多的變數儲存成績是不實際的

所以C語言提供陣列,方便你宣告一個以索引為識別的資料結構

一維陣列

陣列的宣告方式如下:

1
資料型態 變數名稱[陣列長度];

例如:

1
2
int score[10]; // 宣告10個元素的整數陣列
float weight[5]; // 宣告5個元素的浮點數陣列

陣列的長度必須事先決定,原因是因為編譯器在編譯過程中,陣列所需的空間必須是靜態的

如果長度不確定,編譯器就無法保留空間給陣列

下一個章節會提到如果陣列空間不確定時,如何宣告一個動態長度的陣列

而之前在資料型態與變數運算有提過,變數宣告後

變數的內容是不確定的,所以你可以這樣初始化陣列

1
2
int score[10] = {0}; // 這樣裡面10個元素都會初始化為0
float weight[5] = {0.0}; // 這樣裡面5個元素都會初始化為0.0

你也可以在宣告陣列的時候指定初始值

1
2
int score[10] = {1,2,3,4,5,6,7,8,9,10};
float weight[5] = {1.0,2.0,3.0,4.0,5.0};

當你需要存取某個元素的時候,只要

1
int first = score[0];

這樣就可以取得第一個元素的值了,這邊要注意的是

陣列的索引值是從0開始,從0到9總共10個元素

而為什麼索引值從0開始,是因為陣列名稱是指向陣列第一個元素的

索引值就是往後偏移量,因為開頭已經指向第一個元素,所以偏移量是零

陣列的每個元素可以直接當作變數使用,也可以直接做輸入輸出

下面是一個簡單的範例程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>

int main(void) {

int array[10] = {0};
int i;

for(i = 0; i < 10; i++) {
printf("請輸入第%d個元素:",i+1);
scanf("%d",&array[i]);
}

printf("你輸入了:");

for(i = 0; i < 10; i++) {
printf("%d ", array[i]);
}

puts("");

return 0;

}

執行結果

請輸入第1個元素:10
請輸入第2個元素:9
請輸入第3個元素:8
請輸入第4個元素:7
請輸入第5個元素:6
請輸入第6個元素:5
請輸入第7個元素:4
請輸入第8個元素:3
請輸入第9個元素:2
請輸入第10個元素:1
你輸入了:10 9 8 7 6 5 4 3 2 1

使用陣列時有以下幾點要注意

  1. 如果你在初始化的時候未定義陣列大小,編譯器將會幫你決定陣列大小

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <stdio.h>

    int main(void) {

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

    printf("陣列長度:%d\n", sizeof(array) / sizeof(array[0]));

    return 0;

    }

    執行結果

    陣列長度:5
    
  2. 不能存取超過陣列長度的元素,這會造成無法預期的錯誤

    小則取得無法預期的值,大則程式爆炸

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <stdio.h>

    int main(void) {

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

    printf("第八個元素:%d\n",array[7]);

    return 0;

    }

    執行結果

    第八個元素:0
    
  3. 陣列是不能直接指定的,必須一個元素一個元素指定

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include <stdio.h>

    int main(void) {

    int array1[] = {1,2,3,4,5};
    int array2[5] = {0};
    int i;

    for(i = 0; i < 5; i++)
    array2[i] = array1[i];

    for(i = 0; i < 5; i++)
    printf("%d ",array2[i]);

    puts("");

    return 0;

    }

    執行結果

    1 2 3 4 5
    
  4. 想要比較陣列是否相同,也必須一個元素一個元素比較

  5. 如果傳陣列到函數裡面,在函數裡面的改變會保留回到主函數,原因會在下一章說明

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    #include <stdio.h>

    void modify_array(int[],int);

    int main(void) {

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

    printf("改變前:");
    for(i = 0; i < 5; i++)
    printf("%d ",array[i]);
    printf("\n");

    modify_array(array,5);

    printf("改變後:");
    for(i = 0; i < 5; i++)
    printf("%d ",array[i]);
    printf("\n");

    return 0;

    }

    void modify_array(int array[],int length){

    int i;
    for(i = 0; i < length; i++)
    array[i] *= 2;

    }

    執行結果

    改變前:1 2 3 4 5
    改變後:2 4 6 8 10
    

二維陣列

如果你想統計全校成績,就需要使用二維陣列,宣告語法如下

1
變數型態 變數名稱[ROW][COLUMN];

例如:

1
int score[5][40]; // 5個班級,每班40個人

二維陣列在宣告的時候指定初始值如下:

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

以下是二維陣列的範例程式,宣告了5列9行的二維陣列,num[i-1][j-1]表示取出第i-1列j-1行的元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>

int main(void) {

int num[5][9] = {};
int i,j;

for(i = 1; i < 6; i++){
for(j = 1; j < 10; j++){
num[i-1][j-1] = i*j;
}
}

for(i = 1; i < 6; i++){
for(j = 1; j < 10; j++){
printf("%d\t",num[i-1][j-1]);
}
puts("");
}

return 0;

}

執行結果

1       2       3       4       5       6       7       8       9
2       4       6       8       10      12      14      16      18
3       6       9       12      15      18      21      24      27
4       8       12      16      20      24      28      32      36
5       10      15      20      25      30      35      40      45

二維陣列實際上是一維陣列的變形,以下二維陣列的宣告實際上跟一維陣列的宣告是一樣的

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

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

//以上兩個是一樣的

而行與列是我們為了理解陣列元素的存取想像而來的,在記憶體中,二維陣列仍然是線性配置的

兩個索引值代表的意義都是跟陣列開頭偏移的量,只是第一個偏移量是以一維陣列計算

例如num[1][0]表示往後偏移一個長度為3的一維陣列

而num[1][2]則代表往後偏移一個長度為3的一維陣列,再往後偏移2個元素

如果想傳二維陣列到函數,不像一維陣列這麼簡單,以下是範例程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>

void print_array(int[][3]);

int main(void) {

int num[2][3] = {{1,2,3},{4,5,6}};
print_array(num);

return 0;

}

// 第一個索引值是可以不用填的
// 但是第二個索引值就必須要填
// 編譯器至少要知道二維陣列有幾行
// 這樣偏移才能準確偏移 N 個單位的一維陣列
void print_array(int array[][3]){

int i,j;

for(i = 0; i < 2; i++){
for(j = 0; j < 3; j++){
printf("%d\t",array[i][j]);
}
printf("\n");
}

}

執行結果

1       2       3
4       5       6

字串

宣告與使用

在C語言裡面,字元陣列又稱為字串,由’\0’做結尾,宣告語法如下

1
char str[20]; // 宣告可以輸入20字以內的字串

你也可以像初始化陣列一樣初始化字串

1
char str[] = "Hello World!"

這邊要注意的是字串結尾’\0’也算是字元,所以上面這個字串的長度為13,而不是12

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>

int main(void) {

char str[] = "Hello World!";
int length = sizeof(str)/sizeof(str[0]);

int i;

printf("%s的長度為:%d\n",str,length);

for(i = 0; i < length; i++) {
if(str[i] == '\0')
puts("\\0");
else
printf("%c ", str[i]);
}
puts("");

return 0;
}

執行結果

Hello World!的長度為:13
H e l l o   W o r l d ! \0

也就是說,你宣告50個字元,實際上只有49個字元可以使用,如果超過上限會導致不可預期的爆炸XD

字串跟陣列一樣,除了初始化可以指定以外,其他時機是不能指定的,必須一個元素一個元素指定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>

int main(void) {

char str[15] = {'\0'};
str[0] = 'W';
str[1] = 'h';
str[2] = 'a';
str[3] = 't';
str[4] = '\0';
str[5] = ' ';
str[6] = 't';
str[7] = 'h';
str[8] = 'e';
str[9] = ' ';
str[10] = 'f';
str[11] = 'u';
str[12] = 'c';
str[13] = 'k';
str[14] = '\0';
puts(str);

return 0;

}

這邊要注意,上面只會顯示What,因為str[4]就會被認為是字串結尾,之後不管有什麼都不管

執行結果

What

字串其實就是一維陣列,所以傳參數到函數的方式跟陣列一樣,以下是示範程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <string.h>

void reverse(char str[]);

int main(void) {

char str[] = "Hello World!";

printf("反轉前:%s\n",str);

reverse(str);

printf("反轉後:%s\n",str);

return 0;

}

void reverse(char str[]){

int length = strlen(str);
int i,j=length/2;

for(i = 0; i < j; i++){
char c=str[i];
str[i] = str[length-i-1];
str[length-i-1] = c;
}

}

執行結果

反轉前:Hello World!
反轉後:!dlroW olleH

常用函數

C語言提供了很多函數來操作字串,以下舉幾個常用例子

函數名稱 標頭檔 說明
strlen string.h 取得字串長度(不含’\0’)
strcpy string.h 複製字串
strcat string.h 連接字串
strcmp string.h 比對字串
strstr string.h 找出符合的子字串
atoi stdlib.h 將字串轉為int
atol stdlib.h 將字串轉為long
atof stdlib.h 將字串轉為double
isalnum ctype.h 是否為字母或數字
isalpha ctype.h 是否為字母
isdigit ctype.h 是否為數字
islower ctype.h 是否為小寫字母
isupper ctype.h 是否為大寫字母

以下是幾個範例程式

  1. strlen範例程式

    size_t是string.h所定義的資料型態,大部分為unsigned int

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #include <stdio.h> 
    #include <string.h>

    int main() {

    char input[] = "Hello World!";

    size_t length;

    length = strlen(input);

    printf("字串長度:%u\n", length);

    return 0;

    }

    執行結果

    字串長度:12
    
  2. strcpy範例程式

    第一個參數是目標變數,第二個參數是你要複製的變數

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #include <stdio.h> 
    #include <stdlib.h>
    #include <string.h>

    int main() {

    char input[50];
    char tmp[50];

    puts("請輸入字串:");
    gets(input);

    strcpy(tmp, input);
    printf("複製後:%s\n", tmp);

    return 0;

    }

    執行結果

    請輸入字串:
    Hello
    複製後:Hello
    
  3. strcat範例程式

    第一個參數是要被連接的變數,第二個參數是要連接上去的變數

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #include <stdio.h> 
    #include <stdlib.h>
    #include <string.h>

    int main() {

    char str1[50] = "Hello";
    char str2[] = "World";

    printf("串接前:%s\n", str1);

    strcat(str1, str2);

    printf("串接後:%s\n", str1);

    return 0;

    }
執行結果

    串接前:Hello
    串接後:HelloWorld
  1. strcmp範例程式

    參數是兩個要比較的字串str1,str2,傳回-1代表str1str2

    比較方法是字典順序,字典順序就像字典在編排單字一樣,例如b大於a,ab大於aa

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdio.h> 
    #include <stdlib.h>
    #include <string.h>

    int main() {

    char str1[] = "a";
    char str2[] = "ab";

    printf("str1 < str2 %d\n",strcmp(str1, str2));
    printf("str1 == str2 %d\n",strcmp(str1, str1));
    printf("str1 > str2 %d\n",strcmp(str2, str1));

    }

    執行結果

    a < ab  -1
    a == a  0
    ab > a  1
    

更多範例可以上string.h還有ctype.h查詢www

參考

  1. C語言
  2. 一維陣列
  3. 二維陣列
  4. 字串(字元陣列)
  5. 字串長度、複製、串接
  6. 字串比較、搜尋
  7. 字串轉換、字元測試
  8. 陣列
  9. ctype.h
  10. string.h