第一部分:char类型与字符串
1.1 char类型基础
⭐ 老师强调 :char类型用于存放单个字符,如
char c = 'A';。字符常量用单引号包裹,这是最基础的字符单元。
char c = 'A'; // 单个字符
char d = 'a'; // 字符常量用单引号
1.2 字符串的本质
⭐ 老师强调 :C语言没有独立的字符串类型 。字符串本质上是以'\0'结尾的char类型数组。'\0'(空字符)是字符串的结束标识,缺了它程序就不知道字符串在哪结束。
// ✅ 字符串:以'\0'结尾的字符数组
char s1[] = "hello"; // 实际存储: h e l l o \0
// 数组长度: 6(5个字符 + 1个'\0')
// ❌ 普通字符数组:没有'\0',不是字符串
char s2[3] = {'a','b','c'}; // 没有结束符,不是字符串
// ✅ 字符数组作为字符串(需手动加'\0')
char s3[4] = {'a','b','c','\0'}; // 是字符串
⭐ 老师强调 :双引号包裹的才是字符串,如
"hello"。单引号包裹的是单个字符,如'a'。字符串末尾隐含一个'\0',定义时需为其预留空间。
内存布局示例:
char s[] = "hello";
| 索引 | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| 内容 | h | e | l | l | o | \0 |
⭐ 老师强调:'\0'不显示但占一个字节,标志字符串终结。可类比成书本末尾的"完"字,没它系统就不知在哪停,会越界读内存。
1.3 字符串定义方式对比
| 写法 | 含义 | 是否字符串 |
|---|---|---|
char c = 'A'; |
单个字符 | ❌ |
char s[3] = {'a','b','c'}; |
字符数组,无结束符 | ❌ |
char s[4] = {'a','b','c','\0'}; |
带结束符的字符数组 | ✅ |
char s[] = "hello"; |
字符串(自动加'\0') | ✅ |
char s[6] = "hello"; |
字符串,长度6正好容纳 | ✅ |
char s[10] = "hello"; |
字符串,多余位置填'\0' | ✅ |
第二部分:字符串的输入输出
2.1 字符串输出
#include <stdio.h>
#include <string.h>
int main() {
char s[] = "hello";
// 方式1:printf + %s
printf("%s\n", s); // 输出 hello,遇到'\0'停止
// 方式2:puts(自动换行)
puts(s); // 输出 hello 并换行
// 方式3:putchar(输出单个字符)
putchar(s[0]); // 输出 h
return 0;
}
⭐ 老师强调 :
printf("%s", s)遇到'\0'自动停止输出。puts()输出字符串后自动换行。putchar()输出单个字符,按下标取元素。
2.2 字符串输入
#include <stdio.h>
int main() {
char s[100];
// 方式1:scanf(遇空格停止)
scanf("%s", s); // 输入 "hello world" → 只读取 "hello"
printf("%s\n", s);
// 方式2:带宽度限制(防溢出)
scanf("%2s", s); // 只读取前2个字符
// 方式3:getchar(读取单个字符)
char c = getchar(); // 读取一个字符
printf("%c\n", c);
// 方式4:scanf读取字符(%c前加空格跳过空白)
scanf(" %c", &c); // 跳过空格、换行等空白字符
return 0;
}
⭐ 老师强调 :
scanf("%s")遇到空格、换行、Tab键 会立即停止,只能读取连续的非空白内容。输入"hello world"只会拿到"hello"。可用宽度限定如%2s限制最大长度,防止缓冲区溢出。
字符输入注意事项:
// ❌ 问题:%c会读取上次输入残留的换行符
scanf("%c", &c); // 可能读到'\n'
// ✅ 解决:%c前加空格跳过空白字符
scanf(" %c", &c); // 忽略前导空白
第三部分:str系列函数
3.1 头文件
⭐ 老师强调 :使用str系列函数必须包含头文件
#include <string.h>,否则编译报错。
#include <string.h> // 必须包含
3.2 strcmp ------ 字符串比较
⭐ 老师强调 :字符串比较不能用
==运算符(比较的是地址),必须用strcmp()比较内容。
#include <stdio.h>
#include <string.h>
int main() {
char a[] = "hello";
char b[] = "world";
// 方式1:使用strcmp
if (strcmp(a, b) == 0) {
printf("a == b\n");
} else if (strcmp(a, b) > 0) {
printf("a > b\n");
} else {
printf("a < b\n");
}
return 0;
}
strcmp返回值:
| 返回值 | 含义 |
|---|---|
0 |
两字符串相等 |
> 0 |
前者大于后者 |
< 0 |
前者小于后者 |
⭐ 老师强调 :
strcmp按字典序比较,逐字符比较ASCII码值。
3.3 strcpy ------ 字符串复制
⭐ 老师强调 :数组名是常量指针,不能被赋值,不能直接用
a = b。必须用strcpy(dest, src)复制内容。
#include <stdio.h>
#include <string.h>
int main() {
char a[20] = "hello";
char b[] = "world";
// ❌ 错误:数组名不能赋值
// a = b; // 编译报错
// ✅ 正确:使用strcpy
strcpy(a, b); // 把b复制到a
printf("%s\n", a); // 输出 world
return 0;
}
⭐ 老师强调 :
strcpy(dest, src)将src的内容复制到dest,包括末尾的'\0'。确保dest空间足够大。
3.4 strcat ------ 字符串拼接
#include <stdio.h>
#include <string.h>
int main() {
char a[20] = "hello";
char b[] = "world";
// 拼接:在a末尾追加b
strcat(a, b);
printf("%s\n", a); // 输出 helloworld
return 0;
}
3.5 strlen ------ 字符串长度
⭐ 老师强调 :
strlen()计算字符串有效字符个数,不包含'\0'。
#include <stdio.h>
#include <string.h>
int main() {
char s[] = "hello";
// 方式1:strlen函数
int len = strlen(s); // len = 5(不包含'\0')
printf("长度: %d\n", len);
// 方式2:手动遍历
int len2 = 0;
for (int i = 0; s[i] != '\0'; i++) {
len2++;
}
printf("手动计算: %d\n", len2);
return 0;
}
⭐ 老师强调 :
strlen与sizeof不同------strlen算有效字符数(不含'\0'),sizeof算数组占用的总字节数(含'\0')。
| 表达式 | 结果("hello") | 说明 |
|---|---|---|
strlen(s) |
5 | 有效字符数,不含'\0' |
sizeof(s) |
6 | 数组总大小,含'\0' |
第四部分:字符串遍历
4.1 遍历方式
#include <stdio.h>
#include <string.h>
int main() {
char s[] = "hello";
// 方式1:用'\0'判断结束
for (int i = 0; s[i] != '\0'; i++) {
printf("%c\n", s[i]);
}
// 方式2:用strlen获取长度
int len = strlen(s);
for (int i = 0; i < len; i++) {
printf("%c\n", s[i]);
}
return 0;
}
⭐ 老师强调 :遍历字符串的两种方式------用
'\0'判断结束,或用strlen获取长度后循环。前者更通用,后者更直观。
第五部分:字符串反转(双指针法)
5.1 核心思路
⭐ 老师强调 :字符串反转的本质是交换对称位置的字符。用双指针:left从0开始,right指向末尾字符(长度-1),两指针相向而行,交换所指字符,直到相遇或交叉。
反转过程图示:
原始: h e l l o
↑ ↑
left right → 交换h和o → o e l l h
o e l l h
↑ ↑
left right → 交换e和h → o h l l e
o h l l e
↑
left/right → 相遇,停止
结果: o l l e h
5.2 完整代码
#include <stdio.h>
#include <string.h>
// 字符串反转函数
void reverse(char str[]) {
int len = strlen(str);
int left = 0;
int right = len - 1; // 指向最后一个有效字符,不是'\0'
while (left < right) {
// 交换左右字符
char temp = str[left];
str[left] = str[right];
str[right] = temp;
// 指针向中间移动
left++;
right--;
}
}
int main() {
char s[] = "hello";
printf("反转前: %s\n", s);
reverse(s);
printf("反转后: %s\n", s); // 输出 olleh
return 0;
}
5.3 手动实现strlen
// 不调用strlen,手动计算长度
int my_strlen(char str[]) {
int len = 0;
for (int i = 0; str[i] != '\0'; i++) {
len++;
}
return len;
}
// 反转时用自定义长度
void reverse_manual(char str[]) {
int len = my_strlen(str); // 不依赖库函数
int left = 0;
int right = len - 1;
while (left < right) {
char temp = str[left];
str[left] = str[right];
str[right] = temp;
left++;
right--;
}
}
⭐ 老师强调 :反转时**'\0'不参与运算**,它是字符串结束符,不能放进指针范围。
right应指向len - 1(最后一个有效字符),而非len(指向'\0')。循环条件left < right,一旦相遇或交叉必须停止。
易错点:
// ❌ 错误:right指向了'\0'
int right = strlen(str); // 指向'\0'
while (left < right) { ... } // 会把'\0'交换到前面
// ✅ 正确:right指向最后一个有效字符
int right = strlen(str) - 1;