解题思路:
注意事项:
如果使用strcmp感觉只能用冒泡排序了,初始化字符串时可以用一维的字符串指针数组储存,用二维字符串数组也行。
参考代码:
#include <stdio.h>
#include <string.h>
//输入三个字符串,按由小到大的顺序输出
int main()
{
char str1[300] = {0}, str2[300] = {0}, str3[300] = {0};
char *str[3] = {str1, str2, str3};
char temp[300] = {0};
//定义一个暂时的字符串指针
//和char *temp有什么区别?
fgets(str1, sizeof(str1), stdin);
str1[strcspn(str1, "\n")] = '\0';
fgets(str2, sizeof(str2), stdin);
str2[strcspn(str2, "\n")] = '\0';
fgets(str3, sizeof(str3), stdin);
str3[strcspn(str3, "\n")] = '\0';
// for(int i = 0; i < 3; i++)
// {
// printf("%s\n", str[i]);
// printf("%p\n", str[i]);
// }
for(int i = 0; i < 2; i++)//// 外层循环:n个元素需n-1轮
{
for(int j = 0; j < 2 - i; j++)//// 内层循环:每轮少比较i个(尾部已排序)
{
if(strcmp(str[j], str[j+1]) >= 0)
{
// printf("str[%d] > str[%d]\n", j, j+1);
strcpy(temp, str[j]);
strcpy(str[j], str[j+1]);
strcpy(str[j+1], temp);
}
}
}
for(int i = 0; i < 3; i++)
{
printf("%s\n", str[i]);
}
}
// char* 的意思不是 “指针上是一个字符”,而是 “这个指针是专门用来指向字符类型数据的指针” —— 指针本身存储的是内存地址(比如 0x7ffd8b5c8a4c),而不是字符本身;通过这个地址,能找到并操作对应的字符。
// 可以用一个通俗的比喻理解:
// char* p 就像一张 “纸条”,上面写着一个 “房间号”(内存地址);
// 这个 “房间” 里存放的是 单个字符(char 类型数据,占 1 字节);
// 你不能在 “纸条” 上直接写字符(比如把 'a' 写在纸条上),只能写房间号,通过房间号找到房间里的字符。
// 关键澄清:char* 指向的两种常见场景
// 1. 指向单个字符
// char* 可以指向一个独立的字符变量,此时通过指针解引用(*p)能访问 / 修改这个字符:
// c
// 运行
// char ch = 'A'; // 字符变量ch,存储在某个内存地址(比如0x1234)
// char* p = &ch; // p存储ch的地址(0x1234),p是“指向字符的指针”
// printf("%c", *p); // *p:通过p的地址找到ch,输出 'A'
// *p = 'B'; // 通过p修改ch的值,此时ch变成 'B'
// 这里 p 是 char*,指向的是单个字符,符合 “指向字符类型数据” 的定义。
// 2. 指向字符串(最常用场景)
// C 语言中没有专门的 “字符串类型”,字符串本质是 “以 \0 结尾的字符数组”。此时 char* 指向的是字符数组的首元素地址,通过指针偏移(p[i] 或 *(p+i))能访问整个字符串:
// c
// 运行
// char str[] = "hello"; // 字符数组:h e l l o \0,首元素h的地址是0x5678
// char* p = str; // p存储首元素h的地址(0x5678),p是“指向字符的指针”
// printf("%c", *p); // *p:访问首元素h,输出 'h'
// printf("%c", p[1]); // p[1]:偏移1个字符,访问e,输出 'e'
// printf("%s", p); // %s:从p指向的地址开始,直到\0,输出 "hello"
// 这里 p 依然是 char*(指向字符的指针),只是通过它能 “遍历” 整个字符串 —— 核心还是 “指向字符类型数据”,只是延伸出了字符串的用法。
// 常见误区纠正
// ❌ 错误理解:char* 是 “指针上存了一个字符”。✅ 正确理解:char* 是 “指针存了一个地址,这个地址对应的内存里存的是字符”。
// ❌ 错误用法:char* p = 'A';(试图把字符直接赋给指针)。✅ 正确用法:char* p = &ch;(给指针赋字符的地址)或 char* p = "hello";(给指针赋字符串首元素地址)。
// 总结
// char* 的核心定义是 “指向字符类型数据的指针”:
// 指针本身存的是 “内存地址”,不是字符;
// 通过这个地址,既能操作单个字符,也能遍历整个字符串(因为字符串是字符数组);
// 关键是 “指向的目标类型是 char”,而不是 “指针本身存字符”。
// 这其实是 C 语言的一个关键特性:char[100] 本身是 “字符数组”,既不是指针也不是字符串,但它在不同场景下会 “被当作” 指针或字符串使用,本质是 “数组名的隐式转换” 和 “字符串的存储规则” 共同导致的。
// 先明确核心概念:数组、指针、字符串的关系
// char arr[100] = {0}:这是一个字符数组,开辟了 100 字节的连续内存空间,用于存储字符({0} 表示所有元素初始化为 '\0')。
// 指针:是存储内存地址的变量(比如 char* p),本身占 4/8 字节(取决于系统),只存地址不存数据。
// 字符串:C 语言没有专门的 “字符串类型”,字符串本质是 “以 '\0' 结尾的字符数组”—— 换句话说,“字符串” 是字符数组的一种 “使用场景”(当数组里的字符以 '\0' 收尾时,它就被视为字符串)。
// 1. 为什么字符数组会 “被当作指针”?—— 数组名的隐式转换
// C 语言规定:在大多数表达式中,数组名会自动隐式转换为 “指向数组首元素的指针”(char* 类型)。比如 char arr[100] = {0},当你写 printf("%p", arr) 时,arr 会自动变成 &arr[0](数组首元素 arr[0] 的地址),所以看起来 “arr 像个指针”。
// 举个具体例子:
// c
// 运行
// char arr[100] = {0};
// char* p = arr; // 合法!arr 隐式转为 &arr[0],p 指向数组首元素
// printf("%c", *arr); // 合法!arr 转为指针后,*arr 就是 arr[0](值为 '\0')
// printf("%c", arr[3]); // 本质是 *(arr + 3):arr 转为指针后,偏移 3 个字符
// 但要注意:数组名不是指针!比如 sizeof(arr) 得到的是数组总大小(100 字节),而 sizeof(p) 得到的是指针大小(4/8 字节)—— 这能明确区分数组和指针。
// 2. 为什么字符数组会 “被当作字符串”?—— 字符串的存储规则
// 前面说过,C 语言的字符串是 “以 '\0' 结尾的字符数组”。你的代码 char arr[100] = {0} 中,{0} 会把所有元素初始化为 '\0',相当于创建了一个 “空字符串”(首元素就是 '\0')。
// 当你给数组赋值字符并保证以 '\0' 结尾时,它就完全符合字符串的定义,能被所有字符串函数(printf("%s")、strlen、strcpy 等)识别:
// c
// 运行
// char arr[100] = {0};
// strcpy(arr, "hello"); // 给数组赋值字符串 "hello"(实际存 h e l l o '\0')
// printf("%s", arr); // 合法!printf 把 arr 当作字符串,从首元素开始输出,直到 '\0'
// 如果数组没有 '\0' 结尾(比如 char arr[5] = {'h','e','l','l','o'}),它就只是一个普通字符数组,不是字符串 —— 用 %s 输出时会乱码(因为找不到 '\0',会一直读内存直到遇到随机的 '\0')。
// 总结:char[100] = {0} 的 “三重身份” 真相
// 本质身份 被当作指针的原因 被当作字符串的原因
// 字符数组(100 字节连续内存) 数组名在表达式中隐式转为 “指向首元素的指针” 数组以 '\0' 结尾,符合 C 语言字符串的定义
// 简单说:
// 你看到 “像指针”,是因为数组名自动转成了首元素地址;
// 你看到 “像字符串”,是因为数组里的字符以 '\0' 收尾,满足字符串的存储规则;
// 但它的本质永远是 “字符数组”,不是指针也不是独立的字符串类型 —— 后两者都是它的 “使用场景”。
0.0分
1 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复