1

编辑
问题的解决方案是了解 Ctrl-D 实际在做什么。
在新的空行上,单个 Ctrl-D 将发出 EOF 信号。
但如果该行中已有字符,则第一个 Ctrl-D 会使该行的内容回显到屏幕(但不写入STDOUT)。如果字符已经在缓冲区中,则必须向 发出第二个 Ctrl-D 信号EOF,从而将缓冲区写入STDOUT
这可以通过将输出重定向到文件来证明。
编辑

我正在使用 fgetc() 从stdin. 我循环直到收到 EOF。在循环中,我根据在按下 Ctrl-D 之前键入的字符构建一个字符串。但我无法找出退出循环的方法,因为从中读取的缓冲区 ch = fgetc() 不包含 EOF。(EOF 只触发 fgetc() 返回它的第一个值。)

ungetc() 不允许将 EOF 推入缓冲区,推入任何其他字符都有与真实数据混淆的风险,我被卡住了!我已经阅读了很多答案,但它们没有解决这个问题或不适用于我试图实现的用例。

我希望能够在标准输入缓冲区上计数、窥视等。

我真的不想读一整行(或一次 X 个字符),因为我正在处理从 fgetc()到达(编辑)的每个字符。

关于如何克服这一困境的任何建议?(不使用 NCurses)

我正在使用 Ubuntu。EOF = Ctrl-D 这是我正在使用的一些代码:

这有效,并且与乔纳森的简单示例相同,但不是我想要的:

int main(int argc, char **argv) {

    int inputChr;

    do {
        inputChr = fgetc(stdin);
        if (inputChr != EOF) {
            fputc( inputChr, stdout);
        }
        if (feof(stdin)) {
            if (ferror(stdin)) {
                perror(NULL);
                return errno;
            }
        }
    } while (inputChr != EOF);
    return EXIT_SUCCESS;
}

但是,这被卡住了,但正在尝试做我想做的事情(编辑),但需要 Ctrl-D 第二次:

char *buildLine (FILE *inputSource, char *currLine, int showTabs, int showNonPrint, int *haveLF) {

    int inputChr;
    char *thisLine = malloc(1);
    int inputSize;

    *haveLF = FALSE;
    while ( (inputChr = fgetc(inputSource)) != EOF ) {

        if (ferror(inputSource)) {
            perror(NULL);
        } else {
            if (inputChr == LF) {
                *haveLF = TRUE;
            } else {
                thisLine = strconcat(thisLine,(char *)&inputChr);
            }
        }
    }

    return thisLine;
}

还有一些被问到的代码:

char * strconcat ( char *str1, char * str2) {

    char *newStr = malloc(strlen(str1)+strlen(str2)+1);
    if (newStr == NULL) {
        return NULL;
    }
    strcpy(newStr,str1);
    strcat(newStr,str2);

    return newStr;
}

下面的这个版本会逐个字符地处理输入的字符,并且工作起来就像cat. 但我决定先将每个字符处理成一行,然后再应用一些我需要实现的额外转换。这简化了状态机设计,但尝试构建线条可能不是一个好的选择(不使用 NCurses)。:(

int echoInput( FILE *inputSource, FILE *outputDestination, int numbers, int showEnds) {

    int haveNewLine = TRUE;
    int lineNo = 1;
    int inputChr;

    do {
        inputChr = fgetc(inputSource);
        if (inputChr != EOF) {
            if (numbers && haveNewLine) {
                long lineNoSize = (long) log10(lineNo)+1;   // effectively floor(log10(lineNo)+1) = number digits
                char *lineNoStr =  (lineNoSize<6)?malloc(8):malloc(lineNoSize+2);   // If less than 6 digits, allow for minimum 6 plus tab.  Also +1 for terminator.
                if (lineNoStr == NULL) {
                    printf ("Error::Out of Memory");
                    return ENOMEM;
                }
            sprintf(lineNoStr,"%6d\t",lineNo);  // format lineNo string
                fputs(lineNoStr, outputDestination);    // send string to output
                lineNo++;
                haveNewLine = FALSE;
            }
            if (inputChr == LF) {
                if (showEnds) {
                    fputc('$', outputDestination);  // send char to output
                }
                haveNewLine = TRUE;
            }
            fputc( inputChr, outputDestination);
        }
        if (feof(inputSource)) {
            if (ferror(inputSource)) {
                perror(NULL);
                return errno;
            }
        }
        if (ferror(outputDestination)) {
            perror(NULL);
            return errno;
        }
    } while (inputChr != EOF);
    return EXIT_SUCCESS;
}
4

2 回答 2

3

这个问题必须有其他变体,答案足够好,但这里还有一个。

fgetc()(and getc()and )返回的值getchar()是 anint而不是 a char。它必须是 a,int因为可以返回的值集包括 a 的每个可能值char和一个额外的值 EOF,它是负数(而字符都是正数)。尽管 EOF 是最常见-1的,但您永远不应该按照这种假设进行编码。

有两件事可能会出错:

char c;

while ((c = fgetc(stdin)) != EOF)

如果类型char是有符号的,那么在到达 EOF 之前,某些字符(通常是 0xFF、通常是 ÿ、y-变音符号、Unicode U+00FF、LATIN SMALL LETTER Y WITH DIAERESIS)将被误解为指示 EOF。

如果类型char是无符号的,那么您将永远不会检测到 EOF,因为分配给的值c将是 0xFF(正),并且永远不会等于 EOF(负值)。

你是正确的,你不能将 EOF 推回到输入流上ungetc()

请注意Control-D(或Control-Z在 Windows 上)不会将字符添加到输入队列。相反,它表示没有更多可用的字符(稍微简化一些事情),这意味着read()系统调用返回读取的 0 字节,这意味着 EOF。

getchar()使用and将标准输入复制到标准输出的简单程序putchar()是:

int c;
while ((c = getchar()) != EOF)
    putchar(c);

如果您希望打开文件并阅读它们,您可以调整它以使用fgetc()orgetc()fputc()或。putc()关键是使用 anint来保存读取的值。

于 2014-03-24T05:33:40.413 回答
0

EOF通常是一个整数(不是 a char),并且它的值与任何有效字符都不相同。

正常的 C 风格是用\0. 当然,理论上可以读取一个NUL字符,如果您想处理这些可能性,您需要记录读取的字符数以及读取它们的缓冲区。

于 2014-03-24T05:31:19.010 回答