青江的个人站

“保持热爱,奔赴星海”

  • 主页
  • 目录
  • 图床
  • 留言板
  • -关于我-
友链 搜索文章 >>

青江的个人站

“保持热爱,奔赴星海”

  • 主页
  • 目录
  • 图床
  • 留言板
  • -关于我-

【C语言学习笔记】十、字符串


阅读数: 0次    2026-01-10
字数:5.7k字 | 预计阅读时长:23分钟

1. 字符串

C语言中字符串的处理是非常重要的。

可以使用char直接定义一个单个字符,使用单引号('')初始化,用%c可以将单个字符输出:

1
2
char c = 't';
printf("%c\n", c);

字符串本质上来说是一个由字符组成的数组,类型是char[],字符串可以储存由多个字符组成的字符序列,用大括号加双引号({""})或直接用双引号("")初始化,用%s可以将字符串输出,直接传入数组名即可:

1
2
char str[] = "Hello";	// 实际的字符数组:{'H', 'e', 'l', 'l', 'o', '\0'}
printf("%s\n", str);

C语言中,字符串的结尾必定是\0,如果结尾丢失\0,会导致意料之外的问题。

1
2
3
4
5
char str1[6] = "Hello";	// 正确,数组长度足以存储字符串和终止符
printf("%s\n", str1); // 输出:Hello

char str2[5] = "Hello"; // 错误,数组长度不足以存储字符串和终止符
printf("%s\n", str2); // 输出(未定义行为):Hello�����������������������

因此定义字符串时一般不会显式指定字符数组的长度,应该使用和数组类似的特性,直接让编译器自行计算长度,这样可以防止手动计算出错。

微软在处理字符串问题时,推荐使用带_s后缀的函数,例如对于字符串读取,微软推荐使用scanf_s而不是scanf,这种新的函数对字符串有特殊处理,可以避免出现字符串的未定义行为。

字符串也可以使用指针定义,与数组的指针类似,字符串的指针可以理解为指向字符数组中第一个字符的指针。

指针定义的字符串同样可以使用%s输出,但输出时与其他类型的指针不同,不需要有解引用符(*),直接将指针传入即可。

1
2
char* ptr_str = "Hello!"; // 指向字符串常量的指针
printf("%s\n", ptr_str);

需要注意的是,使用指针定义的字符串,其指针指向的是字符串常量,因此不可以修改单个字符,强制修改会导致未定义行为,且编译器不会显式报错,非常危险。

1
ptr_str[0] = 'h'; // 未定义行为,字符串常量不可修改,可能会导致程序崩溃

想要修改指针定义的字符串时,只能直接修改指针,使其直接指向另一个字符串常量:

1
ptr_str = "world!";	// 指针可以指向另一个字符串常量

一般情况下,字符串定义后不会再进行修改,因此字符串会定义为const常量字符数组类型,或者在定义指针字符串的时候显式写上const关键字。

1
2
const char str[] = "Hello";
const char* ptr_str = "Hello";

这样定义的话,修改字符串中的某个字符时,编译器会显式报错,更为安全。

如果不加const常量类型,使用字符数组定义的字符串可以直接单独修改其中的字符。

1
str[0] = 'h';

此外,如果定义字符指针指向定义好的指针数组,通过指针可以实现字符的修改,这个与其他类型的数组类似。

1
2
3
char str[] = "Hello";
char* ptr_str = str;
ptr_str[0] = 'h'; // 修改指针指向的内容

同样也可以使用这个特性结合指针加法遍历字符串数组:

1
2
3
4
5
6
7
char str[] = "Hello";
char* ptr_str = str;

while (*ptr_str != '\0'){
printf("%c\n", *ptr_str);
ptr_str++;
}

因此,如果想要定义一个需要修改的字符串,应该使用字符数组来定义,要么隐式定义,要么定义的数组长度应满足最大长度要求。

当字符数组的长度大于有效值时,字符串的结尾以及其他无效字符均为\0。

如果想要定义一个不需要修改的字符串,可以使用const指针定义,也可以定义为const常量类型的字符数组,在修改时会有明显的报错,可读性更强。

2. strcpy_s的用法

常用的字符串处理函数包含在一个C语言自带的头文件string.h中,使用时需要包含头文件。

strcpy_s用于将一个字符串复制到另一个字符串当中。

