六、C语言字符串与字符

思维导图


一、 字符与转义字符

1.1 字符的本质是整数

在计算机眼里,'A' 只是一个数字 65
char 类型通常占用 1 个字节(8 bits),范围是 -128 到 127。

代码示例:

c 复制代码
char c = 'A';
printf("字符: %c\n", c);  // 输出 A
printf("ASCII: %d\n", c); // 输出 65

// 字符运算
char next = c + 1;
printf("下一个: %c\n", next); // 输出 B

1.2 转义字符

有些字符看不见(如换行),或者有特殊含义(如双引号),需要用反斜杠 \ 来转义。

转义符 含义
\n 换行
\t 制表符,用于对齐
\\ 反斜杠本身
\' 单引号(在字符常量中用)
\" 双引号(在字符串中用)
\0 空字符,字符串结束标志

二、 C 字符串的存储规则

2.1 核心规则:以 \0 结尾

C 语言没有记录字符串的长度。它怎么知道字符串在哪里结束?

答案: 只要遇到 ASCII 值为 0 的字符 \0,就认为结束了。

声明与初始化:

c 复制代码
// 写法 1:逐个字符,必须手动加 \0,否则打印乱码
char s1[] = {'H', 'e', 'l', 'l', 'o', '\0'}; 

// 写法 2:字符串字面量(编译器自动加 \0)
char s2[] = "Hello"; 

// 内存视角:
// s2 占用了 6 个字节:'H' 'e' 'l' 'l' 'o' '\0'

2.2 数组 vs 指针

代码对比:

c 复制代码
// 1. 字符数组:内容存放在栈上,可以随意修改
char str[] = "Hello";
str[0] = 'X'; // 合法,变成 "Xello"

// 2. 字符串指针:指向只读数据区(常量区)
char *ptr = "Hello";
// ptr[0] = 'X'; // 崩溃!Segfault (非法写入)

三、 常用字符串函数

3.1 strlen:计算长度

功能: 计算字符串的有效长度,不包括 \0
注意: 它需要从头走到尾数数,时间复杂度 O(N)。不要在循环条件里调用它!

手写 strlen:

c 复制代码
size_t my_strlen(const char *s) {
    size_t len = 0;
    while (s[len] != '\0') { // 只要没遇到结束符
        len++;
    }
    return len;
}

3.2 strcpy / strncpy:复制

strcpy(dst, src):把 src 的内容(含 \0)拷给 dst。

风险: 如果 dst 空间不够,会发生 缓冲区溢出。

推荐: strncpy(dst, src, n),限制拷贝 n 个字符。但要注意 strncpy 可能不补 \0,需要手动补。

3.3 strcmp:比较

错误写法: if (s1 == s2) ------ 这比的是 地址,不是内容!
正确写法: if (strcmp(s1, s2) == 0) ------ 相等返回 0。

3.4 strcat:拼接

strcat(dst, src):把 src 接到 dst 后面。
前提: dst 必须有 足够 的剩余空间容纳 src。

四、 字符串输入的坑与解决

4.1 scanf("%s") 的缺陷

  1. 遇空格即停: 输入 "Hello World",只能读到 "Hello"。 2. 不检查边界: 极易导致 溢出。

危险代码:

c 复制代码
char buf[10];
scanf("%s", buf); // 输入 "ThisIsTooLong",程序崩溃或被黑客利用

4.2 fgets:更安全的替代者

语法: fgets(buf, size, stdin);

优点:

1.限制读取大小(最多 size-1 个),绝对安全。

2.可以读取 空格。

缺点: 会把 \n 也读进去(如果空间够的话)。

最佳实践模板:

c 复制代码
char buf[100];
printf("请输入:");

if (fgets(buf, sizeof(buf), stdin)) {
    // 处理末尾的换行符
    size_t len = strlen(buf);
    if (len > 0 && buf[len-1] == '\n') {
        buf[len-1] = '\0'; // 替换为结束符
    }
    printf("你输入了: %s\n", buf);
}

五、 练习题

题目 1: char s[10] = "abc";sizeof(s)strlen(s) 分别是多少?

题目 2: char s[] = "abc"; 这个数组实际占用了几个字节?

题目 3: 为什么不能用 if (str == "hello") 来判断字符串内容?

题目 4: 下面代码输出什么?

