C - 扫描后 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)] = '';
        s2[strlen(s2)] = '';
        if (s1[0] == 'n' && s2[0] == 'n') {
            printf("YESn");
            continue;
        }
        delspace(s1);
        delspace(s2);
        for (i = 0; s1[i] != ''; i++)
            s1[i] = tolower(s1[i]);
        for (i = 0; s2[i] != ''; i++)
            s2[i] = tolower(s2[i]);
        if (strcmp(s1, s2) == 0) {
            printf("YESn");
        }
        else {
            printf("NOn");
        }
    }
    return 0;
}
void delspace(char* str) {
    int i = 0;
    int j = 0;
    char sTmp[strlen(str)];
    while (str[i++] != '') {
        if (str[i] != ' ') {
            sTmp[j++] = str[i];
        }
    }
    sTmp[j] = '';
    strcpy(str, sTmp);
}

输入"循环"后,"s1"自动分配了一个空行。它是如何发生的?我确定我的键盘工作正常。

scanf()准确地读取您要求它的内容,将fgets()读取该行末尾的以下n留在缓冲区中。 要么做一些事情来使用换行符,要么(我的首选解决方案)fgets()然后从该字符串sscanf()

scanf输入

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

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

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

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

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

如果行s1[strlen(s1)] = '';在执行之前已经正确终止 null s1则为无操作。

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

  • POSIX (*nix) 系统上的 SIGSEGV。
  • 视窗上的GPF。

这是因为strlen基本上可以找到现有 null 终止符的索引并返回它!下面是一个有效的、未优化的 strlen 实现:

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

所以。。。如果你真的担心字符串没有被null终止,那么你会做这样的事情:

  • 在本地自动字符串string[sizeof(string)]='';(编译器"知道"字符串的大小);
  • string[SIZE_OF_STRING]所有其他字符串,其中SIZE_OF_STRING(最常见的)是#define常量,或者您专门维护用于存储动态分配字符串的 current-SIZE(而不是长度)的变量。
如果你真的,真的

,真的担心字符串没有被null终止(就像你正在处理"脏"的库方法(例如Tuxedo的ATMI),你也可以"清除"你的"返回字符串",然后再将它们传递给可疑的库方法:

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

SIG11 是一个完整的 biatch 找到,因为(除非你用信号处理器"挂钩"它们并说其他话,否则它们会导致 Unix 硬终止你的程序,所以你不能记录任何东西(事后)来帮助弄清楚到底是从哪里来的......特别是考虑到在许多情况下,抛出 SIG11 的代码行与字符串丢失其空终止符的实际原因相去甚远。

这对你有意义吗?

PS:警告:strncpy并不总是空终止...你可能的意思是strlcpy。我以艰难的方式学到了这一点...当 6000 万美元的计费运行崩溃时。

<小时 />

编辑:

仅供参考:这是一个"安全"(未优化)的 strlen 版本,我称之为 strnlen(我认为这应该在 string.h 中。叹息。

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

只是把 scanf("%dn",&loops);

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

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

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

其中,根据手册页:

* 禁止分配。 接下来的转换照常发生,但不使用指针;转换的结果被简单地丢弃。

这是非常不可能的,但是在扫描期间检查错误的好习惯:

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

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

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:

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

getchar()放在扫描和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

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

#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

最新更新