程序设计基础第四周答疑要点整理
输入不定个数字符时,不要通过换行符''判断结尾
有的同学在做E4-B
《从十进制数到2421码》时,使用while((c = getchar()) != '\n')
语句来实现不定个数字符输入,但提交上OJ会发现结果为TLE
(超时)。这是因为OJ是通过读取测试点输入文件的方式实现输入的,题目中并没有规定以换行符'\n'
作为输入的结尾,那么输入文件的最后就不一定会有'\n'
,当代码始终读不到'\n'
时,就会一直循环执行循环体代码块,导致超时。
正确的做法是使用while ((c = getchar()) != EOF)
或while (scanf("%c", &c) !=EOF)
。
不定组输入时怎么在本地调试
当题目中要求不定组数据输入时,常用读入方式为while (scanf()!=EOF){}
(其中scanf
函数的括号里需要根据读入内容填入合适的格式字符串和变量序列),此时本地调试中如果要输出最终的结果,需要我们手动输入文件结束符表示输入结束,输入方式为在最后一行数据后输入回车,在下一行行首先按住ctrl
键,再按下Z
键,此时程序运行控制台中显示输入了^Z
,然后再次输入回车,将上述内容送入自己编写的程序,这样就可以起到控制台输入文件结束符的作用。以C4-E
《真实命中率》的样例输入为例:
输入样例数据操作展示:
注意:此时输入控制台的最后一行为一个控制字符ctrl Z
,是通过先按住ctrl
键然后按下Z
键的方式输入的,而不是^
与Z
两个字符
结束输入后,在ctrl Z
后按下回车,输出结果:
百分数字面值不存在,要写成小数
不存在形如x%
的百分数字面值,应当使用百分数对应的浮点数字面值。
也就是说,没有这样的写法:
1 |
|
如需要用10%
时应当使用0.1
,即:
1 |
|
不要以变量作为数组的大小
固定大小的数组在声明时,可以通过赋值的方式直接初始化,例如:
1 |
|
有些同学使用变量作为数组长度,并且试图像上面一样初始化:
1 |
|
但是他们发现本地上可以运行,但是提交到OJ上显示编译失败,这是为什么呢?
事实上,编译失败的提示信息是:
1 |
|
本地可以编译,但是提交上去却不通过,可能的原因是本地代码文件在新建后保存时默认为cpp
类型,代码语法为C++,也就是说本地运行的代码实际上是C++代码。判断方式是查看当前打开代码文件的后缀名,若为.c
则表示这个文件是C语言代码文件,若为.cpp
则表示这个文件是C++语言代码文件:
为了避免出现代码本地编译运行正常而OJ上CE
的问题,这里要求大家在新建代码文件并保存时必须将后缀名改为.c
,这样就可以在本地编译运行代码时发现上述问题。如下图所示,在“保存类型”一栏中选择C source files(*.c)
选项后保存:
另外,强烈不建议在声明数组时以变量作为数组的大小。即:数组的长度必须要在程序开始运行之前确定。
建议根据数据范围上限,直接声明一个一定满足题目所有要求的固定大小数组,然后根据其他输入数据的范围使用这个数组的一部分或全部位置。
switch-case
语句的一些问题
switch-case
结构中,当被switch
语句判断的变量满足某个case
分支的条件时就会使代码运行进入该分支。但与if
不同的是:在该case
分支中的语句执行完后,如果没有break
语句来跳出switch-case
结构,那么会继续执行后面case
分支中的语句。举例如下:
带break
的switch-case
结构及其执行结果:
不带break
的switch-case
结构及其执行结果:
因此,我们建议:switch
中的 case
和 default
必须以 break
终止,如果存在极特殊的情况需要共用 case
,必须加以明确注释。
另外还发现有人在case
里面用continue
的,没有这样的用法,也不允许出现。
整除运算和模运算的一点性质
C99标准规定,整型除法的结果向0取整,也就是说,当对应实数除法的结果为正时,整除结果为实数除法结果向下取整,当对应实数除法的结果为负时,整除结果为实数除法结果向上取整。例如:
1 |
|
模运算的两个运算数只能是整型变量,当整型变量a,b
都为正数时,模运算a % b
的结果范围为0 ~ b-1
执行模运算时需要考虑待取模的数的符号。模运算a % b
的结果并不总是非负的,当取模结果不为0时,结果的符号取决于a
的符号,结果的绝对值为:a
的绝对值 对 b
的绝对值 取模的值。例如:
1 |
|
unsigned int
类型变量使用的一个隐蔽问题
unsigned int
类型变量表示无符号整型,有的同学会认为当确保不会存入负数的时候就可以使用该类型,事实上这是不合适的。因为当unsigned int
类型变量被用作和int
类型变量比较时,会隐式地将int
变量中存的数转换为unsigned int
类型,当参与比较的int
类型变量原本保存的值为负数时,这步转换会导致运行结果与预期完全不符,且很难发现问题所在。当对unsinged int
类型变量的值进行修改时,如果该变量的新值为负数,同样会产生问题。例如:
1 |
|
上面的代码会运行6次循环就结束吗?错了!事实上上面的代码是一个无限循环。因为unsigned int
变量能表示的值中不存在负数,当i == 0
时执行i--
时,i
变量空间中存储的二进制比特位会变成-1
的补码形式,而由于变量i
为unsigned int
类型,此时变量i
的值事实上是unsigned int
类型变量所能表示的最大值。所以i >= 0
条件将永远满足,循环也将永远执行下去。
下面的代码输出了unsigned int
类型的0
减去1
后得到的值的十进制与十六进制形式,也证实了上述情况:
综上所述:使用unsigned int
类型变量时,需要慎重考虑变量可能的范围。