【问题标题】:How to handle user input errors如何处理用户输入错误
【发布时间】:2015-01-09 14:27:26
【问题描述】:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

struct vector
{
    double x;
    double y;
    double z;
};

struct vector *array;
double length(struct vector*);

int main()
{
    int num,i;
    double xin;
    double yin;
    double zin;
    char buffer[30];
    char buffer2[30];

    printf("Enter number of vectors:");
    fgets(buffer, 30, stdin);
    sscanf(buffer, "%d", &num);

    array = malloc( sizeof(struct vector) * num);

    for(i=0;i<=num;i++)
    {
        printf("Please enter x y z for the vector:");
        fgets(buffer2,100,stdin);
        sscanf(buffer2, " %lf %lf %lf", &xin, &yin, &zin);

            array[i].x = xin;
            array[i].y = yin;
            array[i].z = zin;
    }

    for(i=0;i<=num;i++)
    {
        printf( "Vector:%lf %lf %lf has a length of %lf\n", array[i].x, array[i].y, array[i].z, length(&array[i]));
    }
}


double length(struct vector* vec)
{
    return sqrt( (vec->x * vec->x) + (vec->y * vec->y) + (vec->z * vec->z) );
}

好的,上面的代码差不多完成了,它询问用户向量的数量,然后它询问用户这些向量的值,然后它会计算长度并相应地打印出来。

我试图在这里检查一些错误,但我似乎无法得到它...我查找了 fgets 和 sscanf 的所有可能返回值,但我似乎无法得到它

防御功能

FIRST printf-----input 只能是大于 0 的单个数字,EOF 应该返回类似 printf("enter a number--bye!") 的消息,所以我尝试了

while( sscanf(buffer, "%d", &num) ==1 && num > 0 )

但如果输入 3dadswerudsad 之类的内容,它仍然有效

此外,当用户输入向量的 3 个值时,如果为向量输入了除 3 个双精度之外的任何值,则程序应该以一条消息终止,所以我尝试了

while( sscanf(buffer2, "%lf %lf %lf", &xin, &yin, &zin) ==3 )

但它不会检查这些不正确的输入!!

我要疯了

【问题讨论】:

  • 您的 sscanf 正在按预期工作。您已经告诉它扫描 %d - 任何十进制数。由于输入的字符串以3 开头,sscanf 会发现 3...另外,您的长整数 sscanf 在模式的开头有一个空格...
  • 如果当前行不是有效输入,您应该读取一个新行,可能在while 循环中。
  • 所以没有办法绕过以数字开头的线路?
  • 您始终可以采用两步方法:使用%s 而不是数字扫描字符串,然后通过使用strtol 测试该字符串来验证它是否是有效数字。 (strtol 为您提供了指向已解析数字之后的最后一个字符的指针,对于有效数字,该指针应为 '\0'。)
  • 0) i&lt;=num --> i&lt;num, char buffer2[30]; --> char buffer2[100];

标签: c data-structures error-handling structure


【解决方案1】:

以下代码:

  • 编译干净
  • 显示了几个错误检查示例

发布的代码引发了编译器警告,即在没有返回语句的情况下到达非 void 函数的末尾(需要更正警告)。
要查看所有警告,请在为gcc 编译时启用所有警告,使用参数:-Wall -Wextra -Wpedantic

顺便说一句:正确声明结构的荣誉

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

struct vector
{
    double x;
    double y;
    double z;
};

struct vector *array;

// prototypes
double length(struct vector*);

int main()
{
    int num,i;
    double xin;
    double yin;
    double zin;
    char buffer[30];
    char buffer2[30];

    printf("Enter number of vectors:");
    if( NULL == fgets(buffer, 30, stdin) )
    { // then fgets failed
        perror( "fgets for num vectors failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, fgets successful

    if( 1 != sscanf(buffer, " %d", &num) )
    { // then sscanf failed
        perror( "sscanf for num Vectors failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, sscanf failed


    // add validation of num here


    if( NULL == (array = malloc( sizeof(struct vector) * num) ))
    { // then, malloc failed
        perror( "malloc for num Vectors failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, malloc successful


    for(i=0;i<=num;i++)
    {
        printf("Please enter x y z for the vector:");
        if( NULL == fgets(buffer2,100,stdin) )
        { // then fgets failed
            perror( "fgets for vector values failed" );
            free(array); // cleanup
            exit( EXIT_FAILURE );
        }

        // implied else, fgets successful

        if( 3 != sscanf(buffer2, " %lf %lf %lf", &xin, &yin, &zin) )
        { // then sscanf failed
            perror( "sscanf for vector values failed" );
           free(array); // cleanup
            exit( EXIT_FAILURE );
        }

        // implied else, sscanf successful

        array[i].x = xin;
        array[i].y = yin;
        array[i].z = zin;
    } // end for

    for(i=0;i<=num;i++)
    {
        printf( "Vector:%lf %lf %lf has a length of %lf\n",
                array[i].x,
                array[i].y,
                array[i].z,
                length(&array[i]));
    } // end for

    free(array); // cleanup

    return(0);
} // end function: main

【讨论】:

  • 两个问题。请参阅问题下方的 BLUEPIXY 评论。另外,你的代码能解决 OP 的问题吗?
  • OP 对输入中多余字符的担忧对 OPs 代码的操作没有影响。这个例子简单地展示了如何执行错误检查。事实上,OP 已经通过使用 fgets 和 sscanf 处理了指示的问题。
  • 我知道。但是 OP 想要一个像 2xyz(假设是第一个 fgets)这样的输入来在显示错误消息后停止程序。另外,你还没有解决我在第一条评论中告诉你的两个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-08
  • 2013-08-08
相关资源
最近更新 更多