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

C語言字符串拼接實戰:指鉤操作與標準庫函數對比

     編輯:關於C語言

核心需求:在 C 中如何高效拼接字符串?

C 語言無內建字符串類型,字符串拼接本質是將源字符串內容複製到目標字符串尾部,並確保以 '\0' 結尾。本文通過一個經典的指鉤實現版本,深入剖析其邏輯、隱患,並對比標準庫 strcat/strncat 及安全版本的最佳實踐。

一、 指鉤版拼接函數深度解析

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h> // 實際開發建議包含

// 將字符串 t 拼接到字符串 s 末尾
void link(char *s, char *t) {
    // 1. 定位 s 的結尾 '\0'
    while (*s != '\0') {
        s++;
    }
    // 2. 複製 t 到 s 末尾,包含結尾 '\0'
    while (*t != '\0') {
        *s++ = *t++;
    }
    *s = '\0'; // 3. 關鍵:手動添加結尾符
}

int main() {
    char p[128] = "123"; // 目標緩衝區必須足夠大!
    char *q = "456";     // 源字符串 (常量區,只讀)
    link(p, q);
    printf("連接後的 p: %s\n", p); // 輸出: 123456
    // system("pause"); // 非跨平台,建議用 getchar()
    getchar();
    return 0;
}

關鍵點圖解

  1. 指針移動:第一個循環將 `s` 移至原字符串終止符處。
  2. 覆蓋寫入:第二個循環逐字符覆蓋終止符並追加新內容。
  3. 封閉結尾:循環結束時 `t` 指向 `\0`,需顯式賦值 `*s = '\0'` 確保新字符串合法。

二、 核心風險:緩衝區溢出

代碼中 char p[128] 固定大小,若 `strlen(p) + strlen(q) >= 128`,將導致**緩衝區溢出**,覆蓋棧上相鄰內存,引發崩潰或安全漏洞。此函數無長度檢查,屬高危實現。

三、 標準庫方案對比

函數簽名特點安全性
strcatchar *strcat(char *dest, const char *src)直接拼接,無長度檢查❌ 高危
strncatchar *strncat(char *dest, const char *src, size_t n)最多追加 n 字符,自動補 `\0`⚠️ 需正確計算 n
strlcat (BSD)size_t strlcat(char *dst, const char *src, size_t size)以總緩衝區大小為限,返回嘗試長度✅ 推薦 (非標準)
strcat_s (C11 Annex K)errno_t strcat_s(char *dest, rsize_t destsz, const char *src)檢查緩衝區邊界,失敗返回錯誤碼✅ 最佳 (需編譯器支持)

四、 安全拼接最佳實踐代碼

// 移植性較好的安全拼接封裝
#include <string.h>
#include <stdio.h>

int safe_strcat(char *dest, size_t dest_size, const char *src) {
    size_t dest_len = strlen(dest);
    if (dest_len >= dest_size) return -1; // 已滿或異常
    size_t remain = dest_size - dest_len - 1; // 留 1 位給 '\0'
    if (remain == 0) return -1;
    strncat(dest, src, remain);
    return 0;
}

int main() {
    char buf[32] = "Hello";
    safe_strcat(buf, sizeof(buf), " World!");
    printf("%s\n", buf); // 安全輸出
    return 0;
}

五、 進階:動態內存拼接 (適用於未知長度)

char *dynamic_concat(const char *s1, const char *s2) {
    size_t len1 = strlen(s1), len2 = strlen(s2);
    char *result = malloc(len1 + len2 + 1);
    if (!result) return NULL;
    memcpy(result, s1, len1);
    memcpy(result + len1, s2, len2 + 1); // 包含 '\0'
    return result; // 調用者負責 free()
}

總結

  • 指鉤實現是理解底層機制的優秀教具,生產代碼嚴禁直接使用無邊界檢查版本。
  • 優先使用 strncat 並精確計算剩餘空間,或引入 strlcat/strcat_s。
  • 頻繁拼接場景建議使用動態字符串結構體(如 struct { char *data; size_t len, cap; })實現擴容策略,避免反覆拷貝。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved