【问题标题】:getc function not reading '\n'getc 函数未读取 '\n'
【发布时间】:2014-10-02 22:02:38
【问题描述】:

我希望该函数在到达新行时打印一个 0,但它不起作用,但从文件中获取每个单词都可以正常工作。快速响应将不胜感激。

输入文件中的数据如下所示:

blossom flower
bewilder confound confuse perplex
dwell live reside

代码:

int getWord(FILE * in, char str[]){
    int ch;
    int i = 0;
    while(!isalpha(ch = getc(in)) && ch != EOF);
        if(ch == EOF) return -1;
    str[i++] = tolower(ch);
    while(isalpha(ch = fgetc(in)) && ch != EOF){
            if(i < MAX_WORD)
                str[i++] = tolower(ch);
    }
    if(ch == '\n') return 0;
    str[i] = '\0';
    return 1;
}     

【问题讨论】:

  • 如果读取换行符,您的函数不会将\0 添加到字符串中。
  • 我知道我想在读取新行时做一些事情
  • 您需要将ch 定义为int,而不是charEOF 是不等于任何有效字符的负 int 值。
  • 因为 getc 的手册页说它返回一个 int linux.die.net/man/3/getc。如果一切都失败了,请阅读手册
  • @EOF:第一个循环的行尾有一个分号,所以条件缩进错误,实际上是循环后的语句。换句话说,代码的布局很糟糕。

标签: c function getc


【解决方案1】:

直接回答评论中的问题

我的问题仍未得到解答——我只是想知道是什么导致它无法return 0

因为:

  1. 您在 Windows 上运行,
  2. 文件作为二进制文件打开,并且
  3. 在行尾终止单词的字符是 CR 而不是 LF。

当您下次调用该函数时,它会在第一个循环中读取 LF 并忽略它,因为它不是字母。

主要答案

简而言之,您的代码确实可以识别换行符 — 至少在 Linux 上是这样。

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

enum { MAX_WORD = 50 };

static
int getWord(FILE *in, char str[])
{
    int ch;
    int i = 0;
    while (!isalpha(ch = getc(in)) && ch != EOF)
        ;
    if (ch == EOF)
        return -1;
    str[i++] = tolower(ch);
    while (isalpha(ch = fgetc(in)) && ch != EOF)
    {
        if (i < MAX_WORD)
            str[i++] = tolower(ch);
    }
    if (ch == '\n')
        return 0;
    str[i] = '\0';  // Bug; should be before the if
    return 1;
}

int main(void)
{
    char buffer[MAX_WORD];
    int rc;

    while ((rc = getWord(stdin, buffer)) >= 0)
        printf("Got: %d (%s)\n", rc, buffer);
    return 0;
}

给定输入文件:

blossom flower
bewilder confound confuse perplex
dwell live reside

程序产生输出:

Got: 1 (blossom)
Got: 0 (flowerm)
Got: 1 (bewilder)
Got: 1 (confound)
Got: 1 (confuse)
Got: 0 (perplex)
Got: 1 (dwell)
Got: 1 (live)
Got: 0 (residex)

请注意,当您读取换行符(返回 0 时)并且当前单词比前一个单词短时,您会在单词中留下杂散的字符。如果行中的最后一个单词比之前的任何单词都长并且堆栈足够混乱,那么您可能会出现不良行为。您可以通过在 if 条件之前移动空终止来修复该错误。那么输出是:

Got: 1 (blossom)
Got: 0 (flower)
Got: 1 (bewilder)
Got: 1 (confound)
Got: 1 (confuse)
Got: 0 (perplex)
Got: 1 (dwell)
Got: 1 (live)
Got: 0 (reside)

请注意,在 Windows 上,如果程序读取 '\r'(CRLF 行结尾的 CR 部分),则将跳过零返回,因为终止单词的字符是 '\r',并且在下一次调用该函数,第一个循环跳过'\n'

请注意,指示平台(Unix vs Windows)将有助于澄清问题并更快地获得答案。

请注意,当我创建一个 DOS (Windows) 格式文件 data.dos 并使用相同(已修复错误)二进制文件(在 Ubuntu 14.04 衍生版本上运行)读取该文件时,输出为:

