C语言数组和字符串

概述

本文档详细介绍C语言中数组和字符串的使用方法,包括一维数组、二维数组、字符数组、字符串处理函数等内容。数组和字符串是C语言中常用的数据结构,掌握它们的使用对于编写高效、可靠的C程序至关重要。

一维数组

数组的声明与初始化

数组是一种存储相同类型元素的集合,一维数组的声明和初始化语法如下:

1
2
3
4
5
6
7
8
9
10
11
// 声明数组
类型 数组名[数组大小];

// 初始化数组
类型 数组名[数组大小] = {元素1, 元素2, ..., 元素n};

// 自动推断数组大小
类型 数组名[] = {元素1, 元素2, ..., 元素n};

// 部分初始化,其余元素为0
类型 数组名[数组大小] = {元素1, 元素2, ...};

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
// 数组声明和初始化
int numbers[5] = {1, 2, 3, 4, 5}; // 显式初始化
int numbers2[] = {6, 7, 8, 9, 10}; // 自动推断大小
int numbers3[5] = {11, 12}; // 部分初始化,其余为0

// 访问数组元素
printf("numbers[0] = %d\n", numbers[0]); // 第一个元素
printf("numbers[4] = %d\n", numbers[4]); // 最后一个元素

// 修改数组元素
numbers[2] = 100;
printf("修改后 numbers[2] = %d\n", numbers[2]);

数组的遍历

遍历数组是指依次访问数组中的每个元素,通常使用for循环实现:

1
2
3
4
5
6
7
8
9
10
11
// 打印数组
void print_array(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}

// 调用打印函数
printf("numbers数组: ");
print_array(numbers, 5);

补充示例:数组的冒泡排序

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
// 冒泡排序函数
void bubble_sort(int arr[], int size) {
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// 交换元素
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}

// 使用冒泡排序
int unsorted[] = {5, 2, 9, 1, 5, 6};
int size = sizeof(unsorted) / sizeof(unsorted[0]);

printf("排序前: ");
print_array(unsorted, size);

bubble_sort(unsorted, size);

printf("排序后: ");
print_array(unsorted, size);

二维数组

二维数组的声明与初始化

二维数组是一种特殊的数组,它的元素是一维数组。二维数组的声明和初始化语法如下:

1
2
3
4
5
6
7
8
9
// 声明二维数组
类型 数组名[行数][列数];

// 初始化二维数组
类型 数组名[行数][列数] = {
{元素1, 元素2, ...},
{元素1, 元素2, ...},
...
};

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
// 二维数组声明和初始化
int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};

// 访问二维数组元素
printf("matrix[0][0] = %d\n", matrix[0][0]); // 第一行第一列
printf("matrix[1][2] = %d\n", matrix[1][2]); // 第二行第三列

// 修改二维数组元素
matrix[0][1] = 20;
printf("修改后 matrix[0][1] = %d\n", matrix[0][1]);

二维数组的遍历

遍历二维数组通常使用嵌套的for循环:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 打印二维数组
void print_2d_array(int arr[][3], int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
}

// 调用打印函数
printf("二维数组matrix: \n");
print_2d_array(matrix, 2);

补充示例:二维数组的转置

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
// 二维数组转置
void transpose_matrix(int matrix[][3], int transposed[][2], int rows, int cols) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
transposed[j][i] = matrix[i][j];
}
}
}

// 使用转置函数
int original[2][3] = {{1, 2, 3}, {4, 5, 6}};
int transposed[3][2];

printf("原始矩阵:\n");
print_2d_array(original, 2);

transpose_matrix(original, transposed, 2, 3);

printf("转置矩阵:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
printf("%d ", transposed[i][j]);
}
printf("\n");
}

字符数组和字符串

字符数组的初始化

在C语言中,字符串是由字符组成的数组,以空字符'\0'结尾。字符数组的初始化方法如下:

1
2
3
4
// 字符数组初始化
char char_array[5] = {'H', 'e', 'l', 'l', 'o'}; // 普通字符数组,没有结束符
char string1[] = "Hello"; // 字符串,自动添加结束符
char string2[20] = "World"; // 指定大小的字符串

字符串的输出

字符串可以使用printf函数的%s格式说明符输出:

1
2
3
4
5
6
7
8
9
10
// 字符数组输出
printf("char_array: ");
for (int i = 0; i < 5; i++) {
printf("%c", char_array[i]);
}
printf("\n");

// 字符串输出
printf("string1: %s\n", string1);
printf("string2: %s\n", string2);

字符串长度

可以使用strlen函数获取字符串的长度(不包括结束符'\0'):

1
2
3
4
5
#include <string.h>

// 字符串长度
printf("string1的长度: %zu\n", strlen(string1));
printf("string2的长度: %zu\n", strlen(string2));

字符串处理函数

C语言提供了丰富的字符串处理函数,定义在<string.h>头文件中。

常用字符串处理函数

函数 功能 示例
strcpy(dest, src) 复制字符串 strcpy(dest, "Hello")
strcat(dest, src) 连接字符串 strcat(dest, " World")
strcmp(s1, s2) 比较字符串 strcmp(s1, s2)
strlen(s) 获取字符串长度 strlen(s)
strncpy(dest, src, n) 安全复制指定长度的字符串 strncpy(dest, src, sizeof(dest)-1)
strncat(dest, src, n) 安全连接指定长度的字符串 strncat(dest, src, sizeof(dest)-strlen(dest)-1)
strchr(s, c) 查找字符首次出现的位置 strchr(s, 'a')
strstr(s, sub) 查找子串首次出现的位置 strstr(s, "abc")

示例代码

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
// strcpy: 复制字符串
char dest[50];
char src[] = "Hello, ";
strcpy(dest, src);
printf("strcpy(dest, src): %s\n", dest);

// strcat: 连接字符串
char append[] = "World!";
strcat(dest, append);
printf("strcat(dest, append): %s\n", dest);

// strcmp: 比较字符串
char str1[] = "apple";
char str2[] = "banana";
char str3[] = "apple";

printf("strcmp(str1, str2): %d\n", strcmp(str1, str2)); // 返回负数
printf("strcmp(str1, str3): %d\n", strcmp(str1, str3)); // 返回0
printf("strcmp(str2, str1): %d\n", strcmp(str2, str1)); // 返回正数

// strncpy: 安全地复制指定长度的字符串
char safe_dest[20];
strncpy(safe_dest, "This is a very long string", sizeof(safe_dest) - 1);
safe_dest[sizeof(safe_dest) - 1] = '\0'; // 确保字符串结束
printf("strncpy安全复制: %s\n", safe_dest);

// strncat: 安全地连接指定长度的字符串
strncat(safe_dest, " appended", 10);
printf("strncat安全连接: %s\n", safe_dest);

// strchr: 查找字符首次出现的位置
char *pos = strchr("Hello, World!", 'W');
if (pos != NULL) {
printf("'W'首次出现的位置: %ld\n", pos - "Hello, World!");
}

// strstr: 查找子串首次出现的位置
char *sub_pos = strstr("Hello, World!", "World");
if (sub_pos != NULL) {
printf("'World'首次出现的位置: %ld\n", sub_pos - "Hello, World!");
}

补充示例:字符串分割

1
2
3
4
5
6
7
8
9
10
11
12
13
// 字符串分割函数
void split_string(char *str, const char *delimiter) {
char *token = strtok(str, delimiter);
while (token != NULL) {
printf("%s\n", token);
token = strtok(NULL, delimiter);
}
}

// 使用字符串分割函数
char sentence[] = "Hello,World,How,Are,You";
printf("分割字符串 \"%s\":\n", sentence);
split_string(sentence, ",");

字符串输入输出

使用scanf输入字符串

scanf函数可以用于输入字符串,但它会在空格处停止读取:

1
2
3
4
char name[50];
printf("请输入你的名字: ");
scanf("%s", name); // 注意:scanf会在空格处停止
printf("你好, %s!\n", name);

使用fgets输入带空格的字符串

fgets函数可以读取带空格的字符串,它会读取直到换行符或指定长度:

1
2
3
4
5
6
char full_name[50];
printf("请输入你的全名: ");
fflush(stdin); // 清空输入缓冲区
fgets(full_name, sizeof(full_name), stdin);
full_name[strcspn(full_name, "\n")] = '\0'; // 移除换行符
printf("你好, %s!\n", full_name);

补充示例:安全的字符串输入函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 安全的字符串输入函数
void safe_gets(char *buffer, size_t size) {
fgets(buffer, size, stdin);
// 移除换行符
size_t len = strlen(buffer);
if (len > 0 && buffer[len-1] == '\n') {
buffer[len-1] = '\0';
}
}

// 使用安全的字符串输入函数
char input[100];
printf("请输入一段文本: ");
safe_gets(input, sizeof(input));
printf("你输入的是: %s\n", input);

字符串操作示例

反转字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 反转字符串
void reverse_string(char str[]) {
int len = strlen(str);
for (int i = 0; i < len / 2; i++) {
char temp = str[i];
str[i] = str[len - 1 - i];
str[len - 1 - i] = temp;
}
}

// 使用反转字符串函数
char test_str[] = "Hello, World!";
printf("原始字符串: %s\n", test_str);
reverse_string(test_str);
printf("反转后: %s\n", test_str);

统计元音字母个数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 统计字符串中的元音字母个数
int count_vowels(const char str[]) {
int count = 0;
for (int i = 0; str[i]; i++) {
char ch = tolower(str[i]);
if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') {
count++;
}
}
return count;
}

// 使用统计元音字母函数
char test_str[] = "Hello, World!";
int vowel_count = count_vowels(test_str);
printf("元音字母个数: %d\n", vowel_count);

字符串大小写转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 字符串转大写
char upper_str[50];
strcpy(upper_str, test_str);
for (int i = 0; upper_str[i]; i++) {
upper_str[i] = toupper(upper_str[i]);
}
printf("大写: %s\n", upper_str);

// 字符串转小写
char lower_str[50];
strcpy(lower_str, test_str);
for (int i = 0; lower_str[i]; i++) {
lower_str[i] = tolower(lower_str[i]);
}
printf("小写: %s\n", lower_str);

补充示例:字符串替换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 字符串替换函数
void replace_char(char *str, char old_char, char new_char) {
for (int i = 0; str[i]; i++) {
if (str[i] == old_char) {
str[i] = new_char;
}
}
}

// 使用字符串替换函数
char text[] = "Hello, World!";
printf("原始字符串: %s\n", text);
replace_char(text, 'o', '0');
printf("替换后: %s\n", text);

数组和指针关系

数组名作为指针

在C语言中,数组名可以看作是指向数组首元素的指针:

1
2
3
4
5
6
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr; // 数组名是指向首元素的指针

printf("arr[0] = %d, *ptr = %d\n", arr[0], *ptr);
printf("arr[1] = %d, *(ptr+1) = %d\n", arr[1], *(ptr+1));
printf("arr[2] = %d, ptr[2] = %d\n", arr[2], ptr[2]);

指针算术

指针可以进行算术运算,如加、减操作:

1
2
3
4
5
6
7
8
9
// 指针算术
ptr++;
printf("ptr++后, *ptr = %d\n", *ptr);

ptr += 2;
printf("ptr += 2后, *ptr = %d\n", *ptr);

ptr -= 1;
printf("ptr -= 1后, *ptr = %d\n", *ptr);

数组参数传递

当数组作为函数参数传递时,实际上传递的是数组首元素的地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 数组参数传递
void modify_array(int arr[], int size) {
for (int i = 0; i < size; i++) {
arr[i] *= 2; // 修改数组元素
}
}

// 使用修改数组函数
int numbers[] = {1, 2, 3, 4, 5};
printf("修改前: ");
print_array(numbers, 5);

modify_array(numbers, 5);

printf("修改后: ");
print_array(numbers, 5);

动态数组

使用malloc和free

可以使用动态内存分配函数创建动态数组:

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
#include <stdlib.h>

// 动态数组示例
int *create_array(int size) {
int *arr = (int *)malloc(size * sizeof(int));
if (arr == NULL) {
printf("内存分配失败\n");
exit(1);
}
return arr;
}

// 使用动态数组
int size = 5;
int *dynamic_arr = create_array(size);

// 初始化动态数组
for (int i = 0; i < size; i++) {
dynamic_arr[i] = i + 1;
}

printf("动态数组: ");
print_array(dynamic_arr, size);

// 释放动态数组
free(dynamic_arr);

