isdigit(c) - char或int类型?

时间:2017-07-10 04:24:08

标签: c++

我编写了以下代码来测试给定输入是否为数字。

#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?

2 个答案:

答案 0 :(得分:5)

不幸的是,情况比其他答案所说的要复杂得多。

首先:代码的第一部分是正确的(忽略多字节编码);如果您想使用char阅读单个cin,则必须使用char变量与>>运算符。

现在,关于isdigit:为什么需要int代替char

这一切都来自C; isdigit及其伴侣的诞生与getchar()等函数一起使用,这些函数从流中读取字符并返回int。这反过来是为了提供字符错误代码:getchar()可以通过返回代码返回EOF(定义为一些实现定义的负常量)表示输入流已结束。

所以,基本思路是:否定=错误代码; positive =实际字符代码。

不幸的是,这会导致“常规”char的互操作性问题。

简短的题外话:char最终只是一个范围非常小的整体类型,但却是一个特别愚蠢的类型。在大多数情况下 - 使用字节或字符代码时 - 您希望它默认为unsigned; OTOH,出于一致性原因与其他整数类型(intshortlong,...),你可以说正确的事情是普通char应该是signed。标准选择了最愚蠢的方式:普通charsignedunsigned,取决于编译器的实现者决定 1

因此,您必须为char signedunsigned做好准备;在大多数实现中,默认情况下它是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之前检查流是否仍处于有效状态。

  1. 当然这有点不公平;正如 @Pete Becker 在下面的评论中提到的那样,并不是说他们都是白痴,而是标准大多数都试图与现有的实现兼容,这些实现可能在无符号和有符号{{{ 1}}。在大多数现代编译器中都可以找到此拆分的痕迹,这通常可以通过命令行选项更改char的签名(char / -fsigned-char用于gcc / clang,-funsigned-char在VC ++)。

答案 1 :(得分:0)

如果你想读一个字符并检查它是否是数字,那么它应该是字符。

如果将其设置为int,则将读取多个字符,并且isDigit的结果将始终为true。