我编写了以下代码来测试给定输入是否为数字。
#include<iostream>
#include<ctype.h>
#include<stdio.h>
using namespace std;
main()
{
char c;
cout<<"Please enter a digit: ";
cin>>c;
if(isdigit(c)) //int isdigit(int c) or char isdigit(char c)
{
cout<<"You entered a digit"<<endl;
}
else
{
cout<<"You entered a non-digit value"<<endl;
}
}
我的问题是:输入变量类型应该是什么? char还是int?
答案 0 :(得分:5)
不幸的是,情况比其他答案所说的要复杂得多。
首先:代码的第一部分是正确的(忽略多字节编码);如果您想使用char
阅读单个cin
,则必须使用char
变量与>>
运算符。
现在,关于isdigit
:为什么需要int
代替char
?
这一切都来自C; isdigit
及其伴侣的诞生与getchar()
等函数一起使用,这些函数从流中读取字符并返回int
。这反过来是为了提供字符和错误代码:getchar()
可以通过返回代码返回EOF
(定义为一些实现定义的负常量)表示输入流已结束。
所以,基本思路是:否定=错误代码; positive =实际字符代码。
不幸的是,这会导致“常规”char
的互操作性问题。
简短的题外话:char
最终只是一个范围非常小的整体类型,但却是一个特别愚蠢的类型。在大多数情况下 - 使用字节或字符代码时 - 您希望它默认为unsigned
; OTOH,出于一致性原因与其他整数类型(int
,short
,long
,...),你可以说正确的事情是普通char
应该是signed
。标准选择了最愚蠢的方式:普通char
是signed
或unsigned
,取决于编译器的实现者决定 1 。
因此,您必须为char
signed
或unsigned
做好准备;在大多数实现中,默认情况下它是signed
,这会导致上面的getchar()
排列出现问题。
如果char
用于读取字节且为signed
,则意味着所有具有高位设置的字节(AKA字节,以unsigned
8位类型读取将是&gt; 127)结果为负值。这显然与使用getchar()
的否定值的EOF
不兼容 - 实际的“否定”字符与EOF
之间可能存在重叠。
因此,当C函数谈到在int
变量中接收/提供字符时,契约总是假定该字符被char
强制转换为unsigned char
(这样它总是正的,负值溢出到其范围的上半部分)然后放入int
。这将我们带回isdigit
函数,该函数在其伴随函数中也有此契约:
标题
<ctype.h>
声明了几个对字符分类和映射有用的函数。在所有情况下,参数都是int
,其值应表示为unsigned char
或等于宏EOF
的值。如果参数具有任何其他值,则行为未定义。
(C99,§7.4,¶1)
所以,长话短说:你的if
至少应该是:
if(isdigit((unsigned char)c))
问题不仅仅是理论问题:几个广泛使用的C库实现直接使用提供的值作为查找表的索引,因此负值将读入未分配的内存并对程序进行分段。
此外,您没有考虑流可能会被关闭的事实,因此>>
返回时不会触及您的变量(这将是未初始化的值);要考虑到这一点,您应该在处理c
之前检查流是否仍处于有效状态。
char
的签名(char
/ -fsigned-char
用于gcc / clang,-funsigned-char
在VC ++)。答案 1 :(得分:0)
如果你想读一个字符并检查它是否是数字,那么它应该是字符。
如果将其设置为int,则将读取多个字符,并且isDigit的结果将始终为true。