补充示例:二维动态数组

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
// 创建二维动态数组
int **create_2d_array(int rows, int cols) {
int **arr = (int **)malloc(rows * sizeof(int *));
if (arr == NULL) {
printf("内存分配失败\n");
exit(1);
}

for (int i = 0; i < rows; i++) {
arr[i] = (int *)malloc(cols * sizeof(int));
if (arr[i] == NULL) {
printf("内存分配失败\n");
exit(1);
}
}

return arr;
}

// 释放二维动态数组
void free_2d_array(int **arr, int rows) {
for (int i = 0; i < rows; i++) {
free(arr[i]);
}
free(arr);
}

// 使用二维动态数组
int rows = 2, cols = 3;
int **dynamic_2d_arr = create_2d_array(rows, cols);

// 初始化二维动态数组
int count = 1;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
dynamic_2d_arr[i][j] = count++;
}
}

// 打印二维动态数组
printf("二维动态数组:\n");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%d ", dynamic_2d_arr[i][j]);
}
printf("\n");
}

// 释放二维动态数组
free_2d_array(dynamic_2d_arr, rows);

综合示例

示例1:数组元素查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 线性查找函数
int linear_search(int arr[], int size, int target) {
for (int i = 0; i < size; i++) {
if (arr[i] == target) {
return i; // 找到目标元素,返回索引
}
}
return -1; // 未找到目标元素
}

// 使用线性查找函数
int numbers[] = {10, 20, 30, 40, 50};
int size = sizeof(numbers) / sizeof(numbers[0]);
int target = 30;

int index = linear_search(numbers, size, target);
if (index != -1) {
printf("元素 %d 在数组中的索引位置: %d\n", target, index);
} else {
printf("元素 %d 不在数组中\n", target);
}

示例2:字符串处理综合示例

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
// 字符串处理综合示例
void process_string(char *str) {
printf("原始字符串: %s\n", str);

// 计算字符串长度
int len = strlen(str);
printf("字符串长度: %d\n", len);

// 统计单词个数
int word_count = 0;
int in_word = 0;

for (int i = 0; str[i]; i++) {
if (isspace(str[i])) {
in_word = 0;
} else if (!in_word) {
in_word = 1;
word_count++;
}
}

printf("单词个数: %d\n", word_count);

// 转换为大写并打印
char upper_str[100];
strcpy(upper_str, str);
for (int i = 0; upper_str[i]; i++) {
upper_str[i] = toupper(upper_str[i]);
}

printf("大写字符串: %s\n", upper_str);
}

// 使用字符串处理函数
char text[] = "Hello, how are you today?";
process_string(text);

数组和字符串的常见问题

常见问题及解决方案

  1. 数组越界:访问超出数组范围的元素

    • 解决方案:确保数组索引在有效范围内,使用循环时检查边界条件
  2. 字符串没有结束符:导致字符串处理函数出错

    • 解决方案:确保字符串以'\0'结尾,使用strncpy等安全函数
  3. 内存泄漏:动态分配的内存没有释放

    • 解决方案:使用free函数释放动态分配的内存,养成良好的内存管理习惯
  4. 缓冲区溢出:输入数据超过缓冲区大小

    • 解决方案:使用fgetsstrncpy等安全函数,指定最大读取长度
  5. 指针未初始化:使用未初始化的指针

    • 解决方案:总是初始化指针,使用前检查指针是否为NULL

最佳实践

  1. 使用有意义的变量名:数组和字符串变量名应清晰表达其用途
  2. 初始化数组:声明数组时进行初始化,避免使用未初始化的数组
  3. 使用常量定义数组大小:使用#defineconst定义数组大小,提高代码可维护性
  4. 优先使用安全的字符串函数:如strncpystrncat等,避免缓冲区溢出
  5. 检查函数返回值:如fgetsmalloc等函数的返回值
  6. 释放动态内存:使用free函数释放动态分配的内存
  7. 使用适当的数据结构:根据实际需求选择合适的数据结构,如数组、链表等
  8. 编写模块化代码:将数组和字符串操作封装为函数,提高代码复用性
  9. 添加适当的注释:解释复杂的数组和字符串操作
  10. 测试边界情况:测试空数组、空字符串、最大长度等边界情况

总结

