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

C 語言字符串複製深度解析:何時需要 malloc?

     編輯:關於C語言

C 語言字符串複製深度解析:何時需要 malloc?

閱讀前輩代碼時發現:有時直接將字符串指針賦給另一指針,有時又 malloc 內存再拷貝內容。這其中門道何在?研究後發現其實很簡單,記錄如下。

核心結論

若源字符串所在內存即將被釋放/覆蓋(如棧上局部數組),必須 malloc 新內存並拷貝內容;若源字符串生命週期足夠長(如靜態/全局/堆內存),直接賦值指針即可。

有時 malloc 也是為了避免修改源字符串影響副本(防止別名問題),但這屬於設計選擇,非必然。

場景演示

錯誤示範:直接賦值指針指向棧上局部數組

#include <stdio.h>
#include <string.h>

typedef void(*str_cpy_cb)(char *name);
void test(str_cpy_cb cb);
void call_back(char *name);

char *test_name = NULL;

int main() {
    test(call_back);
    printf("name: %s\n", test_name); // 未定義行為:test_name 指向已銷毀的棧內存
    return 0;
}

void test(str_cpy_cb cb) {
    char myname[8] = {0};
    snprintf(myname, sizeof(myname), "%s", "slk");
    printf("myname: %s\n", myname);
    cb(myname); // 傳遞局部數組地址
}

void call_back(char *name) {
    test_name = name; // 直接賦值指針,危險!
    printf("test_name: %s\n", test_name);
}

結果: main 中輸出亂碼或崩潰,因為 `myname` 是 `test` 的局部數組,函數返回後棧幀銷毀,內存無效。

錯誤運行結果

正確做法:malloc 拷貝內容

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef void(*str_cpy_cb)(char *name);
void test(str_cpy_cb cb);
void call_back(char *name);

char *test_name = NULL;

int main() {
    test(call_back);
    printf("name: %s\n", test_name); // 正確輸出 "slk"
    free(test_name); // 記得釋放
    return 0;
}

void test(str_cpy_cb cb) {
    char myname[8] = {0};
    snprintf(myname, sizeof(myname), "%s", "slk");
    printf("myname: %s\n", myname);
    cb(myname);
}

void call_back(char *name) {
    test_name = (char *)malloc(strlen(name) + 1); // 分配新內存
    snprintf(test_name, strlen(name) + 1, "%s", name); // 拷貝內容
    printf("test_name: %s\n", test_name);
}

結果: 正確輸出 "slk",且 `test_name` 指向堆內存,生命週期由程序員控制。

正確運行結果

進階說明

  • 字符串字面量(如 `"hello"`)存儲在只讀數據區,生命週期贯穿整個程序,直接賦值指針安全(但不可修改內容)。
  • 動態分配內存(malloc/new)生命週期直到 free/delete,跨函數傳遞指針安全。
  • 靜態/全局數組 生命週期全程,直接賦值指針安全。
  • 函數參數為 `char *` 時,調用者傳入的緩衝區所有權歸調用者,被調用者不應 free,也不應長期持有指針除非複製。

最佳實踐建議

  1. 明確內存所有權:誰分配誰釋放,文檔化接口契約。
  2. 跨作用域共享字符串內容時,優先深拷貝(malloc + strcpy/strncpy)。
  3. 使用 `strdup`(POSIX)或自寫安全複製函數簡化代碼。
  4. 嵌入式/受限環境可考慮靜態緩衝區池避免頻繁 malloc/free。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved