指針是 C 語言的靈魂,字符串則是指針應用的最高頻場景。本文結合動態內存分配、指針算術、字符串構建與遍歷,通過兩個完整案例演示正確用法並揭露經典坑點。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char *ptr = malloc(27 * sizeof(char)); // 26 字母 + '\0'
if (!ptr) {
puts("內存分配失敗!");
return EXIT_FAILURE;
}
ptr[26] = '\0'; // 先寫終止符,防衛性編程
char *p = ptr; // 工作指針,保護 ptr 不被移動
for (int ch = 'A'; ch <= 'Z'; ++ch) {
*p++ = (char)ch; // 寫入並後移
}
printf("ptr 內容: %s\n", ptr); // ABCDEFGHIJKLMNOPQRSTUVWXYZ
// 重置 p 以便再次遍歷或釋放
p = ptr;
puts(p); // 等價於 puts(ptr)
free(ptr); // 歸還堆內存
ptr = NULL; // 避免懸空指針
return EXIT_SUCCESS;
}
if (!ptr) 是專業代碼必備。p 遍歷,保持 ptr 指向塊首,便於 free。#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
// 1. 字符串字面量 —— 存儲在只讀區,不可修改
char *msg1 = "I am mini, I am very well!";
// msg1[0] = 'H'; // 錯誤:段錯誤(只讀內存)
// 2. 棧上字符數組 —— 可修改,生命週期隨作用域結束
char msg2[] = { "I am mini, I am very well!" };
msg2[0] = 'H'; // 合法
// 3. 動態分配 —— 可修改,手動管理生命週期
char *msg3 = malloc(100);
if (msg3) {
strcpy(msg3, "Dynamic string");
msg3[0] = 'H'; // 合法
free(msg3);
}
// 4. 不同類型指針的 malloc 模式
int *arr = malloc(50 * sizeof(int)); // 50 個 int
float *farr = malloc(10 * sizeof(float)); // 10 個 float
char *single = malloc(1); // 1 字節
*single = 'x';
free(arr); free(farr); free(single);
return 0;
}
| 概念 | 說明 | 典型錯誤 |
|---|---|---|
| 字符串結束符 | \0 (ASCII 0),標記字符串結尾 | 忘記分配/寫入 \0,導致越界讀取 |
| 指針算術 | p++ 移動 sizeof(*p) 字節 | 對 void* 算術(GNU 允許但非標準) |
| 字面量 vs 數組 | char *s = "abc"; 指向只讀區;char s[] = "abc"; 棧上拷貝 | 嘗試修改字面量導致崩潰 |
| malloc 參數 | 總字節數 = 元素數 × sizeof(類型) | 只寫元素數,忘記乘 sizeof |
void* 做算術(除非強轉為 char*)。free 非 malloc/calloc/realloc 返回的指針(如字面量、棧地址)。free 的指針(置 NULL 即可避免)。snprintf、strncpy 等帶長度限制的安全版本。指針與字符串的舞蹈,核心在於所有權清晰、邊界檢查、生命週期同步。熟練掌握動態內存模式,是從「能跑通」進化到「工業級可靠」的分水嶺。