C语言中的数组和字符串是基础但重要的数据结构,通过本文档的学习,我们了解了:

  1. 一维数组:声明、初始化、访问、修改和遍历
  2. 二维数组:声明、初始化、访问、修改和遍历
  3. 字符数组和字符串:初始化、输出、长度计算
  4. 字符串处理函数strcpystrcatstrcmp等常用函数的使用
  5. 字符串输入输出scanffgets的使用方法
  6. 字符串操作:反转、统计、大小写转换等
  7. 数组和指针关系:数组名作为指针、指针算术、数组参数传递
  8. 动态数组:使用mallocfree创建和释放动态数组
  9. 常见问题及解决方案:数组越界、字符串没有结束符等问题的解决方法
  10. 最佳实践:编写高质量数组和字符串代码的建议

掌握数组和字符串的使用对于编写高效、可靠的C程序至关重要,希望本文档能帮助您更好地理解和使用C语言中的数组和字符串。

arrays_strings.c

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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
#include <stdio.h>
#include <string.h>
#include <ctype.h>

/**
* @brief 数组和字符串操作示例
* @details 这个程序演示了C语言中数组和字符串的各种用法,包括
* 一维数组、二维数组、字符数组、字符串处理函数等。
* @return 0 表示程序成功执行
*/

// =========================
// 函数原型声明
// =========================
void print_array(int arr[], int size); // 打印一维数组
void print_2d_array(int arr[][3], int rows); // 打印二维数组
void reverse_string(char str[]); // 反转字符串
int count_vowels(const char str[]); // 统计元音字母个数

/**
* @brief 主函数
* @return 0 表示程序成功执行
*/
int main() {
// =========================
// 一维数组
// =========================
printf("=== 一维数组 ===\n");

// 数组声明和初始化
int numbers[5] = {1, 2, 3, 4, 5}; // 显式初始化
int numbers2[] = {6, 7, 8, 9, 10}; // 自动推断大小
int numbers3[5] = {11, 12}; // 部分初始化,其余为0

// 访问数组元素
printf("numbers[0] = %d\n", numbers[0]); // 第一个元素
printf("numbers[4] = %d\n", numbers[4]); // 最后一个元素

// 修改数组元素
numbers[2] = 100;
printf("修改后 numbers[2] = %d\n", numbers[2]);

// 打印数组
printf("numbers数组: ");
print_array(numbers, 5);

printf("numbers2数组: ");
print_array(numbers2, 5);

printf("numbers3数组: ");
print_array(numbers3, 5);

printf("\n");

// =========================
// 二维数组
// =========================
printf("=== 二维数组 ===\n");

// 二维数组声明和初始化
int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};

// 访问二维数组元素
printf("matrix[0][0] = %d\n", matrix[0][0]); // 第一行第一列
printf("matrix[1][2] = %d\n", matrix[1][2]); // 第二行第三列

// 修改二维数组元素
matrix[0][1] = 20;
printf("修改后 matrix[0][1] = %d\n", matrix[0][1]);

// 打印二维数组
printf("二维数组matrix: \n");
print_2d_array(matrix, 2);

printf("\n");

// =========================
// 字符数组和字符串
// =========================
printf("=== 字符数组和字符串 ===\n");

// 字符数组初始化
char char_array[5] = {'H', 'e', 'l', 'l', 'o'};
char string1[] = "Hello";
char string2[20] = "World";

// 字符串输出
printf("char_array: ");
for (int i = 0; i < 5; i++) {
printf("%c", char_array[i]);
}
printf("\n");

printf("string1: %s\n", string1);
printf("string2: %s\n", string2);

// 字符串长度
printf("string1的长度: %zu\n", strlen(string1));
printf("string2的长度: %zu\n", strlen(string2));

printf("\n");

// =========================
// 字符串处理函数
// =========================
printf("=== 字符串处理函数 ===\n");

char dest[50];
char src[] = "Hello, ";
char append[] = "World!";

// strcpy: 复制字符串
strcpy(dest, src);
printf("strcpy(dest, src): %s\n", dest);

// strcat: 连接字符串
strcat(dest, append);
printf("strcat(dest, append): %s\n", dest);

// strcmp: 比较字符串
char str1[] = "apple";
char str2[] = "banana";
char str3[] = "apple";

