編寫一個函數將輸入字符串複製到字符數組中,在主函數中實現輸入輸出。限制條件:未學指針,需使用數組下標訪問。
gets() 或 scanf() 獲取輸入while 循環逐字符複製,直到遇到 '\0''\0' 結束標記puts() 或循環輸出結果#include <stdio.h>
// 函數聲明:接收字符數組(實際為指針,但初學者可理解為數組傳遞)
void str_copy(char dest[], const char src[]) {
int i = 0;
// 逐字符複製,包含結束符
while (src[i] != '\0') {
dest[i] = src[i];
i++;
}
dest[i] = '\0'; // 關鍵:手動添加字符串結束標記
}
int main() {
char input[100];
char output[100];
printf("請輸入一個字符串: ");
// 使用 fgets 替代危險的 gets,防止緩衝區溢出
fgets(input, sizeof(input), stdin);
// 處理 fgets 保留的換行符
int len = 0;
while (input[len] != '\0') len++;
if (len > 0 && input[len-1] == '\n') {
input[len-1] = '\0';
}
str_copy(output, input);
printf("複製結果: ");
puts(output); // 自動換行
return 0;
}
字符串 = 字符數組 + '\0' 結束標記。"hello" 在內存中實際佔用 6 字節:'h','e','l','l','o','\0'。
雖然語法上寫 char dest[],但編譯器實際將其轉換為 char *dest。函數內部對數組元素的修改**直接影響原數組**——這就是「傳址調用」的體現,無需指針語法即可實現。
dest = src?數組名是常量指針,不能賦值。必須逐元素複製內容。
gets() 的危險性與替代方案gets() 不檢查緩衝區大小,極易導致緩衝區溢出漏洞,已從C11標準中移除。
安全替代:fgets(buffer, size, stdin) 或 scanf("%99s", buffer) (限制長度)
// 返回實際複製字符數(不含結束符),-1表示截斷
int str_copy_safe(char dest[], int dest_size, const char src[]) {
if (dest_size <= 0) return -1;
int i = 0;
for (; i < dest_size - 1 && src[i] != '\0'; i++) {
dest[i] = src[i];
}
dest[i] = '\0';
return (src[i] == '\0') ? i : -1; // -1表示源串過長被截斷
}
| 錯誤現象 | 原因 | 修正方法 |
|---|---|---|
| 輸出包含亂碼 | 目標數組未以 '\0' 結束 | 複製循環後添加 dest[i] = '\0' |
| 只複製了第一個字符 | 循環條件寫錯,如 while(src[i]) 但未遞增 i | 檢查循環體內 i++ 位置 |
| 程序崩潰 | 目標數組太小導致越界寫入 | 確保目標數組足夠大,或使用帶長度檢查版本 |
| 輸入含空格時只讀到第一個詞 | 使用 scanf("%s") 遇空格停止 | 改用 fgets() 或 scanf("%[^\n]") |
實際工程中直接使用標準庫:
#include <string.h>
strcpy(dest, src); // 基本複製,無長度檢查
strncpy(dest, src, n); // 複製前n字符,可能不添加'\0'
strlcpy(dest, src, size); // BSD擴展,安全複製(非標準)
snprintf(dest, size, "%s", src); // 通用安全格式化複製
str_cat:字符串拼接str_cmp:字符串比較str_len:計算字符串長度str_rev:字符串反轉