难以使用scanf进行输入

时间:2015-12-04 08:36:48

标签: c scanf

有人可以帮我解决问题吗?我对%[^\n]有疑问。当我尝试输入错误输入时程序循环我写的警告,但如果我使用%s并输入我的字符串,则下一个语句无法正常工作。

#pragma warning (disable:4996)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int main(){
    char name[30];
    char number[12];
    int flag, flag1, flag2, flag3;
    int i;


    printf("Add New Contact\n");
    do {

    printf("input name [1..30 char]: ");
    scanf("%[^\n]", name); fflush(stdin); 

        if ((name[0] >= 'A' && name[0] <= 'Z') || (name[0] >= 'a' && name[0] <= 'z')) {
            flag = 1;
        }
        else {
            flag = 0;
            printf("First letter of name should be an alphabet (A-Z or a-z)\n");

        }

        if (strlen(name) > 30) {
            flag1 = 0;
            printf("Length of name should be between 1 and 30 characters\n");
        }
        else {

            flag1 = 1;
        }



    } while (flag == 0 || flag1 == 0);

    do {
        printf("Input phone number[6..12 digits]: ");
        scanf("%s", number); fflush(stdin);

        for (i = 0; i < strlen(number); i++) {
            if (number[i] >= '0' && number[i] <= '9') {
                flag2 = 1;
            }
            else {
                flag2 = 0;
            }
        }
        if (flag2 == 0) {
            printf("Phone numbers should only contain digits (0-9)\n");
        }
        if (strlen(number) >= 6 && strlen(number) <= 12) {
            flag3 = 1;
        }
        else {
            flag3 = 0; 
            printf("Length of phone numbers should be between 6 and 12 digits\n");
        }



    } while (flag2 == 0 || flag3 == 0);

    printf("\n");
    printf("New contact successfully added!\n");
    printf("Press Enter to continue...");

    getchar();
    getchar();
    return 0;
}

2 个答案:

答案 0 :(得分:2)

哦顺便说一下,问题可能只是scanf调用将换行符留在缓冲区中,如果循环再试一次,看到的第一个字符将是换行符,scanf应该不读任何东西。

您应该做两件事:首先检查scanf 返回的内容,如果它读取字符串,则应返回1。其次,您应该通过在格式字符串scanf中首先添加空格来告诉" %[^\n]"丢弃任何可能的前导空格。

大多数scanf格式会自动跳过前导空格,但在使用"%[""%c"格式时则不会。

另外,为了不用担心写出数组的界限,你应该添加一个长度修饰符,以确保scanf没有读取比它可以写的更多的输入:" %29[^\n]" 。如果在此之后字符串的长度为29,那么您应该阅读,直到您逐字符到达行尾。

答案 1 :(得分:1)

这是你的程序修复:

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

// In case you need this -- not needed for this case
void discard_input()
{
    char c;

    while( ( c = getchar() ) != '\n' && c != EOF );
}

void remove_trailing_newline(char * s)
{
    char * ch = s + strlen( s ) - 1;

    while( ch != s ) {
        if ( *ch == '\n' ) {
            *ch = 0;
            break;
        }

        --ch;
    }

    return;
}

int main(){
    char name[30];
    char number[12];
    int flag, flag1, flag2, flag3;
    int i;


    printf("Add New Contact\n");
    do {

    printf("\nInput name [1..30 char]: ");
    fgets( name, 30, stdin );
    remove_trailing_newline( name );
    flag1 = flag = 1;

        if ( !isalpha( name[ 0 ] ) ) {
            flag = 0;
            printf("First letter of name should be an alphabet (A-Z or a-z), found: %s\n", name );

        }

        // impossible
        if (strlen(name) > 30) {
            flag1 = 0;
            printf("Length of name should be between 1 and 30 characters\n");
        }

    } while (flag == 0 || flag1 == 0);

    do {
        printf("\nInput phone number[6..12 digits]: ");
        fgets( number, 12, stdin );
        remove_trailing_newline( number );
        flag2 = flag3 = 1;
        int len_phone = strlen( number );

        for (i = 0; i < strlen(number); i++) {
            if ( !isdigit( number[ i ] ) ) {
                flag2 = 0;
            }
        }

        if (flag2 == 0) {
            printf("Phone numbers should only contain digits (0-9), found:'%s'\n", number);
        }

        if ( len_phone < 6 || len_phone > 12) {
            flag3 = 0; 
            printf("Length of phone numbers should be between 6 and 12 digits, found: %d\n", len_phone );
        }

    } while (flag2 == 0 || flag3 == 0);

    printf("\n");
    printf( "Name: '%s'\n", name );
    printf( "Phone: '%s'\n", number );
    printf("New contact successfully added!\n");
    printf("Press Enter to continue...");
    getchar();
    return 0;
}

您可以找到程序here

这些定价或多或少都很有趣,我在这里列举一下:

  • 起初,我认为问题是尾随的新行被留在输入缓冲区中。 fflush(stdin)实际上是C中的未定义行为,因为fflush()函数用于输出流。无论如何,我将代码包含在question 12.26b of the comp.lang.c FAQ中,因为我认为它正在将其作为参考。然后,我决定使用scanf()更改fgets()。这是因为scanf()将空格作为分隔符,因此您无法写出完整的名称,即姓名和姓氏。请记住,gets()不是一个选项,因为它将输入写入缓冲区的限制。实际上,fgets()通过让我们定义要读取的字符限制来解决这个问题。问题是fgets()还包括&#39; \ n&#39;在缓冲区中,这就是我包含remove_trailing_newline()函数的原因。整蛊,不是吗?

  • 您添加了一个条件来检查名称输入是否超过30个字符。实际上,这是不可能检查你的程序。首先,fgets()将读取29个字符+最终字符标记(0)。其次,如果你实际上允许输入超过30个字符,那么输入将被写入超过缓冲区的大小,这是未定义的行为(在大多数情况下崩溃)。你必须使用更复杂的东西,比如C ++中的 std :: string ,然后检查它的长度。或者也许可以使用第三方展开式string代替C.或推出自己的expandable string ...

  • 您可以使用isalpha(c)isdigit(c)函数来判断是否存在字母字符或数字。

  • 当您要多次使用某个值时,例如strlen(name),那么您应该预先计算它并将其存储在局部变量中。虽然一个好的编译器(它的优化器)会检测到这种情况并为你解决它,但你永远不知道哪个编译器会编译你的代码,以及它有多高级。此外,优化器更容易使事情变得简单。

  • 如果您在某种情况下设置了用于发出错误信号的信号,则更容易将其设置为&#34;无错误&#34;在检查任何内容之前的值,并且仅在出现错误的情况下,将其设置为&#34;错误&#34;值。这将更容易阅读,因此,要理解。

希望这有帮助。