printf("strcmp(str1, str2): %d\n", strcmp(str1, str2)); // 返回负数
printf("strcmp(str1, str3): %d\n", strcmp(str1, str3)); // 返回0
printf("strcmp(str2, str1): %d\n", strcmp(str2, str1)); // 返回正数

// strncpy: 安全地复制指定长度的字符串
char safe_dest[20];
strncpy(safe_dest, "This is a very long string", sizeof(safe_dest) - 1);
safe_dest[sizeof(safe_dest) - 1] = '\0'; // 确保字符串结束
printf("strncpy安全复制: %s\n", safe_dest);

// strncat: 安全地连接指定长度的字符串
strncat(safe_dest, " appended", 10);
printf("strncat安全连接: %s\n", safe_dest);

// strchr: 查找字符首次出现的位置
char *pos = strchr("Hello, World!", 'W');
if (pos != NULL) {
printf("'W'首次出现的位置: %ld\n", pos - "Hello, World!");
}

// strstr: 查找子串首次出现的位置
char *sub_pos = strstr("Hello, World!", "World");
if (sub_pos != NULL) {
printf("'World'首次出现的位置: %ld\n", sub_pos - "Hello, World!");
}

printf("\n");

// =========================
// 字符串输入输出
// =========================
printf("=== 字符串输入输出 ===\n");

char name[50];
char full_name[50];

printf("请输入你的名字: ");
scanf("%s", name); // 注意:scanf会在空格处停止
printf("你好, %s!\n", name);

// 使用fgets读取带空格的字符串
printf("请输入你的全名: ");
fflush(stdin); // 清空输入缓冲区
fgets(full_name, sizeof(full_name), stdin);
full_name[strcspn(full_name, "\n")] = '\0'; // 移除换行符
printf("你好, %s!\n", full_name);

printf("\n");

// =========================
// 字符串操作示例
// =========================
printf("=== 字符串操作示例 ===\n");

char test_str[] = "Hello, World!";
printf("原始字符串: %s\n", test_str);

// 反转字符串
reverse_string(test_str);
printf("反转后: %s\n", test_str);

// 再次反转回来
reverse_string(test_str);

// 统计元音字母个数
int vowel_count = count_vowels(test_str);
printf("元音字母个数: %d\n", vowel_count);

// 字符串转大写
char upper_str[50];
strcpy(upper_str, test_str);
for (int i = 0; upper_str[i]; i++) {
upper_str[i] = toupper(upper_str[i]);
}
printf("大写: %s\n", upper_str);

// 字符串转小写
char lower_str[50];
strcpy(lower_str, test_str);
for (int i = 0; lower_str[i]; i++) {
lower_str[i] = tolower(lower_str[i]);
}
printf("小写: %s\n", lower_str);

printf("\n");

// =========================
// 数组和指针关系
// =========================
printf("=== 数组和指针关系 ===\n");

int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr; // 数组名是指向首元素的指针

printf("arr[0] = %d, *ptr = %d\n", arr[0], *ptr);
printf("arr[1] = %d, *(ptr+1) = %d\n", arr[1], *(ptr+1));
printf("arr[2] = %d, ptr[2] = %d\n", arr[2], ptr[2]);

// 指针算术
ptr++;
printf("ptr++后, *ptr = %d\n", *ptr);

return 0;
}

// =========================
// 函数定义
// =========================

/**
* @brief 打印一维数组
* @param arr 要打印的数组
* @param size 数组的大小
*/
void print_array(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}

/**
* @brief 打印二维数组
* @param arr 要打印的二维数组
* @param rows 数组的行数
*/
void print_2d_array(int arr[][3], int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
}

/**
* @brief 反转字符串
* @param str 要反转的字符串
*/
void reverse_string(char str[]) {
int len = strlen(str);
for (int i = 0; i < len / 2; i++) {
char temp = str[i];
str[i] = str[len - 1 - i];
str[len - 1 - i] = temp;
}
}

/**
* @brief 统计字符串中的元音字母个数
* @param str 要统计的字符串
* @return 元音字母的个数
*/
int count_vowels(const char str[]) {
int count = 0;
for (int i = 0; str[i]; i++) {
char ch = tolower(str[i]);
if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') {
count++;
}
}
return count;
}