目录
1. 字符指针与字符串的核心原理
字符串的本质
字符串的存储
字符指针的特性
字符指针的操作
2. 编程实例
3. 常见陷阱与注意事项
4. 总结
C语言中没有独立的字符串类型,字符串本质是 以\0
(空字符)结尾的字符数组。
字符串的存储方式:
字符数组:显式声明数组并初始化,如 char str[] = "Hello";
。
字符指针:直接指向字符串字面量(存储在程序的只读内存区),如 char *p = "Hello";
。
在C语言中,字符串是以字符数组的形式存储的,并以空字符 \0 作为字符串的结束标志。下面通过文字描述和图示来解释C语言中的字符串存储规则。
假设有一个简单的字符串 "Hello",在内存中的存储形式如下:
地址 内存内容
-----------------
1000 'H' (72)
1001 'e' (101)
1002 'l' (108)
1003 'l' (108)
1004 'o' (111)
1005 '\0' (0) // 字符串结束标志
图例表示
如果我们用图形的方式表示上述 "Hello" 字符串在内存中的存储方式,可以想象成如下布局:
+--------+--------+--------+--------+--------+--------+
| 1000 | 1001 | 1002 | 1003 | 1004 | 1005 |
+--------+--------+--------+--------+--------+--------+
| 'H' | 'e' | 'l' | 'l' | 'o' | '\0' |
+--------+--------+--------+--------+--------+--------+
每个方格代表一个字节的内存单元,里面存放的是相应字符的ASCII码值。例如,'H' 的ASCII码是72,但在内存表示中我们通常直接写字符本身而不是其ASCII码值,以便于理解和记忆。
指向字符串字面量:字符指针可以指向字符串常量(只读内存区),但不可修改其内容。
char *p = "Hello"; // p指向只读内存区的字符串
// p[0] = 'h'; // 错误!尝试修改只读内存会导致崩溃
char arr[] = "Hello";
char *p = arr; // p指向栈上的字符数组
p[0] = 'h'; // 合法!修改栈内存
实例1:字符指针与字符串初始化
#include
int main() {
// 方式1:字符指针指向字符串字面量(只读)
char *str1 = "Hello";
printf("str1: %s\n", str1); // 输出: Hello
// 方式2:字符数组(可修改)
char str2[] = "World";
char *p = str2; // 指针指向字符数组
p[0] = 'w'; // 修改第一个字符
printf("str2: %s\n", p); // 输出: world
return 0;
}
实例2:动态分配字符串内存
#include
#include
#include
int main() {
// 动态分配内存存储字符串
char *str = (char*)malloc(20 * sizeof(char));
if (str == NULL) {
printf("内存分配失败!\n");
return 1;
}
strcpy(str, "Dynamic"); // 复制字符串到堆内存
printf("初始内容: %s\n", str); // 输出: Dynamic
strcat(str, "123"); // 追加字符串
printf("追加后内容: %s\n", str); // 输出: Dynamic123
free(str); // 释放内存
str = NULL; // 避免野指针
return 0;
}
实例3:字符指针遍历字符串
#include
void print_string(const char *str) {
while (*str != '\0') { // 遍历直到空字符
printf("%c ", *str);
str++; // 指针后移
}
printf("\n");
}
int main() {
char *s = "Pointer";
print_string(s); // 输出: P o i n t e r
return 0;
}
实例4:修改字符指针指向的内容
#include
int main() {
char arr[] = "Hello"; // 栈上的字符数组
char *p1 = arr; // 指向可修改的数组
p1[0] = 'h'; // 合法修改
printf("p1: %s\n", p1); // 输出: hello
char *p2 = "Hello"; // 指向只读内存的字符串字面量
// p2[0] = 'h'; // 运行时错误(段错误)!
printf("p2: %s\n", p2);
return 0;
}
实例5:字符串作为函数参数(指针传递)
#include
// 函数:统计字符串长度(手动实现strlen)
int string_length(const char *str) {
int len = 0;
while (*str != '\0') {
len++;
str++;
}
return len;
}
int main() {
char *s = "C Programming";
printf("字符串长度: %d\n", string_length(s)); // 输出: 13
return 0;
}
1. 修改只读字符串
char *p = "Hello";
p[0] = 'h'; // 段错误!字符串字面量不可修改。
2. 未分配内存直接使用指针
char *p;
strcpy(p, "Hello"); // 野指针!p未初始化指向合法内存。
3. 忘记字符串终止符\0
char arr[5] = {'H', 'e', 'l', 'l', 'o'}; // 缺少\0,遍历时可能越界
printf("%s", arr); // 输出可能包含乱码
4. 内存泄漏
char *str = malloc(100);
// 忘记调用 free(str);
字符指针是操作字符串的核心工具,灵活但需谨慎使用。
字符串字面量存储在只读内存区,字符指针指向时不可修改。
字符数组(栈或堆内存)可通过指针修改内容。
动态分配字符串内存时,必须手动管理生命周期(malloc
/free
)。
始终确保字符串以\0
结尾,避免越界访问。