在嵌入式系統或受限環境中,動態記憶體分配(malloc/free)可能不可用或不穩定。使用固定大小陣列 + 標誌位陣列模擬字串池,是一種輕量、確定性的替代方案。本文實作每條字串固定 9 字元(+1 結束符),支援新增、刪除、查詢操作。
#define CSTRSPACE 10000 // 字串儲存區總大小(字節)
#define NFLAGLEN (CSTRSPACE/10) // 標誌位陣列長度(每條佔 10 字節:9字元+\\0)
char cStr[CSTRSPACE] = {0}; // 字串內容連續儲存
int nFlag[NFLAGLEN] = {0}; // 0=空閒, 1=佔用
第 i 條字串儲存於 cStr + i*10,對應標誌 nFlag[i]。
addString()void addString(char *pcStr, int *pnFlag) {
printf("please input a string:\n");
for (int i = 0; i < NFLAGLEN; i++) {
if (pnFlag[i] == 0) { // 找到空閒槽
scanf("%9s", pcStr + i * 10); // 限寬讀取,防溢出
fflush(stdin); // 清除輸入緩衝(Windows)
pnFlag[i] = 1; // 標記佔用
printf("add succeed!\n\n");
return;
}
}
printf("No Space!\n"); // 滿了
}
searchString()void searchString(char *pcStr, int *pnFlag) {
printf("\n");
for (int i = 0; i < NFLAGLEN; i++) {
if (pnFlag[i] == 1) // 僅顯示有效
printf("%d:\t%s\n", i, pcStr + i * 10);
}
printf("\n");
}
delString()void delString(char *pcStr, int *pnFlag) {
searchString(pcStr, pnFlag); // 先列出供用戶選擇
printf("please input a number:\n");
int idx; scanf("%d", &idx);
if (idx >= 0 && idx < NFLAGLEN) {
pnFlag[idx] = 0; // 僅清標誌,內容保留(可選擇性清零)
printf("delete succeed!\n");
}
}
int main() {
char cStr[CSTRSPACE] = {0};
int nFlag[NFLAGLEN] = {0};
int choice;
while (1) {
printf("1. Add string\t2. Delete string\n");
printf("3. Search string\t0. Exit\n");
printf("please input a number:\n");
scanf("%d", &choice);
if (choice == 0) break;
switch (choice) {
case 1: addString(cStr, nFlag); break;
case 2: delString(cStr, nFlag); break;
case 3: searchString(cStr, nFlag); break;
default: printf("Wrong choose!\n\n");
}
}
return 0;
}
| 議題 | 本方案處理 | 延伸思考 |
|---|---|---|
| 定長限制 | %9s 截斷超長輸入 | 改用動態分配(鏈結串列/向量)支援變長 |
| 刪除後空洞 | 標誌歸零即可復用,無需移動 | 類似磁碟「標記刪除」,後續可實作「整理碎片」 |
| 查詢效率 | O(N) 掃描,N=1000 尚可接受 | 大量資料可建立索引(雜湊/Trie) |
| 執行緒安全 | 無鎖設計,單執行緒適用 | 多執行緒需加互斥鎖或使用無鎖資料結構 |
定長字串池是「陣列模擬堆記憶體」的經典範例,代碼簡潔、行為確定、無碎片化風險(定長下)。理解其原理,有助於掌握嵌入式開發、資料庫存儲引擎、檔案系統等領域的核心記憶體管理思想。建議動手嘗試擴展為變長版本,體會「碎片整理」與「分配演算法」的權衡藝術。