传入的参数中,最后面的是源字符串,最前面的是目标字符串,中间需要传入想要复制的字符串的大小。例如:

1
2
3
4
5
const char src[] = "Hello";
char dest[20];
strcpy_s(dest, sizeof(dest), src);
printf("src = %s\n", src);
printf("dest = %s\n", dest);

这个函数保证了字符串复制不会出现溢出的情况,如果源字符串长度大于要复制的长度,程序运行时会直接报错。

3. VS编译器捕获字符串异常

通过点击strcpy_s查看源码,可以发现此函数有一个类型为errno_t的返回值,在较为规范的程序中可以通过返回值判断函数运行是否异常,从而进行异常的捕获与处理。

在面向对象的语言中,对于异常捕获可以使用专门的try...catch,C语言中想要捕获异常,需要手动写一个异常处理函数,并在main函数中设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <crtdbg.h>

void my_invalid_param_handler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t p_reserved) {
wprintf(L"Invalid parameter detected in function %s. File: %s Line: %d\n", function, file, line);
wprintf(L"Expression: %s\n", expression);
// 可以选择终止程序或其他处理方式
}

// C语言案例
int main(void) {
// 设置无效参数处理程序
_set_invalid_parameter_handler(my_invalid_param_handler);

const char src[] = "Hello";
char dest[20];
// 故意传入错误的大小参数以触发无效参数处理程序
errno_t err = strcpy_s(dest, 2, src);

if (err != 0) {
printf("strcpy_s failed with error code: %d\n", err);
} else {
printf("src = %s\n", src);
printf("dest: %s\n", dest);
}

return 0;
}

需要注意的是,设置无效参数处理程序之后,如果直接运行代码,依然会弹出报错,这是因为Visual Studio在Debug模式下CRT(C Runtime Library)会额外触发断言,导致出现弹窗报错。

需要将程序的生成模式切换到Release模式,或者在Debug模式下在main函数中手动禁用断言弹窗:

1
2
3
4
#ifdef _DEBUG
_CrtSetReportMode(_CRT_ASSERT, 0);
_CrtSetReportMode(_CRT_ERROR, 0); // 可选:同时禁用错误报告
#endif

设置之后,程序捕获到的错误码就会被打印出来。

4. strlen

strlen函数专门用于计算字符串的长度。

传入想要计算长度的字符串即可,在遇到\0时结束计算,不会将\0包含在内,返回size_t类型的值。

1
2
char str[50] = "Hello";
printf("%zu\n", strlen(str)); // 输出:5

但这样写有可能会有警告出现,因为strlen函数并没有检查字符串溢出的功能。

微软建议字符串初始化时统一初始化为0,然后使用strcpy_s函数对字符串安全赋值,赋值后的字符串再使用strlen函数计算长度时就没有警告了。

1
2
3
char str[50] = { 0 };
strcpy_s(str, sizeof(str), "Hello");
printf("%zu\n", strlen(str));

5. strcat_s

strcat_s用于拼接字符串。

如果想要将字符串2拼接到字符串1上,传入的参数中,最前面的是字符串1,会被拼接修改,得到拼接后的字符串,最后面的是字符串2,不会被修改,中间需要传入字符串1的总长度。

1
2
3
4
5
char str[13] = "Hello";
const char* str1 = " World!";

strcat_s(str, sizeof(str), str1);
printf("%s\n", str);

如果被拼接的字符串的剩余长度不足以容纳需要拼接的字符串,程序会出现运行时弹窗报错。

6. sprintf_s

与printf类似,sprintf_s是专属于字符串的格式化输出。

第一个参数传入字符串,第二个参数传入这个字符串的长度,后面的内容与printf函数类似。

sprintf_s会将格式化输出的内容统一解析并格式化为字符串,并存到传入的字符串中。

sprintf_s会返回一个值,当这个值大于0时,则字符串格式化写入成功,否则写入字符串失败。

1
2
3
4
5
6
7
8
9
10
11
12
13
char buffer[50] = { 0 };
int number = 3;
double pi = 3.14159;

int ret = sprintf_s(buffer, sizeof(buffer), "Integer = %d, Double = %.2f", number, pi);

if (ret > 0) {
printf("Formatted string: %s\n", buffer);
}
else
{
printf("Error Formatting string!\n");
}

如果需要写入的字符串长度大于第一个参数中的字符串长度,则会出现运行时报错的弹窗。

7. strncpy_s

