指针与字符串:字符串指针、字符数组与字符串指针的区别、字符串常量

字符串在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,不要用 ==
  • 指针数组比二维字符数组更灵活

好了,关于指针与字符串的基础内容就这些。理解清楚字符数组和字符串指针的区别,后面再学字符串处理函数、指针数组这些内容就会轻松很多。嗯,这块内容虽然基础,但真的很重要——我见过太多人在这个上面栽跟头了。

指针与字符串 · 知识结构图 字符串在C语言中 字符数组 栈上分配,可修改 sizeof = 数组实际大小 不能整体赋值 字符串常量 只读数据段/代码段 不可修改 可能被编译器共享地址 字符串指针 指针在栈,指向只读区 sizeof = 指针大小(4/8) 可指向不同字符串 核心:字符数组可改,字符串常量只读,指针指向常量
公众号:蓝海资料掘金营,微信 deep3321