目录
1. 字符指针与字符串的核心原理
字符串的本质
字符串的存储
字符指针的特性
字符指针的操作
2. 编程实例
3. 常见陷阱与注意事项
4. 总结
1. 字符指针与字符串的核心原理
字符串的本质
-
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) // 字符串结束标志
- 每个字符都占用一个字节的存储空间。
- '\0' 是字符串的结束标记,它告诉程序这个位置之前的所有字符属于当前字符串。
- 注意这里的地址(如1000)只是示意性的,实际的内存地址会根据系统分配情况有所不同。
图例表示
如果我们用图形的方式表示上述 "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'; // 合法!修改栈内存
字符指针的操作
- 遍历字符串:通过指针移动逐个访问字符,直到遇到\0。
- 动态内存分配:使用malloc为字符串动态分配内存,需手动释放。
- 字符串函数:C标准库提供<string.h>中的函数(如strcpy、strlen),底层均依赖指针操作。
2. 编程实例
实例1:字符指针与字符串初始化
#include <stdio.h>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); // 输出: worldreturn 0;
}
实例2:动态分配字符串内存
#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main() {// 动态分配内存存储字符串char *str = (char*)malloc(20 * sizeof(char));if (str == NULL) {printf("内存分配失败!\n");return 1;}strcpy(str, "Dynamic"); // 复制字符串到堆内存printf("初始内容: %s\n", str); // 输出: Dynamicstrcat(str, "123"); // 追加字符串printf("追加后内容: %s\n", str); // 输出: Dynamic123free(str); // 释放内存str = NULL; // 避免野指针return 0;
}
实例3:字符指针遍历字符串
#include <stdio.h>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 <stdio.h>int main() {char arr[] = "Hello"; // 栈上的字符数组char *p1 = arr; // 指向可修改的数组p1[0] = 'h'; // 合法修改printf("p1: %s\n", p1); // 输出: hellochar *p2 = "Hello"; // 指向只读内存的字符串字面量// p2[0] = 'h'; // 运行时错误(段错误)!printf("p2: %s\n", p2);return 0;
}
实例5:字符串作为函数参数(指针传递)
#include <stdio.h>// 函数:统计字符串长度(手动实现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)); // 输出: 13return 0;
}
3. 常见陷阱与注意事项
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);
4. 总结
-
字符指针是操作字符串的核心工具,灵活但需谨慎使用。
-
字符串字面量存储在只读内存区,字符指针指向时不可修改。
-
字符数组(栈或堆内存)可通过指针修改内容。
-
动态分配字符串内存时,必须手动管理生命周期(
malloc
/free
)。 -
始终确保字符串以
\0
结尾,避免越界访问。