strncpy_s的作用与strcpy_s类似,都是复制字符,不同的是,strncpy_s需要多传入一个参数,用于限制最大复制的连续字符数(不包括\0和它后面的字符)。

也就是如果设置最大复制的字符数为n,则真正复制的是源字符串的不多于前n个字符,到\0停止复制。

函数返回一个errno_t类型的值,如果这个值等于0,则字符串拷贝成功,否则字符串拷贝失败。

1
2
3
4
5
6
7
8
9
10
11
12
13
char dest[20];
const char* src = "Hello,World!\n";

rsize_t max_copy = 10;

errno_t result = strncpy_s(dest, sizeof(dest), src, max_copy);

if (!result) {
printf("Copied string: %s\n", dest);
}
else {
printf("Error Copying string!\n");
}

8. strncat_s

与上一节类似,strncat_s比strcat_s多了一个参数,限制函数最多追加多少个字符(不包括\0和其后面的字符)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
char dest[20] = { 0 };
strcpy_s(dest, sizeof(dest), "Hello");
const char* src = ",World!\n";

rsize_t max_append = 5;

errno_t result = strncat_s(dest, sizeof(dest), src, max_append);

if (!result) {
printf("Concatenated string: %s\n", dest);
}
else {
printf("Error concatenating string!\n");
}

9. gets_s

gets_s在功能上与scanf_s类似,都是获取用户的输入,并将其存到一个变量中,但如果用户输入的是纯字符串,应当优先使用gets_s。

gets_s需要传入两个参数,第一个是待存入的字符串,第二个是这个字符串的长度,避免缓冲区溢出。

标准写法是加一个if条件判断,当gets_s的返回值为NULL时,读取输入错误,否则读取用户输入成功。

1
2
3
4
5
6
7
8
9
char buffer[50];

printf("Please enter a string: ");
if (gets_s(buffer, sizeof(buffer)) == NULL) {
printf("Error or end of file encountered.\n");
}
else {
printf("You entered: %s\n", buffer);
}

当输入的长度大于传入的字符串长度时,同样会出现运行时弹窗报错。

10. strtok_s

strtok_s用于按照要求分解字符串,并返回指向下一个子字符串的指针。

需要传入三个变量,第一个是需要分割的字符串,第二个是分隔符(分割要求),第三个是一个二级指针,用于在连续调用这个函数时保存其状态。

当第一个字符串传入NULL时,strtok_s会认为需要继续之前的拆分工作,拆分前面第一次调用它时传入的字符串。

1
2
3
4
5
6
7
8
9
10
char str[] = "This is a sample string";	// 可修改的字符串
char delimiter[] = " "; // 分隔符
char* token; // 用于存储每个分割出的子字符串
char* context = NULL; // 上下文指针,用于保存strtok_s函数在其内部位置的状态

token = strtok_s(str, delimiter, &context); // 获取第一个子字符串
while (token != NULL) { // 循环直到没有更多子字符串
printf("Token: %s\n", token);
token = strtok_s(NULL, delimiter, &context); // 获取下一个子字符串
}

由于第三个参数需要传入一个二级指针,因此定义的时候定义为指针,传入的时候还需要再加一个取地址符。

11. strcmp

前面学过的函数中,只有strlen没有_s的写法,但strlen的功能只是拿到字符串的长度,其他但凡涉及到字符串的修改,都应当使用更为安全的_s版函数。

下面几个要介绍的函数不涉及到字符串的修改,因此没有_s。

strcmp用于比较两个字符串,参数中传入需要比较的两个字符串,返回值是一个int类型的数据,当返回值为0时,两个传入的字符串相同,否则不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const char* str1 = "Hello, World!";
const char* str2 = "Hello, World!";
const char* str3 = "Hello, Guys!";

if (strcmp(str1, str2) == 0) {
printf("str1 and str2 are equal: %s\n", str1);
} else {
printf("str1 and str2 are not equal.\n");
}

if (strcmp(str1, str3) == 0) {
printf("str1 and str3 are equal: %s\n", str1);
} else {
printf("str1 and str3 are not equal.\n");
}

事实上,strcmp对比两个字符串时,会逐个字符通过减法比较其ASCII值的大小,直到找到ASCII值不同的两个对应字符,当str1中这个字符的ASCII值大于str2,则函数返回值大于0,否则函数的返回值小于0。

12. strncmp

