在scanf之后fgets不起作用

时间:2011-05-06 23:37:44

标签: c scanf fgets

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

void delspace(char *str);

int main() {
    int i, loops;
    char s1[101], s2[101];

    scanf("%d", &loops);

    while (loops--) {
        fgets(s1, 101, stdin);
        fgets(s2, 101, stdin);
        s1[strlen(s1)] = '\0';
        s2[strlen(s2)] = '\0';

        if (s1[0] == '\n' && s2[0] == '\n') {
            printf("YES\n");
            continue;
        }

        delspace(s1);
        delspace(s2);

        for (i = 0; s1[i] != '\0'; i++)
            s1[i] = tolower(s1[i]);

        for (i = 0; s2[i] != '\0'; i++)
            s2[i] = tolower(s2[i]);

        if (strcmp(s1, s2) == 0) {
            printf("YES\n");
        }
        else {
            printf("NO\n");
        }
    }

    return 0;
}

void delspace(char* str) {
    int i = 0;
    int j = 0;
    char sTmp[strlen(str)];

    while (str[i++] != '\0') {
        if (str[i] != ' ') {
            sTmp[j++] = str[i];
        }
    }
    sTmp[j] = '\0';
    strcpy(str, sTmp);
}

输入“循环”后,“s1”自动分配一个空行。怎么会发生?我确定我的键盘工作正常。

10 个答案:

答案 0 :(得分:18)

scanf()准确读取您的要求,将\n从缓冲区中该行的末尾留下fgets(),其中fgets()将读取它。要么使用换行符,要么(我的首选解决方案)sscanf()然后从该字符串中使用{{1}}。

答案 1 :(得分:5)

scanf在输入缓冲区中留下空格,包括换行符。要使用fgets读取下一行,您需要手动删除当前行的其余部分:

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

答案 2 :(得分:2)

Vayn,

Geekoaur已经很好地回答了你的问题,我只是用你的代码指出了另一个“问题”。

s1[strlen(s1)] = '\0';行是no-op,如果s1在执行之前已经正确地以空值终止。

但是,如果s1并未正确地在此行执行之前正确地终止(并且您运气不好),则会导致:

  • POSIX(* nix)系统上的SIGSEGV
  • Windows上的GPF

这是因为strlen basicaly找到现有null-terminator 的索引并返回它!这是一个有效的,未经优化的strlen实现:

int strlen(char *string) {
    int i = 0;
    while(string[i] != '\0') {
        ++i;
    }
    return i;
}

所以...如果你真的担心字符串不是空终止,那么你会做类似的事情:

  • string[sizeof(string)]='\0';本地自动字符串上(编译器“知道”字符串的大小);
  • string[SIZE_OF_STRING]用于所有其他字符串,其中SIZE_OF_STRING是(最常见)#define'd常量,或者是您专门用于存储当前SIZE的变量(不是()长度)动态分配的字符串。

