scanf之后fgets不起作用

问题描述 投票:11回答:7
#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”会自动分配为空白行。它是怎么发生的?我确定我的键盘工作正常。

c scanf fgets
7个回答
18
投票

scanf()精确地读取您要求的内容,而从该行末尾的下一个\n保留在缓冲区中,其中fgets()将读取它。要么做一些消耗换行符的操作,要么(我偏爱的解决方案)使用fgets(),然后使用该字符串中的sscanf()


5
投票

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

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

2
投票

Vayn,

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

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

但是如果s1在该行执行之前(不是很幸运)之前还没有正确终止为null,它将导致:

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

这是因为strlen基本上会找到existing null-terminator的索引并返回它!这是strlen的有效,未经优化的实现:

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

所以...如果您真的担心字符串不以空值结尾,那么您可以执行以下操作:

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

并且,如果您真的,真的,真的担心字符串不以null结尾(例如您正在处理“脏”的库方法(例如Tuxedo的ATMI),则您ALSO“清除”您的“返回字符串”,然后使用以下方法将它们传递给可疑库方法:

  • 之前:memset(string, NULL, SIZE_OF_STRING);
  • 调用:DirtyFunction(/*out*/string);
  • 之后:string[SIZE_OF_STRING]='\0'
  • SIG11是一个完整的修补程序,因为(除非您用signal-processor“钩住”它们,否则说,它们会导致unix硬终止您的程序,因此您无法记录任何信息(事后)来提供帮助)弄清楚到底是哪里来的...尤其要考虑到,在许多情况下,引发SIG11的代码行无处不在,字符串丢失的实际原因几乎是空的,终止符。

这对您有意义吗?

欢呼队友。基思。

PS:警告:strncpy不会始终终止...您可能是说strlcpy。我很难学到这个……当一个六千万美元的账单崩溃时。


编辑:

FYI:这是strlen的一个“安全”(未优化)版本,我将其称为strnlen(我认为应该在stdlib

中。S。)。
// 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;
}

1
投票

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


1
投票

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


0
投票

[在使用fgets()后正在“跳过” scanf()的情况下有效


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.