strncmp是在strcmp的基础上限制比较前多少个字符。

第三个参数传入size_t类型的数据,限制比较的字符数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const char* str1 = "Hello, World!";
const char* str2 = "Hello, Guys!";

size_t num1 = 7;
size_t num2 = 8;

if (strncmp(str1, str2, num1) == 0) {
printf("str1 and str2 are equal up to the first %zu characters.\n", num1);
} else {
printf("str1 and str2 are NOT equal up to the first %zu characters.\n", num1);
}

if (strncmp(str1, str2, num2) == 0) {
printf("str1 and str2 are equal up to the first %zu characters.\n", num2);
} else {
printf("str1 and str2 are NOT equal up to the first %zu characters.\n", num2);
}

13. strchr与strrchr

strchr与strrchr用于寻找字符串中的某一个字符,strchr是从前往后找,strrchr是从后往前找,也就是一个字符串从前往后看时,strchr找到的是某一个字符第一次出现的位置,strrchr找到的是某一个字符最后出现的位置。

strrchr多出来的那个r代表reverse,从字符串的末尾开始查找。

第一个参数传入需要寻找字符的字符串,第二个参数传入需要寻找的字符,函数返回一个char*类型的指针,指向找到的那个字符,如果没有找到,返回NULL。

拿到指针后,可以使用指针的加减法输出这个字符在字符串中的位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const char* str = "Hello, World!";

char to_find = 'o';

char* first_occurrence = strchr(str, to_find);
char* last_occurrence = strrchr(str, to_find);

if (first_occurrence) {
printf("First occurrence of '%c': %" PRIdPTR "\n", to_find, (intptr_t)(first_occurrence - str + 1));
}
else {
printf("Character '%c' not found in the string.\n", to_find);
}
if (last_occurrence) {
printf("Last occurrence of '%c': %" PRIdPTR "\n", to_find, (intptr_t)(last_occurrence - str + 1));
}
else {
printf("Character '%c' not found in the string.\n", to_find);
}

14. strstr

strstr用于在一个母字符串中查找另一个子字符串。

传入的第一个参数是母字符串,第二个参数是子字符串,返回值是一个指向第一次出现子字符串的第一个字符位置的指针,如果没有找到,返回NULL。

拿到指针后,同样可以计算出子字符串的首字符在字符串中的位置。

1
2
3
4
5
6
7
8
9
10
11
const char* text = "This is a simple string example.";
const char* sub = "simple";

char* result = strstr(text, sub);

if (result) {
printf("Found '%s' in \"%s\" at position: %" PRIdPTR "\n", sub, text, (intptr_t)(result - text + 1));
}
else {
printf("Substring '%s' not found in \"%s\"\n", sub, text);
}

需要注意的是,当子字符串的长度大于母字符串时,直接返回NULL,表示没有找到。

当子字符串为NULL时,函数会出现警告"sub" 可能是 "0": 这不符合函数 "strstr" 的规范。,程序无法正常运行。

15. strspn与strcspn

strspn用于统计两个字符串从开头开始,相同的字符的个数,直到遇到不同的字符,统计停止。

传入需要进行统计的两个字符串,返回一个size_t类型的长度数据。

1
2
3
4
5
6
const char* str1 = "123456abcdef789";
const char* str2 = "123456789";

size_t len = strspn(str1, str2);

printf("len = %zu\n", len); // 输出:len = 6

strcspn同样传入两个字符串,用于从头开始连续统计传入的第一个字符串中,没有在第二个字符串中出现的字符数,返回一个size_t类型的长度数据。

1
2
3
4
5
6
const char* str1 = "123456abcdef789";
const char* str2 = "ghi7b9";

size_t len = strcspn(str1, str2);

printf("len = %zu\n", len); // 输出:len = 7

这个示例中,字符串1中字符b之前的所有从头开始的连续字符都没有在字符串2中出现,因此计数返回7。

这个函数可以用来做一个检测文件名中是否有非法字符的案例:

1
2
3
4
5
6
7
8
const char* input = "filename.txt";
const char* invalid_characters = "/\\:*?\"<>|";

if (strcspn(input, invalid_characters) < strlen(input)) {
printf("The filename contains invalid characters.\n");
} else {
printf("The filename is valid.\n");
}

16. 案例:关于string.h