c 复制代码
char s[] = "A\0B";
printf("%d", strlen(s));

题目 5: strcpymemcpy 最大的区别是什么?

题目 6: 使用 fgets 读取输入时,如果用户输入的字符数少于缓冲区大小,字符串末尾通常会有什么字符?

题目 7: 字符 '0' 和整数 0 有什么区别?

题目 8: 什么是 缓冲区溢出(Buffer Overflow)?为什么它很危险?

题目 9: 编写一个函数 my_strcpy,实现字符串复制。

题目 10: char *p = "Hello"; p[0] = 'h'; 这行代码会发生什么?

题目 11: 如何将字符串 "123" 转换为整数 123?

题目 12: 下面代码有没有问题?

c 复制代码
char s[5];
strcpy(s, "Hello");

题目 13: 在 C 语言中,字符串常量(如 "Hello")通常存储在哪个内存区域?

题目 14: 为什么说在循环条件中写 i < strlen(s) 是低效的?

题目 15: 给定 char a[] = "Hi"; char b[] = "Hi";,表达式 a == b 的结果是真还是假?

六、 解析

题 1 解析
答案: sizeof 是 10,strlen 是 3。
详解:

sizeof 看的是开辟的 总空间;strlen 看的是 \0 前面有多少个字符。

题 2 解析
答案: 4 字节。
详解:

'a', 'b', 'c', '\0'。编译器自动加结束符。

题 3 解析
答案: 比较的是 地址。
详解:

str 是数组首地址,"hello" 是常量区地址。这两个地址 永远不可能相等。必须用 strcmp

题 4 解析
答案: 1。
详解:

strlen 遇到第一个 \0 就停止计数。后面的 'B' 被忽略了。

题 5 解析
答案: 停止条件不同。
详解:

strcpy 遇到 \0 停止;memcpy 严格按照指定的字节数拷贝,不管内容是什么。

题 6 解析
答案: 换行符 \n
详解:

fgets 会把用户按下的回车键也存入缓冲区(只要空间足够)。

题 7 解析
答案:

'0' 的 ASCII 码是 48;整数 0 的值是 0(也就是 \0)。

题 8 解析
答案:

向缓冲区写入了超过其容量的数据,覆盖了相邻的内存(如返回地址)。黑客可利用此漏洞执行恶意代码。

题 9 解析
答案:

c 复制代码
char *my_strcpy(char *dest, const char *src) {
    char *ret = dest;
    while ((*dest++ = *src++));
    return ret;
}

题 10 解析
答案: 运行时错误 (Segfault)。
详解:

"Hello" 存储在 只读常量区,试图修改会导致硬件保护异常。

题 11 解析
答案: atoi("123")sscanf

题 12 解析
答案: 有问题(越界)。
详解:

"Hello" 需要 6 个字节(含 \0),而 s 只有 5 个。\0 会写到 s 的外面。

题 13 解析
答案: 只读数据段 (Text Segment / .rodata)。

题 14 解析
答案:

strlen 需要遍历字符串。如果放在循环条件里,每次循环都要遍历一次,时间复杂度从 O(N) 变成 O(N^2)。

题 15 解析
答案: 假。
详解:

ab 是两个独立的数组,它们在栈上的地址不同。

日期:2025年2月11日

专栏:C语言

相关推荐
RuoZoe3 天前
重塑WPF辉煌?基于DirectX 12的现代.NET UI框架Jalium
c语言
祈安_6 天前
C语言内存函数
c语言·后端
郑州光合科技余经理8 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
feifeigo1238 天前
matlab画图工具
开发语言·matlab
dustcell.8 天前
haproxy七层代理
java·开发语言·前端
norlan_jame8 天前
C-PHY与D-PHY差异
c语言·开发语言
多恩Stone8 天前
【C++入门扫盲1】C++ 与 Python:类型、编译器/解释器与 CPU 的关系
开发语言·c++·人工智能·python·算法·3d·aigc
QQ4022054968 天前
Python+django+vue3预制菜半成品配菜平台
开发语言·python·django
czy87874758 天前
除了结构体之外,C语言中还有哪些其他方式可以模拟C++的面向对象编程特性
c语言
遥遥江上月8 天前
Node.js + Stagehand + Python 部署
开发语言·python·node.js