Функция 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
,
Так как:
- вы работаете в Windows,
- файл открывается как двоичный файл, и
- символ, заканчивающий слова в конце строки, - это 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 специально; это просто два соседних символа во входном потоке.