如果你真的,真的,真的非常担心字符串不会被空终止(就像你正在处理“脏”的libary方法(例如Tuxedo的ATMI)你“在将它们传递给可疑库方法之前清除“你的”返回字符串:

  • 之前:memset(string, NULL, SIZE_OF_STRING);
  • 调用:DirtyFunction(/*out*/string);
  • 之后:string[SIZE_OF_STRING]='\0'

SIG11是一个完整的生物片段,因为(除非你用signal-processor“挂钩”它们,否则,它们会导致unix难以终止你的程序,所以你不能记录任何东西(事后) )以帮助弄清楚那里发生了什么 - 来自...特别是考虑到在许多情况下抛出SIG11的代码行没有 - 靠近字符串松动的实际原因它是空终止符。

这对你有意义吗?

干杯队友。基思。

PS:警告:strncpy并非总是无效的......你可能意味着strlcpy。我很难理解这一点......当一笔6000万美元的账单崩溃时。


编辑:

仅供参考:这是一个“安全”(未经优化)的strlen版本,我称之为strnlen(我认为这应该在 stdlib 。叹息。)。

// retuns the length of the string (capped at size-1)
int strnlen(char *string, int size) {
    int i = 0;
    while( i<size && string[i]!='\0' ) {
        ++i;
    }
    return i;
}

答案 3 :(得分:2)

这是一个更简单的解决方案

scanf("%d",&loops);
while ((getchar()) != '\n'); //This is consume the '\n' char
//now you're free to use fgets
fgets(string,sizeof(string),stdin);

答案 4 :(得分:1)

我知道这很老了。我是c的新手,想要检查我的方法,该方法使用getchar

#include <stdio.h>

int main()
{

    printf("Please enter your name\n");
    char string[10];

    scanf("%s", string);
    printf("Hello %s\n", string);

    //getchar();  # un commenting this line, fgets perfectly works!!
    printf("Please enter your name again\n");

    fgets ( string, 10, stdin );     

    printf("Hello again %s", string);

    getchar();
}

答案 5 :(得分:1)

刚刚放好     scanf("%d\n",&loops);

而不是      scanf("%d",&loops);

答案 6 :(得分:0)

以下情况有效,如果fgets()被&#34;跳过&#34;使用scanf()

说完后:

scanf("%d", &loops);

说:

char garbage[100];

fgets(garbage,100,stdin);

这会将输入缓冲区中的任何内容存储到垃圾变量中。

这将有效地清除输入缓冲区,并允许您之后使用fgets()

编辑: 我最近了解到,有一个比上面更简单的解决方案。 如果你在scanf()之后说getchar(),它将允许你使用fgets()而不会出现问题。 getchar()将获得输入缓冲区中的下一个字符,在这种情况下将是&#39; \ n&#39;。删除&#39; \ n&#39;从输入缓冲区,fgets应该工作正常。

答案 7 :(得分:0)

在变量标签循环中扫描整数后,另一种忽略后续换行符(由于按ENTER)的方法是:

scanf ("%d%*c", &loops);

在哪里,根据手册页:

  

*禁止分配。随后的转换照常发生,但是没有使用指针。转换结果将被简单丢弃。

这不太可能,但是养成在scanf期间检查错误的习惯:

errno = 0
scanf ("%d%*c", &loops);
if (errno != 0) perror ("scanf");
// act accordingly to avoid un-necessary bug in the code

例如,在您的代码中,循环是一个局部的未初始化变量,包含垃圾。如果scanf无法填充所需的值,则while循环可能会任意运行。

答案 8 :(得分:0)

scanf()从该行的末尾\ n留在缓冲区fgets()中读取它的位置。为了解决这个问题,我们必须做点事情来消耗换行符。让我们看看问题所在。

问题

#include<stdio.h>
void main()
{
    char input[10];
    printf("Enter in fgets: ");
    scanf("%s", input);
    getchar();
    printf("Enter in scanf: ");
    fgets(input, 10, stdin);
}
输出:
Enter in scanf: Hello
Enter in fgets:

如您所见,它没有显示fgets部分。让我们看看解决方案。

getchar()放在scanf和fgets()之间

#include<stdio.h>
void main()
{
    char input[10];
    printf("Enter in fgets: ");
    scanf("%s", input);
    getchar();
    printf("Enter in scanf: ");
    fgets(input, 10, stdin);
}
输出:
Enter in scanf: Hello
Enter in fgets: Hello

如果可能,请在scanf()之后使用fgets()

#include<stdio.h>
void main()
{
    char input[10];
    printf("Enter in fgets: ");
    fgets(input, 10, stdin);
    getchar();
    printf("Enter in scanf: ");
    scanf("%s", input);
}
输出:
Enter in fgets: Hello
Enter in scanf: Hello

放入fget() 2次(此方法有时无效)

#include<stdio.h>
void main()
{
    char input[10];
    printf("Enter in fgets: ");
    scanf("%s", input);
    getchar();
    printf("Enter in scanf: ");
    fgets(input, 10, stdin);
    fgets(input, 10, stdin)
}
输出:
Enter in scanf: Hello
Enter in fgets: Hello

sscanf()插入scanf()

#include<stdio.h>
void main()
{
    char input[10];
    printf("Enter in fgets: ");
    sscanf(hello, "%s", input);
    getchar();
    printf("Enter in scanf: ");
    fgets(input, 10, stdin);
}
输出:
Enter in sscanf: Hello
Enter in fgets: Hello

答案 9 :(得分:-1)

我已解决您的问题,如下所示。现在你的程序运行正常。如果您有任何疑问,可以问我。

list