一、题目需求
输入n个国家名称,读取后按字典序升序 排序,最终输出排序后的结果。
核心难点:正确读取字符串(处理换行符)、使用字符串函数实现排序逻辑。
二、核心知识点拆解
1. fgets:安全读取字符串
(1)函数原型
c
char *fgets(char *str, int n, FILE *stream);
(2)参数说明
str:存储读取到的字符串的数组(比如本题的countries[i]);n:最多读取的字符数(包含末尾的\0,实际读取n-1个字符);stream:输入流,读取控制台输入用stdin。
(3)关键特性(本题必知)
✅ 优点:比scanf("%s")安全,能读取带空格的字符串(比如United States),且不会数组越界;
❌ 注意:读取时会把输入末尾的换行符\n 一起存入字符串(比如输入China+回车,实际存入"China\n"),需手动清理。
(4)本题用法
c
// 读取第i个国家名称,最多读MAX_LEN-1个字符
fgets(countries[i], MAX_LEN, stdin);
2. strcspn:清理换行符的核心
(1)函数原型
c
size_t strcspn(const char *str1, const char *str2);
(2)作用
计算str1中第一个出现在str2字符集合里的字符的位置 (下标),返回该位置值。
👉 本题中:strcspn(countries[i], "\n") → 找到countries[i]中\n的下标。
(3)本题核心用法(清理换行符)
c
// 找到\n的位置,替换为\0(字符串结束符),截断换行符
countries[i][strcspn(countries[i], "\n")] = '\0';
⚠️ 易错点:第二个参数必须是字符串"\n" ,而非单个字符'\n'(类型不匹配会编译/运行错误)。
3. strcmp:字符串比较(排序的核心)
(1)函数原型
c
int strcmp(const char *str1, const char *str2);
(2)返回值(字典序比较)
- 返回
>0:str1字典序 >str2(比如"Japan">"China"); - 返回
=0:str1和str2完全相同; - 返回
<0:str1字典序 <str2。
(3)本题用法(冒泡排序判断条件)
c
// 若前一个字符串字典序更大,交换两者(实现升序)
if(strcmp(countries[j], countries[j+1]) > 0) {
// 交换逻辑
}
4. strcpy:字符串拷贝(交换字符串)
(1)函数原型
c
char *strcpy(char *dest, const char *src);
(2)作用
把src指向的字符串拷贝到dest中(包含\0),需保证dest数组容量足够。
(3)本题用法(冒泡排序交换元素)
c
char temp[MAX_LEN]; // 临时数组存交换的字符串
strcpy(temp, countries[j]); // 把前一个字符串存到temp
strcpy(countries[j], countries[j+1]); // 后一个覆盖前一个
strcpy(countries[j+1], temp); // temp覆盖后一个
三、完整代码(带详细注释)
c
#include<stdio.h>
#include<string.h>
#define MAX_LEN 50 // 单个国名最大长度
#define MAX_COUNTRIES 110 // 最多国名数量
int main()
{
int n;
// 输入合法性检查:避免非数字/超出范围的n
if (scanf("%d", &n) != 1 || n < 1 || n > MAX_COUNTRIES) {
printf("输入数量不合法!\n");
return 1;
}
getchar(); // 吸收scanf残留的换行符(否则fgets会读空行)
char countries[MAX_COUNTRIES][MAX_LEN]; // 存储国名的二维数组
char temp[MAX_LEN]; // 交换用的临时数组
// 1. 读取n个国名,清理换行符
for(int i = 0; i < n; i++)
{
fgets(countries[i], MAX_LEN, stdin); // 读取一行字符串
// 关键:用strcspn找到\n的位置,替换为\0去掉换行符
countries[i][strcspn(countries[i], "\n")] = '\0';
}
// 2. 冒泡排序:按字典序升序排列
for(int i = 0; i < n - 1; i++) // 排序轮数:n-1轮
{
for(int j = 0; j < n - i - 1; j++) // 每轮比较次数递减
{
// strcmp比较两个字符串,前大后小则交换
if(strcmp(countries[j], countries[j+1]) > 0)
{
strcpy(temp, countries[j]);
strcpy(countries[j], countries[j+1]);
strcpy(countries[j+1], temp);
}
}
}
// 3. 输出排序结果
for(int i = 0; i < n; i++)
{
printf("%s\n", countries[i]);
}
return 0;
}
四、常见错误避坑
- fgets读取空行 :
scanf("%d", &n)后未加getchar(),残留的换行符会被fgets读取,导致第一个字符串为空; - strcspn参数错误 :把
"\n"写成'\n'(字符 vs 字符串,类型不匹配); - 数组越界 :未检查n的范围(比如n>110),导致访问
countries数组超出定义长度; - strcmp使用错误 :误以为返回1/-1,实际返回任意正/负数,只需判断
>0/<0即可。
五、核心总结
- fgets :安全读取带空格的字符串,但会读取换行符,需用
strcspn清理; - strcspn :快速定位目标字符(如
\n)的位置,是处理fgets换行符的最优方式; - strcmp:字符串比较的核心函数,字典序排序的关键,返回值判断大小关系;
- strcpy:字符串拷贝工具,需配合临时数组实现字符串交换(二维字符串数组无法直接赋值)。
这套组合是C语言字符串处理的经典用法,尤其适用于"读取-处理-排序-输出"类字符串题目。