「浙江理工大学ACM入队200题系列」问题 K: 零基础学C/C++84——奇偶ASCII值判断

本题是浙江理工大学ACM入队200题第八套中的K题

我们先来看一下这题的题面.

题面

题目描述

任意输入一个字符,判断其ASCII是否是奇数,若是,输出YES,否则,输出NO;

例如,字符A的ASCII值是65,则输出YES,若输入字符B(ASCII值是66),则输出NO

输入

输入为多组测试数据。

输入一个字符

输出

如果其ASCII值为奇数,则输出YES,否则,输出NO

样例输入

A

样例输出

YES

题目分析

这题其实没有任何难度,但是在acm群里问的还是挺多的,出问题的地方除了对换行的处理以外基本都是不知道在C中如何获得一个字符的ASCII码值.说到底是对char类型理解不深刻.

首先科普下什么是ASCII码(以下内容来自维基百科):

在计算机中,所有的数据在存储和运算时都要使用二进制数表示。例如,像a、b、c、d这样的52个字母(包括大写)以及0、1等数字还有一些常用的符号(例如*、#、@等)在计算机中存储时也要使用二进制数来表示,而具体用哪些二进制数字表示哪个符号,这就是编码。如果不同的计算机要想互相通信而不造成混乱,那么每台计算机就必须使用相同的编码规则,于是美国有关的标准化组织就推出了ASCII编码。

ASCII是由美国国家标准学会(American National Standard Institute,ANSI)制定的,使用标准的单字节字符编码方案,用于基于文本的数据。方案起始于50年代后期,在1967年定案。它最初是美国的标准,供不同计算机在相互通信时需共同遵守的西文字符编码标准。现已被国际标准化组织(International Organization for Standardization,ISO)定为国际标准(ISO/IEC 646),适用于所有拉丁字母。

我们知道,在C语言中存储一个字符的时候,我们使用char类型.但是不知道大家还记不记得,我们讨论数值类型的时候,我们也会说到char类型,说它是占用1个字节的数值型.

那这不矛盾吗?为啥同一个类型即是数值又是字符呢?

少年,你还是太年轻了,连波粒二象性都有了,区区一个char不能有"二象性"嘛?

在C中,如果你把char当成数值型使用(运算、用%d输出等),那么它就表现为一个数值,而当你把它作为一个字符型来使用时(作为字符串的一部分,用%c输出等),他就表现为一个字符.

比如如下代码:

	char c = 65;
	printf("%c\n", c); // 输出字符a
	printf("%d\n", (int)c); // 输出数值65(char没有自己专用格式字符,这里强制转型后用%d(强制转型仅仅是因为没有对应的格式字符而已,如果有一个对应的格式字符便可以直接输出这个数值了))
	c = 'a' + 3; // 此处'a'表现为一个整数,值为a的ASCII码值(65),然后+3,结果为68,存入变量a中
	printf("%d\n", (int)c); // 输出数值68
	printf("%c\n", c); // 输出字符d('d'的ASCII码为67,所以前面的加法从字符的角度也可以理解成顺着ASCII码表往后第n个字符)

明白了char的这个特殊的"二象性",这题的代码就很好写了吧?没错,和对一个整数判断奇偶数一模一样,因为在取模时char表现为一个整数,而且就是这个字符的ASCII码值.


常见错误

解决完char的问题之后,欢迎来到下一个乱葬岗.

很多朋友按照上面的思路写完代码,信心满满提交上去,迎头一个WA,而且通过率还是0%.


不想丸辣!

原因相对比较复杂,我们这里比较浅显的说明一下.

在我们输入数据的时候,在一组数据输完之后,是通过按下回车来完成把数据输入进去的,对吧?(不打回车就不会读进去,不用管本质,接着看,下同)

然而很不幸的是,你键入的这个回车,当你使用scanf中使用%c时,它也被当成一个字符读进来.这会导致你的一次输入出现以下情况:

image

(^Zctrl+Z,表示输入结束,此时scanf会返回EOF)

由于异常读入的回车,导致一次输入两次输出(这个问题在Java中似乎也有,在不使用Scanner对象包装Systm.in的时候,也会异常读入输入结尾的换行)

那怎么解决捏?方法有很多,这边不展开讲了,就说一种最容易的.

在相信很多朋友都已经隐约感受到了,scanf的格式控制字符中,空格似乎不仅仅代表一个空格.事实上,在空格代表的是一个空白字符,空格属于一个空白字符,啥也没有也属于一个空白字符,而换行,也属于一个空白字符.所以我们可以通过使用" %c"来滤掉空格.

相信会用getchar函数的朋友这个时候要问了,不就是一个换行嘛?换行不就是\n嘛,一个字符,我直接用一个getchar把它读了不就行了.

思路确实可行,本地跑也是完全没有问题的,但是这样提交上去依旧是WA.因为你把换行想简单了.

实际上,换行不只有\n一种写法,也可能是\r\n,具体不展开,总之在这题的评测机输入中,你必须连续调用两次getchar函数才可以读掉换行,在评测机上AC.但是这会导致你本地跑不了(因为本地换行是\n,具体原因不解释).所以为什么不在scanf里打一个空格捏?简单又可行.

这个换行问题在后续还是会碰到的,特别是scanfgets一起使用的时候.这边建议有空学一学C++的cin对象,用cin对象即可完美解决换行的问题.不过记得还要学一下怎么关闭cinscanf的同步,不然代码的常数会比较大(人话:比较慢).


参考代码

下面给出了我自己做这道题时候的完整代码:
(仅作为参考,一定要自己写一下奥,作弊没意思,害人又害己)

#include <stdio.h>

int main()
{
	char c;
	while (~scanf(" %c", &c)) // 利用空格代表空白字符,去掉换行,同时保证没有换行时代码也是正确的.看不懂~(按位非)就写scanf(" %c", &c) != EOF
	{
		if (c % 2) // 即奇数(养成习惯不要==1,因为负奇数,虽然这里不可能会是负数)
		{
			printf("YES\n");
		}
		else // 即偶数
		{
			printf("NO\n");
		}
	}
	return 0;
}

"正是我们每天反复做的事情,最终造就了我们,优秀不是一种行为,而是一种习惯" ---亚里士多德

这篇题解就到这里了,各位朋友如果有问题欢迎到acm成员群中提问哦!

posted @ 2022-10-03 16:34  星双子  阅读(339)  评论(0编辑  收藏  举报