案例:一个综合案例,可能会用到本章学到的各种函数,实现以下功能:

  • 将一句话中的特定单词替换为另一个单词;
  • 对替换后的字符串统计其中出现某个字符的总数;
  • 统计替换后的字符串的单词数;
  • 将替换后的字符串中每一个单词提取出来,去重后放在一个数组里。

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <stdbool.h>

// ========== 常量定义 ==========

#define TEXT_SIZE 100 /**< 最大文本长度 */
#define WORD_SIZE 20 /**< 最大单词长度 */
#define DELIMITER " ,.!?\n" /**< 单词分隔符(空格、逗号、句号、问号、感叹号、换行符) */

// ========== 函数声明 ==========
// 替换字符串中的特定单词
void replaceWord(const char* text, const char* oldWord, const char* newWord, char* result);

// 统计字符串中某个字符的出现次数
uint32_t countCharOccurrences(const char* text, char targetChar);

// 统计字符串中的单词数
uint32_t countWords(const char* text);

// 去重提取字符串中的单词到数组
void extractUniqueWords(const char* text, char uniqueWords[][WORD_SIZE], uint32_t* uniqueWordCount);

int main(void) {
// 原始文本
const char text[TEXT_SIZE] = "This is a simple test. This text is for testing.";
printf("Original Text: %s\n", text);

// 存储替换后的文本
char replacedText[TEXT_SIZE] = { 0 };

// 要替换的旧单词
const char oldWord[] = "test";

// 替换后的新单词
const char newWord[] = "example";

// 要统计的目标字符
const char countCharTarget = 's';

// 存储唯一单词的二维数组
char uniqueWords[TEXT_SIZE][WORD_SIZE] = { 0 };

// 唯一单词的数量
uint32_t uniqueWordCount = 0;

// ========== 步骤 1: 替换特定单词 ==========
replaceWord(text, oldWord, newWord, replacedText);
printf("Replaced Text: %s\n", replacedText);

// ========== 步骤 2: 统计特定字符出现的总数 ==========
printf("Character '%c' Occurrences: %" PRIu32 "\n",
countCharTarget,
countCharOccurrences(replacedText, countCharTarget));

// ========== 步骤 3: 统计单词数 ==========
printf("Word Count: %" PRIu32 "\n", countWords(replacedText));

// ========== 步骤 4: 提取唯一单词 ==========
extractUniqueWords(replacedText, uniqueWords, &uniqueWordCount);
printf("Unique Words:\n");
for (size_t i = 0; i < uniqueWordCount; i++) {
printf("%s\n", uniqueWords[i]);
}

return 0;
}

// ========== 函数实现 ==========

/**
* @brief 替换字符串中的特定单词
* @param text 原始文本
* @param oldWord 要替换的旧单词
* @param newWord 替换后的新单词
* @param result 存储结果的缓冲区
*
* @details
* 使用 strstr 查找旧单词的位置,逐段拼接新字符串。
* 注意:只替换完整单词匹配(子串匹配),不区分单词边界。
*/
void replaceWord(const char* text, const char* oldWord, const char* newWord, char* result) {
// 临时缓冲区,用于构建替换后的字符串
char buffer[TEXT_SIZE] = { 0 };

// 当前搜索位置
const char* pos = text;

// 找到的旧单词位置
const char* temp = text;

// 旧单词的长度
size_t oldWordLen = strlen(oldWord);

// 循环查找并替换所有旧单词
while ((temp = strstr(pos, oldWord)) != NULL) {
// 拼接旧单词之前的部分
strncat_s(buffer, TEXT_SIZE, pos, temp - pos);

// 拼接新单词
strcat_s(buffer, TEXT_SIZE, newWord);

// 移动搜索位置到旧单词之后
pos = temp + oldWordLen;
}

// 拼接剩余部分
strcat_s(buffer, TEXT_SIZE, pos);

// 将结果复制到输出缓冲区
strcpy_s(result, TEXT_SIZE, buffer);
}

/**
* @brief 统计字符串中某个字符的出现次数
* @param text 要统计的文本
* @param targetChar 目标字符
* @return 字符出现的次数
*
* @details
* 遍历字符串的每个字符,逐一比较并计数。
*/
uint32_t countCharOccurrences(const char* text, char targetChar) {
// 计数器
uint32_t count = 0;

// 遍历字符串的每个字符
while (*text) {
// 如果当前字符与目标字符匹配
if (*text == targetChar) {
count++;
}
// 移动到下一个字符
text++;
}

return count;
}

