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

深入理解C指針(五):指針與字符串完整指南

     編輯:關於C語言

深入理解C指針(五):指針與字符串完整指南

字符串是C語言中使用最頻繁、也是Bug高發區的數據類型。本文系統梳理字符串的內存模型、初始化方式、標準庫操作、函數傳遞返回、命令行參數處理、函數指針應用,助你構建清晰的字符串編程心智模型。

一、 基礎概念:字符串在內存中的真相

  • 定義:以\0(NUL,ASCII 0)結尾的字符序列。char*指向首字符,長度不含\0,分配空間需+1。
  • 兩類字符串:單字節char*、寬字符wchar_t*(16/32位,支持國際化)。
  • 三種聲明方式:
    1. 字符串字面量:"hello",存儲在只讀字面量池,多次使用同一文面量通常共享一份副本。不可修改,修改導致未定義行為。
    2. 字符數組:char str[] = "hello"; 或 char str[10] = "hi";。存儲在棧(局部)或全局/靜態區,可修改,大小固定。
    3. 字符指針:char *p = "hello"; 指向字面量池(只讀);char *p = malloc(...); strcpy(p, "hello"); 指向堆,可修改、可擴展、需手動free。
  • sizeof vs strlen:sizeof(arr)返回數組總字節數(含\0);sizeof(ptr)返回指針大小(4/8字節);strlen(str)返回邏輯長度(不含\0)。

二、 標準字符串操作(<string.h>)

函數原型關鍵點
比較int strcmp(const char*, const char*)返回0相等,<0 s10 s1>s2。絕不可用 ptr1 == ptr2 比較內容。
複製char* strcpy(char* dest, const char* src)含\0整體複製。dest必須有足夠空間。安全版strncpy不保證以\0結尾。
拼接char* strcat(char* dest, const char* src)將src接到dest末尾(覆蓋dest的\0)。dest需預留足夠空間。常見錯誤:strcat(str1, str2)未分配新空間導致溢出。
長度size_t strlen(const char*)掃描至\0,O(n)。

三、 動態內存管理字符串模式

// 讀取任意長度行,動態擴容
char* readLine() {
    size_t cap = 16, len = 0;
    char *buf = malloc(cap), *p = buf;
    int ch;
    while ((ch = getchar()) != '\n' && ch != EOF) {
        if (len + 1 >= cap) { // +1 for \0
            cap *= 2;
            char *nb = realloc(buf, cap);
            if (!nb) { free(buf); return NULL; }
            p = nb + (p - buf); // 維持相對偏移
            buf = nb;
        }
        *p++ = ch; len++;
    }
    *p = '\0';
    return buf; // 調用者負責 free
}

四、 函數傳遞與返回字符串

  • 傳入:void func(const char* s)(只讀)或 void func(char* buf, size_t n)(輸出緩衝區)。數組名退化為指針傳遞。
  • 返回:
    1. 字面量/靜態緩衝區:const char* getMsg() { return "static"; } 線程不安全,多次調用覆蓋。
    2. 動態分配:char* dup(const char* s) { char* p=malloc(strlen(s)+1); strcpy(p,s); return p; } 調用者必須 free,文檔需明確說明。
    3. 調用者提供緩衝區:void format(char* out, size_t n, ...) 最安全,無所有權轉移。
  • 禁忌:返回局部數組指針(棧幀銷毀後失效)。

五、 命令行參數:main(int argc, char** argv)

  • argc:參數個數(含程序名)。
  • argv:指針數組,argv[0]為程序路徑,argv[1..argc-1]為實際參數。
  • 參數以空格分隔,含空格的參數需用引號包裹:./prog "hello world" 42 → argv[1]="hello world"。

六、 函數指針與字符串:實現策略模式

// 比較器類型
typedef int (*CmpFunc)(const char*, const char*);

// 忽略大小寫比較
int cmpIgnoreCase(const char* a, const char* b) {
    char *la = strToLower(a), *lb = strToLower(b);
    int r = strcmp(la, lb);
    free(la); free(lb);
    return r;
}

// 通用排序
void sortStrings(char* arr[], int n, CmpFunc cmp) {
    for (int i=0; i 0) {
                char* t = arr[j]; arr[j] = arr[j+1]; arr[j+1] = t;
            }
}

// 使用
char* names[] = {"Jack","rose","TITANIC"};
sortStrings(names, 3, strcmp);         // 區分大小寫
sortStrings(names, 3, cmpIgnoreCase);  // 忽略大小寫

函數指針使算法與比較策略解耦,是C語言實現多態、回調、插件架構的核心機制。

七、 總結:字符串編程黃金法則

  1. 區分只讀字面量與可寫緩衝區,const char*用於只讀參數。
  2. 分配空間必須 +1 給 \0,malloc(strlen(s)+1)。
  3. 誰分配誰釋放,文檔明確所有權歸屬。
  4. 邊界檢查:用strncpy/strncat/snprintf或手動檢查,防緩衝區溢出。
  5. 優先使用調用者提供緩衝區模式,避免動態分配帶來的洩漏風險。

掌握字符串的內存語義、生命週期、所有權轉移,是寫出健壯C代碼的分水嶺。

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