【问题标题】:Simple C Code Error简单的 C 代码错误
【发布时间】:2014-08-16 13:25:55
【问题描述】:

有谁知道为什么我在运行此代码时会出现段错误? Valgrind 告诉我,我在第 13 行 if( !isdigit(x) ) 上有“大小为 4 的未初始化值”,并且在同一行上有一个无效的读取大小 2——地址没有被堆栈, malloc'd 或 free'd。

#include <stdio.h> 
#include <stdlib.h>
#include <ctype.h>
#include <stdbool.h>

int main()
{
    int x;

    printf("Please enter a number: ");
    scanf("%d", &x);

    if( !isdigit(x) )
    {
        printf("You entered %d\n", x);
    }
    else
    {
        printf("You did not enter a valid number!\n");
    }

    return 0;
}

【问题讨论】:

  • isdigit 用于处理字符值;例如,对于 '1' 的输入,它将返回 true,对于 'a' 的输入,它将返回 false。您输入的内容是什么?
  • 如果您使用%disdigit() 不会以您希望的方式工作。例如,如果输入1x 将不包含字符1 的ASCII 码,因此isdigit() 将返回false。
  • 请记得经常检查输入是否成功:scanf(...) == 1?
  • 不相关,但如果输入不是数字,scanf 将失败。因此,您可以将其替换为 scanf 的结果,而不是检查“isdigit”。
  • "得到一个段错误" - 这不是一个段错误。

标签: c stack malloc free


【解决方案1】:

我认为问题在于如果scanf 失败,x 将被未初始化。 最好在字符数组中输入数据。否则,您的代码将毫无意义,因为您无法在 int 类型的对象中输入非数字。此外,如果您输入一个数字,使用函数isdigit 的结果可能会出乎意料。

【讨论】:

  • 我不认为是解决方案。例如,如果您用零值初始化 x,然后输入“dkj”,则输出将是您输入了 0。这不是他想要的。当然,使用默认值初始化变量始终是一个好习惯。谢谢。
【解决方案2】:

我用 g++ 编译了你的代码,没有出现段错误。

输入值:

5、-1、27、43545gbb 和 gggg

产生的结果:

5、-1、27、43545 和 1729208414

【讨论】:

  • 您的输入会导致未定义的行为。你没有遵守isdigit 的前提条件。更不用说从最后的输出中可以清楚地看出您正在使用未初始化的变量。简而言之,虽然这对您(现在)没有段错误,但它可以在任何时候。
【解决方案3】:

为什么第 13 行出现问题?。第 13 行是if( !isdigit(x) )
在第 8 行创建 x 时,您没有初始化它,
因此,如果输入了一个不可接受的值,并在第 11 行由scanf() 处理,则在它到达isdigit() 函数时将继续未初始化。

问题在于isdigit() 期望输入必须是整数值介于 0 和 255 之间的字符。任何其他值都会导致未定义的行为段错误是未定义行为的可能结果之一。

还有其他方法可以实现,例如:
这是一个使用 char 数组(字符串)的示例。请注意 cmets 以解释为什么要完成某些事情。

int main()
{
    //int x;
    char x[2];  //Good for only one digit

    printf("Please enter an integer with up to 10 digits: ");
    //scanf("%d", &x); 
    scanf("%1s", x); //Edited to allow maximum field width of 1.

   // if( !isdigit(x) )        
    if( isdigit(x[0]) ) //note the "!" was removed for logic to work
    {
        printf("You entered %d\n", atoi(x)); //note use of atoi() to convert string to int.
    }
    else
    {
        printf("You did not enter a valid number!\n");
    }

    return 0;
}

【讨论】:

  • isdigit 接受int。只是你给它的int必须在unsigned charEOF的范围内。
  • 当您可以查看if scanf(%d)==1 时,为什么要读取字符串并进行转换?
  • @prajmus - 是的,scanf() 会起作用。但是一个字符数组也是如此。因为 isdigit() 是一个字符测试器,所以我认为以 char 类型为例来说明使用该函数会更好。此外,这里的核心问题是为什么会出现段错误?这可以通过解决作​​为参数传递给 isdigit 的非法值来解决。
  • char x[2]; scanf("%s", x); - 没有。
  • @MattMcNabb - 使用扩展缓冲区进行编辑。让我知道这是否不是问题所在。谢谢。
【解决方案4】:

尝试以下方法:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int x = 0;
    char a;

    printf("Please enter a number: ");

    while(scanf("%d%c",&x,&a) != 2 || a != '\n')
    {
        printf("Please enter an integer only : ");
        do
        {
            scanf("%c",&a);
        }while(a != '\n');
    }

    printf("You entered %d\n", x);
    return 0;
}

代码向您展示了如何使用 scanf 的复杂方法。欲了解更多信息:Working of scanf and checking if input is int

根据 c 文档:isdigit

原型:

int isdigit( int ch );

参数:

ch  -   character to classify

目的:

检查给定字符是否为数字字符 (0123456789)。 如果 ch 的值不能表示为 unsigned char 且不等于 EOF,则行为未定义。

返回值:

如果字符是数字字符,则为非零值 (true),否则为 0 (false)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-19
    • 2011-09-21
    • 2014-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多