[编程题]01、ASCII码排序

目录

前言:

1、题目展示:

 2、问题分析:

1、首先先要解决输入问题。

2、解决排序问题

3、最终代码展示: 


前言:

从今天起开启全新专栏

c语言基础语法编程题100题!

专栏链接

c语言基础语法编程题_1zero10的博客-优快云博客

1、题目展示:

 2、问题分析:

1、首先先要解决输入问题。

要求:输入多组数据,每组占一行,有三个字符组成,之间无空格

有空格的输入需要使用fgets或者gets_s

输入三个字符中间无空格,那么只需要用scanf即可

char a,b,c;
scanf("%c%c%c",&a,&b,&c);

那么关键在于如何一次输入多组数据呢?

这里就会联想到循环,本题每一组输入3个字符,那么循环条件是输入的字符个数为3,如果不等于3就跳出循环

那么循环条件要怎么写,我们应该还记得scanf的返回值和我们输入的数的个数有关

以scanf("%d%d",&a,&b);举例

* 输入两个数:返回2。
* 输入部分正确(如一个数字和一个非数字):返回1。
* 输入完全无法解析(如两个非数字):返回0。
* 遇到EOF:返回EOF(-1)

那么只要我们让循环条件为scanf返回值始终等于3,那么我们一直每组输入3个数就不会跳出循环,如下

while(scanf("%c%c%c",&a,&b,&c)==3){
    printf("%c %c %c",a,b,c);
}

但是上面的代码忽略了一个问题

先介绍缓冲区的概念

输入缓冲区是临时存储用户输入数据的内存区域。例如,当用户通过键盘输入 `Hello\n` 时:

* **缓冲区内容**:`H`, `e`, `l`, `l`, `o`, `\n`。
* **换行符的提交作用**:按下回车键(生成 `\n`)会将缓冲区内容提交给程序。

问题场景:

若程序仅读取部分数据(如 `scanf("%s", str)` 读取 `"Hello"`),剩余的 `\n` 会残留在缓冲区中,导致后续输入函数(如 `fgets()` 或 `getchar()`)意外读取到换行符

也就是第一次输入abc之后\n留在了缓冲区,导致下一次while循环scanf读取的第一个字符是换行符\n,导致程序错乱,输入不了多组字符如下

因此我们 在输完每一行之后,要让电脑去掉换行符,清理缓冲区。怎么做呢?

先把代码写下来,我们慢慢来分析

int ch;
while ((ch = getchar()) != '\n' && ch != EOF);

第一行定义一个叫ch的整型变量

第二行一个while语句,语句内部没有需要循环体语句和条件控制语句

那么就是只要满足括号内的条件判断语句,就不断的把上一次变量的ch值覆盖掉,让下一次getchar的值可以赋值进来,仅通过不断读取并覆盖 `ch` 变量来清空缓冲区。

那么现在着重分析括号内的条件判断语句

(ch = getchar()) != '\n' && ch != EOF

一个复杂的表达式,进行拆解

(ch = getchar()) != '\n' )&&( ch != EOF)

就是当两边的不等于关系运算符都成立时,条件判断语句成立

先看左边

getchar是一个系统函数,包含在头文件stdio.h里

作用是:从标准化输入设备(比如键盘)读取一个字符,不需要传参数(也就是括号里什么东西都不用写)

返回值是读取字符的ASCII码值

那么ch = getchar()) != '\n'的意思就是,getchar把读取的字符的返回值赋值给变量ch,与‘\n换行符的ASCII码值进行比较

当ch的值不等于‘\n换行符的ASCII码值时,成立

也就是如果getchar读取到换行符,则ch = getchar()) != '\n'这个表达式不成立

再看右边

ch != EOF,EOF时文件结束符,时程序结束的标志

那么如果getchar读取的字符是EOF,并且赋值给了ch

那么ch=EOF,表达式不成立

因此while ((ch = getchar()) != '\n' && ch != EOF);整句话的意思就是

只要遇到换行符和EOF文件结束符循环就结束了,那么你肯定有疑问,循环结束了怎么清理缓冲区里的换行符

