一、數(shù)組
一維數(shù)組
1. 數(shù)組定義
基本語(yǔ)法 正確示例:
// 數(shù)據(jù)類型 數(shù)組名[元素個(gè)數(shù)];
char arr[5]; // 字符數(shù)組
int arr[5]; // 整型數(shù)組
double arr[5]; // 雙精度浮點(diǎn)數(shù)組
float arr[5]; // 單精度浮點(diǎn)數(shù)組
// 使用常量表達(dá)式定義數(shù)組大小
int a[5]; // 整型常量
int b['A']; // 字符常量(等價(jià)于 int b[65])
int c[3*4]; // 常量表達(dá)式(等價(jià)于 int c[12])
? 錯(cuò)誤寫法:
int[5] a; // 錯(cuò)誤:[]必須在數(shù)組名后面
int[] b; // 錯(cuò)誤:必須指定元素個(gè)數(shù)
int size = 5;
int d[size]; // 錯(cuò)誤:C89標(biāo)準(zhǔn)不支持變量長(zhǎng)度(C99支持但有限制)
重要規(guī)則:
[]必須放在數(shù)組名后面- 元素個(gè)數(shù)必須是常量或常量表達(dá)式
- 大多數(shù)情況下不能省略元素個(gè)數(shù)(函數(shù)形參和初始化時(shí)除外)
2. 數(shù)組初始化
完全初始化:
char arr[5] = {90, 91, 92, 93, 94}; // 全部元素初始化
部分初始化:
char arr[5] = {90, 91}; // 前兩個(gè)元素初始化,其余自動(dòng)設(shè)為0
// 等價(jià)于:{90, 91, 0, 0, 0}
自動(dòng)推斷大小:
int arr[] = {1, 2, 3, 4, 5}; // 編譯器自動(dòng)推斷大小為5
? 錯(cuò)誤初始化:
int a[3];
a[3] = {1, 2, 3}; // 錯(cuò)誤:定義后不能整體賦值
a = {1, 2, 3}; // 錯(cuò)誤:數(shù)組名是常量指針,不能賦值
注意: 數(shù)組名代表整個(gè)數(shù)組的起始地址,是一個(gè)常量指針。
3. 數(shù)組訪問(wèn)
讀取元素:
char arr[5] = {90, 91, 92, 93, 94};
char s1 = arr[0]; // 讀取第0個(gè)元素:90
char s2 = arr[1]; // 讀取第1個(gè)元素:91
修改元素:
arr[1] = 89; // 修改第1個(gè)元素為89
?? 重要警告:
int arr[5] = {1, 2, 3, 4, 5};
arr[5] = 6; // ? 數(shù)組越界!C語(yǔ)言不會(huì)檢查邊界
C語(yǔ)言編譯器不會(huì)對(duì)數(shù)組下標(biāo)進(jìn)行越界檢查,程序員必須自己確保訪問(wèn)安全。
4. 數(shù)組作為函數(shù)參數(shù)
#include <stdio.h>
// 函數(shù)聲明:數(shù)組作為參數(shù)
void modifyArray(int arr[], int size) {
for(int i = 0; i < size; i++) {
arr[i] *= 2; // 修改數(shù)組元素
}
}
int main() {
int numbers[5] = {1, 2, 3, 4, 5};
printf("修改前: ");
for(int i = 0; i < 5; i++) {
printf("%d ", numbers[i]);
}
// 傳遞數(shù)組給函數(shù)
modifyArray(numbers, 5);
printf("\n修改后: ");
for(int i = 0; i < 5; i++) {
printf("%d ", numbers[i]); // 輸出:2 4 6 8 10
}
return 0;
}
關(guān)鍵點(diǎn): 數(shù)組名作為參數(shù)時(shí),傳遞的是數(shù)組的起始地址,形參和實(shí)參指向同一內(nèi)存空間。
二維數(shù)組
1. 二維數(shù)組定義與初始化
標(biāo)準(zhǔn)初始化:
// 3行4列的二維數(shù)組
int matrix[3][4] = {
{1, 2, 3, 4}, // 第0行
{5, 6, 7, 8}, // 第1行
{9, 10, 11, 12} // 第2行
};
字符二維數(shù)組示例:
char arr[5][3] = {
{91, 92, 93}, // 第0行
{81, 82, 83}, // 第1行
{71, 72, 73}, // 第2行
{61, 62, 63}, // 第3行
{51, 52, 53} // 第4行
};
簡(jiǎn)化初始化:
// 可以省略第一維的大小
int arr[][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}; // 編譯器自動(dòng)推斷為 int arr[3][3]
2. 二維數(shù)組訪問(wèn)
int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
// 訪問(wèn)單個(gè)元素
int element = matrix[0][0]; // 第0行第0列:1
matrix[1][2] = 99; // 修改第1行第2列的元素
// 遍歷二維數(shù)組
for(int i = 0; i < 3; i++) { // 遍歷行
for(int j = 0; j < 4; j++) { // 遍歷列
printf("%d ", matrix[i][j]);
}
printf("\n");
}
注意: 數(shù)組下標(biāo)從
0開始,matrix[m][n]表示第 m 行第 n 列。
重要總結(jié)
核心要點(diǎn)
- 一維數(shù)組最重要:實(shí)際開發(fā)中一維數(shù)組使用頻率遠(yuǎn)高于多維數(shù)組
- 內(nèi)存連續(xù)性:數(shù)組元素在內(nèi)存中是連續(xù)存儲(chǔ)的
- 下標(biāo)從0開始:C語(yǔ)言數(shù)組下標(biāo)始終從0開始計(jì)數(shù)
- 邊界自檢:編譯器不檢查數(shù)組越界,需要程序員保證安全
使用建議
// 良好的編程習(xí)慣:使用常量定義數(shù)組大小
#define MAX_SIZE 100
int main() {
int arr[MAX_SIZE];
// 循環(huán)時(shí)使用明確的邊界檢查
for(int i = 0; i < MAX_SIZE; i++) {
// 安全操作
}
return 0;
}
實(shí)際應(yīng)用優(yōu)先級(jí)
- 一維數(shù)組:★★★★★(最常用)
- 二維數(shù)組:★★☆☆☆(較少使用)
- 高維數(shù)組:★☆☆☆☆(極少使用)
掌握一維數(shù)組的使用是學(xué)習(xí)C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ),二維及以上數(shù)組在實(shí)際工程中應(yīng)用場(chǎng)景有限。
二、字符數(shù)組和字符串
字符串的本質(zhì)
C語(yǔ)言中沒有專門的字符串?dāng)?shù)據(jù)類型,而是通過(guò) 字符數(shù)組 來(lái)模擬字符串的功能。
關(guān)鍵概念:
- C語(yǔ)言中的字符串一定是
char型數(shù)組 - 但
char型數(shù)組不一定是字符串 -
字符串 = 以數(shù)字
0(或\0)結(jié)尾的字符數(shù)組
字符串的定義與區(qū)別
1. 字符 vs 字符數(shù)組 vs 字符串
#include <stdio.h>
int main() {
// 1. 單個(gè)字符
char ch = 'w';
// 2. 普通字符數(shù)組 - 不是字符串!
char arr[5] = {'h','e','l','l','o'};
// 3. 字符串 - 以 \0 結(jié)尾
char str1[] = {'h','e','l','l','o','\0'}; // 手動(dòng)添加 \0
char str2[] = {'h','e','l','l','o', 0}; // 等價(jià)寫法,數(shù)字0 = \0
// 4. 字符串字面量 - 編譯器自動(dòng)添加 \0
char *str3 = "hello"; // 字符串常量
char str4[] = "hello"; // 字符數(shù)組,自動(dòng)添加 \0
return 0;
}
2. 內(nèi)存布局對(duì)比
普通字符數(shù)組: | 'h' | 'e' | 'l' | 'l' | 'o' | ? | ? | ... |
字符串: | 'h' | 'e' | 'l' | 'l' | 'o' | \0 | ? | ... |
字符串的打印與遍歷
打印示例
#include <stdio.h>
int main() {
char arr[5] = {'h','e','l','l','o'}; // 普通字符數(shù)組
char str[] = {'h','e','l','l','o','\0'}; // 字符串
char str2[] = "hello"; // 字符串
// ? 危險(xiǎn):arr沒有\(zhòng)0結(jié)尾,printf會(huì)越界讀??!
printf("arr: %s\n", arr); // 可能打印亂碼
// ? 安全:str和str2以\0結(jié)尾
printf("str: %s\n", str); // 輸出: hello
printf("str2: %s\n", str2); // 輸出: hello
return 0;
}
遍歷示例
#include <stdio.h>
int main() {
char arr[5] = {'h','e','l','l','o'};
char str[] = {'h','e','l','l','o','\0'};
char str2[] = "hello";
printf("遍歷字符數(shù)組arr:\n");
for (int i = 0; i < sizeof(arr); i++) {
printf("%c", arr[i]); // 輸出: hello
}
printf("\n");
printf("遍歷字符串str:\n");
for (int i = 0; i < sizeof(str); i++) {
printf("%c", str[i]); // 輸出: hello
}
printf("\n");
printf("遍歷字符串str2:\n");
for (int i = 0; i < sizeof(str2); i++) {
printf("%c", str2[i]); // 輸出: hello
}
printf("\n");
return 0;
}
字符串長(zhǎng)度與結(jié)束標(biāo)志
字符串長(zhǎng)度規(guī)則
- 從頭開始,到第一個(gè)
\0結(jié)束 -
\0之前的字符個(gè)數(shù)就是字符串長(zhǎng)度
重要示例
#include <stdio.h>
int main() {
char str1[30] = "http://c.biancheng.net";
char str2[] = "C Language";
char str3[30] = "You are a good\0 boy!";
printf("str1: %s\n", str1); // 輸出: http://c.biancheng.net
printf("str2: %s\n", str2); // 輸出: C Language
printf("str3: %s\n", str3); // 輸出: You are a good
return 0;
}
解釋:
-
str1,str2: 編譯器自動(dòng)在末尾添加\0,正常輸出整個(gè)字符串 -
str3: 遇到中間的\0就結(jié)束,不輸出后面的 " boy!"
關(guān)鍵注意事項(xiàng)
1. 數(shù)組大小要足夠
// ? 錯(cuò)誤:數(shù)組太小,沒有空間存放 \0
char str[5] = "hello"; // 錯(cuò)誤!需要6個(gè)字節(jié)
// ? 正確:數(shù)組大小 = 字符數(shù) + 1(給\0留位置)
char str[6] = "hello"; // |h|e|l|l|o|\0|
char str[] = "hello"; // 編譯器自動(dòng)計(jì)算為6
2. 必須正確終止
// ? 不是字符串(缺少\0)
char not_string[5] = {'h','e','l','l','o'};
// ? 是字符串(有\(zhòng)0終止)
char is_string[6] = {'h','e','l','l','o','\0'};
char is_string2[] = "hello";
3. \0 之后的內(nèi)容被忽略
char msg[20] = "Hello\0World";
printf("%s", msg); // 只輸出 "Hello",遇到\0就停止
實(shí)用技巧總結(jié)
安全定義字符串
// 方法1:使用字符串字面量(推薦)
char str1[] = "Hello World";
// 方法2:顯式添加\0
char str2[] = {'H','e','l','l','o','\0'};
// 方法3:先聲明后初始化
char str3[20];
str3[0] = 'H';
str3[1] = 'i';
str3[2] = '\0'; // 重要:手動(dòng)添加結(jié)束符
驗(yàn)證字符串完整性
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "hello";
// 檢查是否以\0結(jié)尾
printf("Length: %zu\n", strlen(str)); // 輸出: 5
printf("Sizeof: %zu\n", sizeof(str)); // 輸出: 6 (包含\0)
printf("Last char: %d\n", str[5]); // 輸出: 0 (\0的ASCII值)
return 0;
}
核心要點(diǎn)回顧
-
字符串本質(zhì):以
\0結(jié)尾的字符數(shù)組 -
結(jié)束標(biāo)志:數(shù)字
0或\0,不是字符'0' -
數(shù)組大小:必須 ≥ 字符數(shù) + 1(為
\0預(yù)留空間) -
打印行為:
printf遇到\0就停止輸出 -
安全第一:確保所有字符串正確以
\0結(jié)尾