/**
* @brief 统计字符串中的单词数
* @param text 要统计的文本
* @return 单词总数
*
* @details
* 使用 strtok_s 按分隔符分割字符串,统计分割出的单词数量。
* 注意:会修改临时缓冲区,不影响原始字符串。
*/
uint32_t countWords(const char* text) {
// 单词计数器
uint32_t count = 0;

// 临时缓缓冲区(因为 strtok_s 会修改字符串)
char buffer[TEXT_SIZE];
strcpy_s(buffer, TEXT_SIZE, text);

// strtok_s 的上下文指针
char* context = NULL;

// 获取第一个单词
char* token = strtok_s(buffer, DELIMITER, &context);

// 循环获取所有单词并计数
while (token) {
count++;
// 获取下一个单词
token = strtok_s(NULL, DELIMITER, &context);
}

return count;
}

/**
* @brief 去重提取字符串中的单词到数组
* @param text 要提取的文本
* @param uniqueWords 存储唯一单词的二维数组
* @param uniqueWordCount 唯一单词数量指针
*
* @details
* 使用 strtok_s 分割字符串,对每个单词检查是否已存在。
* 只有不重复的单词才会被添加到数组中。
*/
void extractUniqueWords(const char* text, char uniqueWords[][WORD_SIZE], uint32_t* uniqueWordCount) {
// 临时缓冲区(因为 strtok_s 会修改字符串)
char buffer[TEXT_SIZE] = { 0 };
strcpy_s(buffer, TEXT_SIZE, text);

// strtok_s 的上下文指针
char* context = NULL;

// 获取第一个单词
char* token = strtok_s(buffer, DELIMITER, &context);

// 循环处理所有单词
while (token) {
// 标记当前单词是否唯一
bool isUnique = true;

// 检查当前单词是否已存在于数组中
for (size_t i = 0; i < *uniqueWordCount; i++) {
if (strcmp(uniqueWords[i], token) == 0) {
// 找到重复单词
isUnique = false;
break;
}
}

// 如果是唯一单词且数组未满,则添加到数组
if (isUnique && *uniqueWordCount < TEXT_SIZE) {
// 将单词复制到数组
strcpy_s(uniqueWords[*uniqueWordCount], WORD_SIZE, token);
// 增加唯一单词计数
(*uniqueWordCount)++;
}

// 获取下一个单词
token = strtok_s(NULL, DELIMITER, &context);
}
}

17. 第十章结束语

本章节主要介绍了字符串的定义与使用,以及很多用于处理字符串的string.h库函数的用法。

字符串的使用与处理涉及到很多指针与数组的相关知识,可以结合起来思考。

多练习,尽量能流畅地使用这些库函数。

本文来源: 青江的个人站
本文链接: https://hanqingjiang.com/2026/01/10/20260110_C_string/
版权声明: 本作品采用 CC BY-NC-SA 4.0 进行许可。转载请注明出处!
知识共享许可协议
赏

谢谢你请我喝可乐~

支付宝
微信
  • Notes
  • C

扫一扫,分享到微信

微信分享二维码
2026新年快乐!
  1. 1. 1. 字符串
  2. 2. 2. strcpy_s的用法
  3. 3. 3. VS编译器捕获字符串异常
  4. 4. 4. strlen
  5. 5. 5. strcat_s
  6. 6. 6. sprintf_s
  7. 7. 7. strncpy_s
  8. 8. 8. strncat_s
  9. 9. 9. gets_s
  10. 10. 10. strtok_s
  11. 11. 11. strcmp
  12. 12. 12. strncmp
  13. 13. 13. strchr与strrchr
  14. 14. 14. strstr
  15. 15. 15. strspn与strcspn
  16. 16. 16. 案例:关于string.h
  17. 17. 17. 第十章结束语
© 2021-2026 青江的个人站
晋ICP备2024051277号-1
powered by Hexo & Yilia
  • 友链
  • 搜索文章 >>

tag:

  • 生日快乐🎂
  • 新年快乐!
  • 小技巧
  • Linux
  • 命令
  • 语录
  • 复刻
  • Blog
  • Notes
  • Android
  • C
  • Homework
  • MATLAB
  • FPGA
  • Server
  • Vivado
  • Git

  • 引路人-稚晖
  • Bilibili-稚晖君
  • 超有趣讲师-Frank
  • Bilibili-Frank