指针与字符串:字符串指针、字符数组与字符串指针的区别、字符串常量
字符串在C语言里,其实是个挺有意思的话题。很多初学者刚接触时,总觉得字符数组和字符串指针差不多,用起来也没啥区别。嗯,我当年也这么想过。直到有一次在项目里,我因为没搞清楚这俩的区别,把一个字符串常量给改了,结果程序跑着跑着就崩了……从那以后,我再也不敢小看这个知识点了。
今天咱们就把这块彻底捋清楚。说白了,字符串在C语言里就是字符的序列,末尾带个'\0'。但怎么存、怎么用,这里面的门道可不少。
1. 字符串的两种存储方式
C语言里没有专门的字符串类型。我们通常用两种方式来表示字符串:字符数组和字符指针。
先看个例子:
char str1[] = "Hello"; // 字符数组
char *str2 = "Hello"; // 字符串指针
这两行代码看起来差不多,但底层差别很大。我刚开始学的时候,也觉得不就是存个"Hello"嘛,有啥区别?后来踩了坑才明白——区别大了去了。
字符数组
str1是一个数组,它在栈上分配了6个字节的空间(5个字符 + 1个'\0')。数组的内容是可以修改的。比如:
str1[0] = 'h'; // 合法,可以修改
字符串指针
str2是一个指针,它指向一个字符串常量。"Hello"这个字符串常量存储在代码段(或只读数据段)中。你想想看,既然是只读的,那能不能改?
str2[0] = 'h'; // 危险!未定义行为,很可能崩溃
2. 字符数组 vs 字符串指针:核心区别
我把它们的区别整理成了一张表,方便你对照着看:
| 对比项 | 字符数组 | 字符串指针 |
|---|---|---|
| 存储位置 | 栈(或全局区) | 指针在栈,字符串在只读区 |
| 是否可修改 | 可以修改内容 | 不能修改(只读) |
| sizeof 结果 | 数组实际大小(含'\0') | 指针本身大小(4或8字节) |
| 赋值方式 | 不能整体赋值(只能用strcpy) | 可以指向另一个字符串 |
| 生命周期 | 作用域内有效 | 指针可能指向常量,一直有效 |
我个人习惯是:如果字符串需要修改,就用字符数组;如果只是读取,用字符串指针更灵活。你想想看,指针可以随时指向另一个字符串,而数组不行——数组一旦定义,地址就固定了。
3. 字符串常量
字符串常量,就是用双引号括起来的一串字符,比如"Hello"。它在程序编译时就被确定下来,存储在只读内存区域。
这里有个细节:相同的字符串常量,编译器可能会优化成同一个地址。什么意思呢?
char *p1 = "Hello";
char *p2 = "Hello";
if (p1 == p2) {
printf("指向同一个地址\n");
}
这段代码在很多编译器上会输出"指向同一个地址"。因为编译器觉得既然内容一样,没必要存两份。嗯,这个优化有时候会让人迷惑,但你要知道有这么回事就行。
strcmp(),不要用 == 比较指针。== 比较的是地址,不是内容。这个坑我见过不少人踩过。
4. 字符串指针的常见用法
字符串指针在实际项目中用得很多。比如遍历字符串:
char *str = "Embedded";
while (*str != '\0') {
putchar(*str);
str++; // 指针后移
}
这段代码会逐个字符打印出来。指针的移动,说白了就是地址的加减。每移动一次,就指向下一个字符。直到遇到'\0',循环结束。
再比如,用指针数组来处理多个字符串:
char *days[] = {"Mon", "Tue", "Wed", "Thu", "Fri"};
for (int i = 0; i < 5; i++) {
printf("%s\n", days[i]);
}
这种方式比二维字符数组灵活得多。每个字符串的长度可以不一样,而且修改指针指向比拷贝整个字符串快得多。我在嵌入式项目里经常用这种结构来管理菜单或状态字符串。
5. 避坑指南
最后,我总结几个常见的坑,都是我曾经遇到过或者帮别人排查过的:
- 不要用
scanf("%s", str)读入字符串指针——指针没有分配空间,读入的数据没地方放,会覆盖未知内存。我见过有人这么写,程序直接崩了。 - 字符数组做函数参数时,会退化为指针——所以在函数里用
sizeof得到的是指针大小,不是数组大小。这个我之前也讲过,一定要记住。 - 字符串常量不能修改——前面已经强调过了,再重复一遍:别去改它。
- 用
strcpy时确保目标数组足够大——否则会缓冲区溢出。嵌入式系统里,这个错误可能导致严重的安全漏洞。
核心要点回顾:
- 字符数组可修改,字符串指针指向只读区
- sizeof 对数组和指针的结果不同
- 字符串常量可能被编译器共享地址
- 比较字符串内容用 strcmp,不要用 ==
- 指针数组比二维字符数组更灵活
好了,关于指针与字符串的基础内容就这些。理解清楚字符数组和字符串指针的区别,后面再学字符串处理函数、指针数组这些内容就会轻松很多。嗯,这块内容虽然基础,但真的很重要——我见过太多人在这个上面栽跟头了。