在實際專案開發中,字串處理往往封裝為標準化介面,強調參數檢查、記憶體安全與指標輸入/輸出特性的區分。
strstr 迴圈)使用 do-while 或 while 配合 strstr 尋找子串,找到後移動指標繼續搜尋,並嚴格檢查邊界條件。
int getCout(char *str, char *substr, int *count) {
if (!str || !substr || !count) return -1; // 參數合法性檢查
int ncout = 0;
char *p = str;
do {
p = strstr(p, substr);
if (!p) break;
ncout++;
p += strlen(substr); // 移至下一個搜尋起始位置
} while (*p != '\0');
*count = ncout; // 透過指標回傳結果 (輸出型參數)
return 0;
}
雙指標 i (頭) 與 j (尾) 向中間收斂,嚴禁修改輸入緩衝區,應將結果複製至輸出緩衝區。
int trimSpace_ok(char *mybuf, char *outbuf) {
int i = 0, j = strlen(mybuf) - 1;
while (isspace(mybuf[i]) && mybuf[i]) i++;
while (isspace(mybuf[j]) && j > 0) j--;
int count = j - i + 1;
if (count < 0) count = 0;
memcpy(outbuf, mybuf + i, count);
outbuf[count] = '\0';
return 0;
}
void reverse(char *p) {
char *p1 = p, *p2 = p + strlen(p) - 1;
while (p1 < p2) {
char c = *p1; *p1 = *p2; *p2 = c;
++p1; --p2;
}
}
適用於 key=value 格式解析,結合 strstr 定位關鍵字與分隔符,再提取值並去除空格。
const char * 最佳實踐。char ** 或緩衝區指標 char *outbuf。strcat、指標推進解析)。strlen、strcpy、strcat理解指標遞增與字元複製的核心邏輯:
// strlen
int mystrlen(char *s) { int n=0; while(*s++) n++; return n; }
// strcpy (標準返回目的地址)
char* mystrcpy(char *dst, const char *src) {
char *ret = dst;
while((*dst++ = *src++));
return ret;
}
// strcat
char* mystrcat(char *dst, const char *src) {
char *ret = dst;
while(*dst) dst++; // 找到結尾
while((*dst++ = *src++));
return ret;
}
自動補齊路徑分隔符 /。
strcmp, sizeof vs strlen, strcat, strtok (注意破壞原字串且非執行緒安全), strstr, sscanf/sprintf 格式化轉換, memset 初始化。
指標陣列 char *argv[] 儲存命令列參數,argc 為個數。環境變數同樣為 char **env,以 NULL 結尾。
int main(int argc, char *argv[], char **env) {
for (int i=0; i<argc; i++) printf("argv[%d]=%s\n", i, argv[i]);
for (int i=0; env[i]; i++) printf("env[%d]=%s\n", i, env[i]);
return 0;
}
#include 檔案包含機制#include <stdio.h> 搜尋系統目錄;#include "my.h" 先搜尋當前目錄,再搜尋系統目錄。可透過 gcc -I 指定搜尋路徑。
#define SIZE 100、#define PI 3.14。#define MAX(a,b) ((a)>(b)?(a):(b))。參數必須加括號,避免運算子優先級問題。多行使用反斜線 \ 續行。# 與連接 ##: #define STR(x) #x、#define CONCAT(a,b) a##b。標準護衛宏模式:
#ifndef MY_HEADER_H #define MY_HEADER_H // 宣告內容 #endif
進階:根據編譯選項 (-DSHORT) 選擇不同型別實作:
#if defined(SHORT) #include "short.h" #elif defined(LONG) #include "long.h" #else #include "standard.h" #endif
static 關鍵字:內部連結與封裝.c),外部不可見,實現資訊隱藏。將功能拆分為 .h (介面) + .c (實作)。Makefile 定義相依關係與編譯指令,實現增量編譯。
# 簡易 Makefile 範例
main: main.o input.o output.o
gcc main.o input.o output.o -o main
main.o: main.c input.h output.h
gcc -c main.c
input.o: input.c input.h
gcc -c input.c
output.o: output.c output.h
gcc -c output.c
clean:
rm -f *.o main
struct Student { int id; char name[20]; };
// 宣告同時定義變數
struct Student stu1 = {101, "Alice"};
// 指定成員初始化 (C99)
struct Student stu2 = {.name = "Bob", .id = 102};
// 巢狀結構:矩形由兩點構成
struct Point { int x, y; };
struct Rect { struct Point lt, rb; };
struct Rect r = {{0,0}, {10,20}};
// 面積計算
int area = abs(r.lt.x - r.rb.x) * abs(r.lt.y - r.rb.y);
struct Month { char name[10]; int days; };
struct Month year[12] = {
{"January", 31}, {"February", 28}, {"March", 31},
{"April", 30}, {"May", 31}, {"June", 30},
{"July", 31}, {"August", 31}, {"September", 30},
{"October", 31}, {"November", 30}, {"December", 31}
};
void f(struct S s): 複製整個結構體,開銷大,函數內修改不影響原物件。void f(struct S *p): 傳遞指標 (4/8 位元組),效率高,可修改原物件。成員存取使用 p->member。最佳實踐: 唯讀傳遞大型結構體用 const struct S *;需修改或節省開銷用 struct S *。
C 語言支援直接返回結構體 (複製返回),但較大結構體建議使用「輸出型參數」模式:
// 返回結構體 (適用於小型結構)
struct Student input1() { struct Student s; scanf(...); return s; }
// 輸出型參數 (推薦用於大型結構或需錯誤碼返回)
int input2(struct Student *out) {
if (!out) return -1;
scanf("%d %s", &out->id, out->name);
return 0;
}
結構體大小非單純成員大小之和。編譯器遵循:
struct { char c; int i; } // 大小通常為 8 位元組 (非 5)
/* 記憶體佈局:
c | padding(3) | i(4) | = 8 bytes
*/
可透過 #pragma pack(n) 或屬性 __attribute__((packed)) 壓縮對齊,但可能影響存取效能或觸發硬體異常。
所有成員共用同一塊記憶體,大小等於最大成員。用於型別轉換、節省記憶體、協定解析。
union Data { int i; float f; char c[4]; };
union Data d;
d.i = 0x41424344;
printf("%s\n", d.c); // 輸出 "DCBA" (小端序)
本質為 int 常數,增強程式碼可讀性與型別安全 (編譯器可檢查 switch 覆蓋率)。
enum Week { Mon=1, Tue, Wed, Thu, Fri, Sat, Sun };
enum Week today = Wed;
switch(today) { case Mon: ... break; ... }
字串處理重在記憶體邊界檢查與指標特性區分;預處理器提供強大的條件編譯與巨集抽象能力,配合 Makefile 實現工程化建置;結構體/聯合/列舉構成了 C 語言自定義資料型別的基石,深入理解記憶體佈局 (對齊/補齊) 為高效系統程式設計鋪路。