当你输入一行字符(例如`abc`后按回车),`getchar()`会逐个读取字符`a`、`b`、`c`,最后读取换行符`\n`。此时,`ch`被赋值为`\n`,循环条件失败,**循环终止**。关键点在于:**换行符`\n`已经被`getchar()`读取到`ch`中**,因此输入缓冲区中不再残留该换行符

**EOF的处理**:如果输入以`EOF`结束(例如通过`Ctrl+D`或`Ctrl+Z`触发),`getchar()`会返回`EOF`,循环同样终止。需要注意的是:

* 在终端输入中,若`EOF`之前无换行符(例如输入`abc`后直接`Ctrl+D`),`EOF`会被“吃掉”(即不被`getchar()`读取),输入缓冲区中仅保留已处理的字符。
  
* 若`EOF`之前有换行符(例如输入`abc\n`后`Ctrl+D`),则换行符会被读取,`EOF`作为文件结束标志终止输入。
  

**缓冲区的最终状态**在循环终止后,**所有字符(包括换行符或`EOF`)均已从缓冲区中取出**。因此,无需额外清理缓冲区

当用户从键盘输入数据时,数据首先存储在输入缓冲区中,而不是直接传递给程序。只有当用户按下回车键或缓冲区满时,缓冲区中的数据才会被传递给程序。输入缓冲区通常在遇到换行符时刷新,这意味着程序会读取缓冲区中的数据直到遇到换行符为止

当第一次while循环时,输入的字符都存在缓冲区里,当你换行时,虽然前面输入的字符被刷新了但,换行符留了下来

while(scanf("%c%c%c",&a,&b,&c)==3){ printf("%c %c %c",a,b,c);}

那么整个多组数据输入并且输出的代码是怎么样的,电脑又是怎么处理的

2、解决排序问题

随意输入三个字符,要把他们进行排序

排序问题我们这里介绍利用变量转换的思想的方法,这是大家总结经验验证出来的方法,从小到大排序就用这个方法,也非常好记

char a,b,c,t;
scanf("%c%c%c",&a,&b,&c);
//假设a=3,b=4,c=1 拿数字举例是一样的
if(a>b){
    t=a,a=b,b=t; //不满足,不执行这一句
}
if(a>c){
    t=a,a=c,c=t; //a=1,c=3
}
if(b>c){
    t=b,b=c,c=t; //b=3,c=4
}
printf("%c %c %c\n",a,b,c);//这样按顺序输出a b c,就是按ASCII码值从小到大 的顺序了

扩展 从大到小怎么排序

char a,b,c,t;
scanf("%c%c%c",&a,&b,&c);
//假设a=3,b=4,c=1
if(a<b){
    t=a,a=b,b=t; // a=4, b=3
}
if(a<c){
    t=a,a=c,c=t; //不执行
}
if(b<c){
    t=b,b=c,c=t; //不执行
}
printf("%c %c %c\n",a,b,c);//这样按顺序输出a b c,就是按按ASCII码值从大到小的顺序了

再优化一下,我们把这个排序的代码变成函数,用到了指针

void paixu(char*a,char*b,char*c){  //void是没有返回值的函数,所以我们不用写return 返回值 //a,b,c是传入的参数
    char t;
    if(*a>*b){
    t=*a,*a=*b,*b=t; 
}
    if(*a>*c){
    t=*a,*a=*c,*c=t; 
}
    if(*b>*c){
    t=*b,*b=*c,*c=t; 
}

}

3、最终代码展示: 

注意在main函数里a,b,c的值要传进paixu函数,涉及值传递,需要用到指针

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void paixu(char* a, char* b, char* c) {  
    char t;
    if (*a > *b) {
        t = *a, * a = *b, * b = t;
    }
    if (*a > *c) {
        t = *a, * a = *c, * c = t;
    }
    if (*b > *c) {
        t = *b, * b = *c, * c = t;
    }

}
int main() {
    char a, b, c;
    while (scanf("%c%c%c", &a, &b, &c) == 3) {
        int ch;
        while ((ch = getchar()) != '\n' && ch != EOF);
        paixu(&a, &b, &c);
        printf("%c %c %c\n", a, b, c);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值