前言
在走进的代码世界之前,先领略一下小桥流水美景的诗意世界吧
完了就直接进入正题
一、C语言字符串的手动内存管理
1、C语言无字符串
"hello bit.\n"
这种由双引号(Double Quote)引起来的一串字符称为字符串字面值(String Literal),或者简称字符串。
注:字符串的结束标志是一个 \0 的转义字符。在计算字符串长度的时候 \0 是结束标志,不算作字符串内容。
2、'\0’的重要性
#include <stdio.h>
//下面代码,打印结果是什么?为什么?(突出'\0'的重要性)
int main()
{
char arr1[] = "Hello";
char arr2[] = { 'H', 'e', 'l', 'l', 'o' };
char arr3[] = { 'H', 'e', 'l', 'l', 'o', '\0'};
printf("%s\n", arr1);
printf("%s\n", arr2);
printf("%s\n", arr3);
return 0;
}
在上面的代码运行结果可以看到,我们在输出arr2时出现了乱码形式
思考:为什么会出现这种情况呢?
因为在arr2中并不包含字符串的结束标志即’\0’,所以会出现上面的乱码!
字符串与\0的深度解析
-
当我们用printf()函数以字符串形式进行输出时,只有遇到’\0’才会停止输出
这时候肯定会有码友会问:为什么输出arr1就不会产生乱码? -
因为在 “” 里面的字符串中就已经自动包含了字符串的结束标志即’\0’,所以当我们输出arr1自然就不会产生乱码
-
当我们在使用 {} 字符串的定义的方式时,一定要记得加上字符串的结束标志,否则就会出现乱码现象
小编提醒:一个合格的程序员必备的素养,是对代码的每一处细节严格把控,虽然我们有时候用不到,但这却是我们必须要做的
3、字符串的初始化
| 方式 | 示例 | 说明 |
|---|---|---|
| 直接赋值 | char s[] = "abc"; |
自动计算长度并补 '\0'(长度=4) |
| 指定大小 | char s[5] = "abc"; |
剩余空间填充 '\0'(实际存储 a b c \0 \0) |
| 逐个字符 | char s[4] = {'a','b','c','\0'}; |
必须显式添加 '\0',否则不是合法字符串 |
| 指针 | char *s = "abc"; |
指向只读的字符串常量(不可修改内容) |
4、与字符串相关的格式说明符
在 C 语言中,与字符串相关的格式说明符主要用于输入/输出函数
(1)%s
用途:输入/输出 字符串(以 ‘\0’ 结尾的 char 数组或指针)。
代码示例:
char str[] = "Hello";
printf("%s\n", str); // 输出字符串
scanf("%s", str); // 输入字符串(遇空格停止)
- 注意:
scanf(“%s”, str) 不安全(可能缓冲区溢出),推荐:
scanf("%19s", str); // 限制最大长度(数组大小-1)
- 或使用 fgets:
fgets(str, sizeof(str), stdin); // 更安全(读取一行)
(2)%c
用途:输入/输出 单个字符(char 类型)。
代码示例:
char ch = 'A';
printf("%c\n", ch); // 输出字符 'A'
scanf("%c", &ch); // 输入单个字符(包括空格/换行)
注意:
若需跳过空白字符,加空格:
scanf(" %c", &ch); // 忽略前面的空格/换行
(3)%p
用途:输出 指针的地址(十六进制格式)。
代码示例:
char *ptr = "Hello";
printf("%p\n", (void *)ptr); // 输出指针地址(如 0x55a1b2c3d4e5)
后面我们讲到指针的时候会深度解析
拓展:fgets
fgets 是 C 语言标准库中用于安全读取字符串的重要函数,相比 gets 和 scanf 的 %s,它提供了更好的安全性和控制能力。
最简单的 fgets 使用模板
#include <stdio.h>
int main() {
char buffer[100]; // 定义一个足够大的字符数组
printf("请输入内容: ");
fgets(buffer, sizeof(buffer), stdin); // 读取输入
printf("你输入的是: %s", buffer);
return 0;
}z
关键要点
三个必要参数:
buffer:存储输入的字符数组
sizeof(buffer):最大读取长度(自动计算数组大小)
stdin:表示从标准输入(键盘)读取
自动添加结束符:
fgets 会自动在字符串末尾添加 \0
所以实际读取的字符数 = 指定长度 - 1
拓展:使用fgets的时候,如何去掉换行符
如果用户按了回车,换行符 \n 会被包含在字符串中
示例:输入 “hello” 后按回车,buffer 内容为 “hello\n\0”
这时候我们可以用到头文件<string.h>来去除换行符
头文件<string.h>的讲解篇章在下面
#include <stdio.h>
#include <string.h> // 需要用到 strcspn
int main() {
char buffer[100];
printf("请输入: ");
fgets(buffer, sizeof(buffer), stdin);
// 去除换行符
buffer[strcspn(buffer, "\n")] = '\0';
printf("处理后的输入: %s", buffer);
return 0;
}
(4)其它相关的格式说明符
下面这些说明符虽然功能强大,但是很少被使用,这里我们只是作简单的讲解,感兴趣的朋友可以去了解一下
1. %[…](扫描集)
用途:自定义 scanf 的输入规则。
- 代码示例:
char str[50];
scanf("%[^\n]", str); // 读取一行(直到换行符)
scanf("%[a-z]", str); // 只读取小写字母
- 常见用法:
%[^\n]:读取一行(含空格)。
%[^,]:读取直到逗号。
2. %n
用途:记录已输出的字符数(不消耗参数)。
- 代码示例:
int count;
printf("Hello%nWorld\n", &count); // count = 5("Hello"的长度)
3. %*s(抑制赋值)
用途:跳过输入的字符串。
- 代码示例:
char str[10];
scanf("%*s %s", str); // 跳过第一个单词,读取第二个
二、C语言字符串的库函数
<string.h> 是C语言中处理字符串和内存操作的重要头文件,下面介绍其中最常用的函数,适合初学者掌握核心功能。
由于<string.h>包含很多英文,为了方便大家的记忆,我会将每个英文前置并在后面附上其作用,方便大家的记忆
1、字符串基本操作
(1) strlen(长度计算)
size_t len = strlen(str); // 不计算'\0'
(2) strcpy(复制)
strcpy(char dest[] , const char arc[]); // 可能溢出
- 功能:将src字符串复制到dest字符串
(2.1)strncpy(复制):
strncpy(dest, src, n); // 最多复制n个字符
- 功能:strncpy可以指定最大复制字符数
(3) strcat(连接)
strcat(dest, src); // 可能溢出
(3.1)strncat(连接)
strncat(dest, src, n); // 最多连接n个字符
(4) strcmp(比较)
int strcmp(const char str1[], const char str2[]);
- 功能:比较两个字符串
(4.1)strncmp(比较)
int strncmp(const char str1[], const char str2[], size_t n);
- 功能:指定几个字符进行比较
返回值:
- 0:相等
- 负数:str1小于str2
- 正数:str1大于str2
代码示例:
if(strcmp("apple", "banana") < 0) {
printf("apple在banana前面");
}
2、内存操作函数
(1)memset(内存设置)
void memset(char arr[], int value, size_t num);
- 功能:将arr数组的前num个字节设置为value,常用于初始化数组
代码示例:
char buffer[50];
memset(buffer, 0, 50); // 将buffer全部初始化为0
(2)memcpy(内存复制)
void memcpy(char dest[], const char src[], size_t num);
- 功能:从src数组复制num个字节到dest数组
代码示例:
int src[5] = {1,2,3,4,5};
int dest[5];
memcpy(dest, src, sizeof(src)); // 复制整个数组
3、内存查找函数
(1) strchr(查找字符位置)
int strchr(const char str[], int c);
- 功能:查找字符c在str中第一次出现的位置,返回字符的索引位置,找不到返回-1
代码示例:
int pos = strchr("Hello", 'l'); // pos现在是2
(2) strstr(查找子串位置)
int strstr(const char haystack[], const char needle[]);
- 功能:在haystack中查找needle,返回子串开始的位置索引,找不到返回-1
代码示例:
int pos = strstr("Hello world", "wor"); // pos现在是6
注意事项
使用这些函数时要确保目标数组足够大
字符串必须以’\0’结尾
数组索引从0开始计算
记得包含头文件 #include <string.h>
三、小编附言
为了方便大家的理解,本期的字符串没有附带指针的内容,后续讲指针的时候,会与字符串联系在一起讲
看到这里麻烦给个三连吧