Got: 1 (blossom)
Got: 1 (flower)
Got: 1 (bewilder)
Got: 1 (confound)
Got: 1 (confuse)
Got: 1 (perplex)
Got: 1 (dwell)
Got: 1 (live)
Got: 1 (reside)

这完全对应于“CR 终止单词并且第一个循环跳过换行符”的场景。您还可以通过在关键位置添加打印语句来进行调试:

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

enum { MAX_WORD = 50 };

static
int getWord(FILE *in, char str[])
{
    int ch;
    int i = 0;
    while (!isalpha(ch = getc(in)) && ch != EOF)
    {
        if (ch == '\n') printf("Got-1 '\\n'\n");
        else if (ch == '\r') printf("Got-1 '\\r'\n");
        else printf("Got-1 '%c'\n", ch);
    }
    if (ch == EOF)
        return -1;
    str[i++] = tolower(ch);
    while (isalpha(ch = fgetc(in)) && ch != EOF)
    {
        if (i < MAX_WORD)
            str[i++] = tolower(ch);
    }
    if (ch == '\n') printf("Got-2 '\\n'\n");
    else if (ch == '\r') printf("Got-2 '\\r'\n");
    else printf("Got-2 '%c'\n", ch);
    str[i] = '\0';
    if (ch == '\n')
        return 0;
    return 1;
}

int main(void)
{
    char buffer[MAX_WORD];
    int rc;

    while ((rc = getWord(stdin, buffer)) >= 0)
        printf("Got: %d (%s)\n", rc, buffer);
    return 0;
}

在 Unix 文件上,现在的输出是:

Got-2 ' '
Got: 1 (blossom)
Got-2 '\n'
Got: 0 (flower)
Got-2 ' '
Got: 1 (bewilder)
Got-2 ' '
Got: 1 (confound)
Got-2 ' '
Got: 1 (confuse)
Got-2 '\n'
Got: 0 (perplex)
Got-2 ' '
Got: 1 (dwell)
Got-2 ' '
Got: 1 (live)
Got-2 '\n'
Got: 0 (reside)

还有 Windows 文件:

Got-2 ' '
Got: 1 (blossom)
Got-2 '\r'
Got: 1 (flower)
Got-1 '\n'
Got-2 ' '
Got: 1 (bewilder)
Got-2 ' '
Got: 1 (confound)
Got-2 ' '
Got: 1 (confuse)
Got-2 '\r'
Got: 1 (perplex)
Got-1 '\n'
Got-2 ' '
Got: 1 (dwell)
Got-2 ' '
Got: 1 (live)
Got-2 '\r'
Got: 1 (reside)
Got-1 '\n'

请注意,Unix/Linux 不会特别对待 CRLF 组合;它们只是输入流中的两个相邻字符。

【讨论】:

  • 我用的是windows所以换行符是'\r''\n'?所以因为函数调用跳过了它不起作用的字符?
  • @hinkatana:是的,不,也许。在 Windows 上,两个连续的字符,'\r''\n' - 也称为 CRLF 或回车换行 - 当文件被检查为二进制文件时标记行尾。通常,如果文件作为文本文件打开,运行时库会将 CRLF 映射为单个 '\n' 字符。但是,如果文件以二进制文件的形式打开(例如fopen("file.txt", "rb")),那么程序将可以使用 CR 并显示我所描述的行为。因此,这一切都取决于文件的打开方式。标准输入通常作为文本文件打开。
  • hmmm 好的,所以它假设是'\n',因为我将它作为常规文本文件打开。但我仍然有点困惑为什么它不从您的解决方案和 cmets 打印return 0。我所能收集到的只是'\n' 在函数调用之间丢失或覆盖的某些实例?
  • 没有任何效果或帮助,所以我只想尝试其他方法,但无论如何谢谢。
  • 您是否尝试了上述诊断程序的副本?您可以使代码在读取时打印每个字符。您没有将文件保存为 RTF 或任何有趣的东西,是吗?我认为这不太可能,但在这一点上,一切都需要检查。由于您没有显示您的调用代码以及文件的打开方式,我们无法提供更多帮助。
猜你喜欢
  • 2012-04-20
  • 1970-01-01
  • 2014-01-12
  • 1970-01-01
  • 2022-01-19
  • 1970-01-01
  • 1970-01-01
  • 2017-03-04
相关资源
最近更新 更多