Функция getc не читает '\n'

Я хочу, чтобы функция выводила 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;
}     

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' (часть CR конца строки CRLF), тогда нулевой возврат будет пропущен, потому что символ, заканчивающий слово, был '\r'и при следующем вызове функции первый цикл пропускает '\n',

Обратите внимание, что указание платформы (Unix против 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 специально; это просто два соседних символа во входном потоке.

Другие вопросы по тегам