char* GetStaffNameById(int iId) {
stStaffInfo stTmpInfo[] = { // 局部數組,棧上分配
{"Socrates", 1},
{"dyx1024", 2},
{"Kevin", 3},
{"Jim", 4}
};
for (int i = 0; i < 4; i++)
if (stTmpInfo[i].iId == iId)
return stTmpInfo[i].pName; // 返回局部數組成員地址!
return "No match Name";
}
運行輸出正確(Staff Name is : dyx1024),但屬於未定義行為:函數返回後棧幀銷毀,返回指針指向已釋放內存,後續任意函數調用均可能覆蓋該區域。
static stStaffInfo stTmpInfo[] = { // 文件作用域,程序生命周期
{"Socrates", 1}, {"dyx1024", 2}, {"Kevin", 3}, {"Jim", 4}
};
char* GetStaffNameById(int iId) {
for (int i = 0; i < 4; i++)
if (stTmpInfo[i].iId == iId) return stTmpInfo[i].pName;
return "No match Name";
}
char* GetStaffNameById(int iId) {
static stStaffInfo stTmpInfo[] = { // 函數級 static,初始化一次
{"Socrates", 1}, {"dyx1024", 2}, {"Kevin", 3}, {"Jim", 4}
};
// ... 同方案一
}
_Thread_local 緩解)void GetStaffNameById(int iId, int nameLen, char *outName) {
if (!outName) return;
stStaffInfo stTmpInfo[] = { ... }; // 局部數組安全
for (int i = 0; i < 4; i++)
if (stTmpInfo[i].iId == iId) {
strncpy(outName, stTmpInfo[i].pName, nameLen);
return;
}
strncpy(outName, "No match Name", nameLen);
}
// 調用
char name[21];
GetStaffNameById(2, 20, name);
char* GetStaffNameById(int iId) {
stStaffInfo stTmpInfo[] = { ... };
char *ret = malloc(20);
if (!ret) exit(1);
for (int i = 0; i < 4; i++)
if (stTmpInfo[i].iId == iId) { strncpy(ret, stTmpInfo[i].pName, 20); return ret; }
strncpy(ret, "No match Name", 20);
return ret;
}
// 調用
char *name = GetStaffNameById(2);
printf("%s\n", name);
free(name); // 必須釋放!
free 導致洩漏exit(1))| 場景 | 推薦方案 | 理由 |
|---|---|---|
| 只讀常量表、單線程、嵌入式 | 方案二 | 零開銷、封裝好 |
| 通用庫函數、多線程、安全優先 | 方案三 | 無所有權轉移、零風險 |
| 返回動態長度字符串、C++ 環境 | 方案四 / std::string | RAII 自動管理 |
| 字面量字符串常量 | 直接返回 | 存儲在 .rodata,生命周期永久 |