字符数组与字符串:别把数组和字面量搞混了

说实话,我刚学C语言那会儿,最头疼的就是字符数组和字符串字面量。明明看起来差不多,用起来却总出幺蛾子。有一次我写了个简单的登录程序,用==比较两个字符串,结果死活不相等——嗯,后来才知道,那是在比地址,不是在比内容。

今天咱们就把这块彻底捋清楚。

字符数组 vs 字符串字面量

先看个例子:

char str1[] = "Hello";      // 字符数组
char *str2 = "Hello";       // 字符串字面量

这两行代码,表面上看都是存了个"Hello",但底层完全不一样。

对比项 字符数组 字符串字面量
存储位置 栈区(可修改) 常量区(只读)
能否修改内容 可以 不行!会崩溃
变量类型 数组名,是地址常量 指针,指向常量区
sizeof结果 整个数组大小(含'\0') 指针本身大小(4或8字节)
⚠️ 我曾经踩过的坑:char *p = "abc"; p[0] = 'x'; 试图修改字符串字面量。程序直接段错误。记住,字符串字面量是只读的,想修改就用字符数组。

字符串的输入:gets 和 fgets

输入字符串,最原始的办法是 scanf("%s", str)。但有个致命问题——它遇到空格就停了。你输入"Hello World",它只读到"Hello"。

所以大家更常用 getsfgets

gets —— 简单但危险

char buf[10];
gets(buf);  // 如果输入超过9个字符,直接溢出

gets 不检查缓冲区大小。我见过一个老项目,就因为 gets 导致缓冲区溢出,被黑客利用执行了恶意代码。所以,永远不要在生产代码里用 gets。C11标准已经把它删掉了。

fgets —— 我推荐你用这个

char buf[10];
if (fgets(buf, sizeof(buf), stdin)) {
    // 安全!最多读 sizeof(buf)-1 个字符
}

fgets 有三个参数:目标缓冲区、最大读取长度、文件流。它会在末尾自动加 '\0',而且不会溢出。

💡 我个人习惯: 用 fgets 时,第二个参数直接写 sizeof(buf),别写死数字。这样以后改缓冲区大小,代码也不用改。

不过 fgets 有个小特点——它会保留换行符。比如你输入"abc\n",buf 里存的是 "abc\n\0"。如果你不想要这个换行,可以手动去掉:

size_t len = strlen(buf);
if (len > 0 && buf[len-1] == '\n') {
    buf[len-1] = '\0';
}

字符串的输出:puts

输出字符串,printf("%s", str) 当然可以。但如果你只是单纯想输出一行字符串,puts 更简洁:

char str[] = "Hello";
puts(str);  // 自动加换行

puts 会自动在末尾加一个 '\n'。它内部其实调用了 fputs(str, stdout) 再加换行。

📌 核心区别:
  • puts(str) 等价于 printf("%s\n", str)
  • fputs(str, stdout) 等价于 printf("%s", str) —— 不加换行

知识体系图

下面这张图,帮你把本章的核心逻辑串起来:

字符数组与字符串处理 字符数组 字符串字面量 可修改内容 只读,不可修改 输入:gets(危险)、fgets(安全) 输出:puts、fputs 核心原则:能修改用数组,只读用字面量

完整示例:综合运用

#include <stdio.h>
#include <string.h>

int main() {
    char name[20];
    char greeting[50];
    
    printf("请输入你的名字:");
    fgets(name, sizeof(name), stdin);
    
    // 去掉换行符
    size_t len = strlen(name);
    if (len > 0 && name[len-1] == '\n') {
        name[len-1] = '\0';
    }
    
    // 拼接字符串
    strcpy(greeting, "你好,");
    strcat(greeting, name);
    strcat(greeting, "!欢迎学习C语言。");
    
    puts(greeting);  // 输出:你好,XXX!欢迎学习C语言。
    
    return 0;
}
💡 我建议: 实际项目中,字符串操作尽量用 strncpystrncat 这类带长度限制的函数,别用 strcpystrcat。安全第一。

好了,字符数组和字符串的基本操作就这些。你想想看,其实核心就两点:能不能改,以及安不安全。记住这两个维度,以后遇到字符串相关的问题,心里就有底了。


公众号:蓝海资料掘金营,微信deep3321