首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言多維數組與字符串數組:內存佈局、訪問模式與字符串處理實戰

     編輯:關於C語言

多維數組:行優先的連續內存

1. 二維數組定義與初始化


float sales[3][8]; // 3行8列
int matrix[3][3] = {{1,2,3}, {4,5,6}, {7,8,9}}; // 分行初始化
int flat[3][3] = {1,2,3,4,5,6,7,8,9};           // 扁平初始化 (按行優先)

2. 內存佈局:行優先

matrix[0][0] matrix[0][1] matrix[0][2]  // 第0行連續
matrix[1][0] matrix[1][1] matrix[1][2]  // 第1行連續
matrix[2][0] matrix[2][1] matrix[2][2]  // 第2行連續

地址遞增順序:[0][0] → [0][1] → [0][2] → [1][0] → ...

3. 元素訪問與指針算術


int a[3][4];
a[i][j]            // 標準下標
*(*(a + i) + j)    // 指針解引用等價
*(a[i] + j)        // 行指針 + 列偏移

4. 三維及更高維


int cube[2][3][4]; // 2層 × 3行 × 4列 = 24元素
cube[layer][row][col] // 邏輯結構
// 內存仍線性:layer主序 → row → col

⚠️ 維度過高 (>3) 代碼複雜度激增,建議扁平化為一維數組 + 索引計算:idx = (l*R + r)*C + c。

字符串數組:指針數組的特殊形態

1. 二維字符數組 vs 指針數組

形式定義內存結構修改性
二維字符數組char strs[10][20]連續塊,每行固定 20 字節可修改內容
指針數組char *strs[10]指針數組 + 字符串字面量/堆內存字面量不可修改

2. 輸入處理:scanf vs gets vs fgets


// ❌ scanf 停於空白
char s[20];
scanf("%s", s); // 輸入 "hello world" → 只讀 "hello"

// ❌ gets 不安全 (已移除 C11),無緩衝區檢查
gets(s); // 危險!

// ✅ fgets 安全標準
fgets(s, sizeof(s), stdin); // 讀整行含換行符
// 移除換行符
s[strcspn(s, "\n")] = '\0';

3. 字符串結束符 \0

  • 字符串字面量 "hello" 編譯器自動添加 \0。
  • strlen 計數不含 \0,sizeof 含 \0。
  • 手動構建字符串必須以 \0 結尾。

字符串操作核心庫函數 (string.h)

函數功能返回值注意
strlen(s)長度 (不含\0)size_tO(n)
strcpy(dst, src)複製dst目標需足夠大,無長度檢查
strncpy(dst, src, n)複製前 n 字符dst若 src< n,補\0;否則不加\0
strcat(dst, src)追加dst目標需足夠大
strcmp(s1, s2)字典序比較<0,=0,>0按 ASCII 值
strncmp(s1, s2, n)比較前 n 字符<0,=0,>0
strchr(s, c)查找字符首次出現指針/NULL
strstr(hay, needle)查找子串指針/NULL

實戰:字符串數組排序


#include 
#include 
#include 

int cmp_str(const void *a, const void *b) {
    return strcmp(*(const char**)a, *(const char**)b);
}

int main() {
    char *names[] = {"Charlie", "Alice", "Bob", "David"};
    int n = sizeof(names)/sizeof(names[0]);
    qsort(names, n, sizeof(char*), cmp_str);
    for (int i = 0; i < n; i++) puts(names[i]);
    // Alice, Bob, Charlie, David
    return 0;
}

動態字符串數組:堆分配指針數組


char **read_lines(int *count) {
    char **lines = NULL;
    char buf[1024];
    *count = 0;
    while (fgets(buf, sizeof(buf), stdin)) {
        buf[strcspn(buf, "\n")] = '\0';
        lines = realloc(lines, (*count + 1) * sizeof(char*));
        lines[*count] = strdup(buf); // strdup = malloc + strcpy
        (*count)++;
    }
    return lines;
}

void free_lines(char **lines, int count) {
    for (int i = 0; i < count; i++) free(lines[i]);
    free(lines);
}

避坑指南

  • ❌ scanf("%s", s) 無長度限制 → 緩衝區溢出。用 fgets 或 scanf("%19s", s)。
  • ❌ 修改字符串字面量 char *p = "abc"; p[0]='x'; → 崩潰。用數組 char p[] = "abc";。
  • ❌ strcpy 目標空間不足 → 溢出。用 strncpy/snprintf 或動態分配。
  • ❌ 忘記 \0 結尾 → strlen/printf 越界讀取。
  • ❌ 二維數組行長固定浪費空間 → 改用指針數組 + malloc。

總結

多維數組按行優先連續存儲,指針算術自動縮放。字符串數組本質是指針數組,配合 string.h 標準函數高效處理。牢記 \0 結尾約定,優先使用安全函數 (fgets, strncpy, snprintf),動態場景採用指針數組 + 堆分配。掌握這些,字符串處理不再是痛點。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved