Я написал эту функцию для чтения строки из файла:
const char *readLine(FILE *file) {
if (file == NULL) {
printf("Error: file pointer is null.");
exit(1);
}
int maximumLineLength = 128;
char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);
if (lineBuffer == NULL) {
printf("Error allocating memory for line buffer.");
exit(1);
}
char ch = getc(file);
int count = 0;
while ((ch != '\n') && (ch != EOF)) {
if (count == maximumLineLength) {
maximumLineLength += 128;
lineBuffer = realloc(lineBuffer, maximumLineLength);
if (lineBuffer == NULL) {
printf("Error reallocating space for line buffer.");
exit(1);
}
}
lineBuffer[count] = ch;
count++;
ch = getc(file);
}
lineBuffer[count] = '\0';
char line[count + 1];
strncpy(line, lineBuffer, (count + 1));
free(lineBuffer);
const char *constLine = line;
return constLine;
}
Функция правильно читает файл, и с помощью printf я вижу, что строка constLine также правильно прочитана.
Однако, если я использую функцию, например, так:
while (!feof(myFile)) {
const char *line = readLine(myFile);
printf("%s\n", line);
}
printf выводит бред. Зачем?
fgets
вместоfgetc
. Вы читаете символ за символом вместо строки за строкой.getline()
это часть POSIX 2008. Могут существовать POSIX-подобные платформы без него, особенно если они не поддерживают остальную часть POSIX 2008, но в мире систем POSIX вgetline()
наши дни довольно переносимы.Ответы:
Если ваша задача состоит не в том, чтобы изобрести функцию построчного чтения, а просто в построчном чтении файла, вы можете использовать типичный фрагмент кода, включающий эту
getline()
функцию (см. Страницу руководства здесь ):источник
getline
относится к GNU libc, то есть к Linux. Однако, если цель состоит в том, чтобы иметь функцию чтения строк (в отличие от изучения C), в Интернете доступно несколько функций чтения строк из общественного достояния.if(line)
Проверка является излишней. Вызовfree(NULL)
по сути не является опцией.источник
(FILE*) fp
? Разве это неfp
уже,FILE *
а такжеfopen()
возвращаетFILE *
?getline
является хорошей альтернативой. Я согласен, чтоFILE *
актеры не нужны.fp
чтобыfilePointer
для большей ясности.В вашей
readLine
функции вы возвращаете указатель наline
массив (строго говоря, указатель на его первый символ, но здесь разница не имеет значения). Поскольку это автоматическая переменная (т. Е. Она «в стеке»), память возвращается после возврата функции. Вы видите бред, потомуprintf
что положил свои вещи в стек.Вам необходимо вернуть динамически выделенный буфер из функции. У вас уже есть один, это
lineBuffer
; все, что вам нужно сделать, это обрезать его до желаемой длины.ДОБАВЛЕНО (ответ на дополнительный вопрос в комментарии):
readLine
возвращает указатель на символы, составляющие строку. Этот указатель - то, что вам нужно для работы с содержимым строки. Это также то, что вы должны передать,free
когда закончили использовать память, занятую этими персонажами. Вот как вы можете использовать этуreadLine
функцию:источник
источник
fopen_s
делает код непереносимым.printf
будет искать спецификаторы формата, а не печатать знаки процента и следующие символы, как они есть . Нулевые байты заставят все символы в остальной части строки исчезнуть. (Не говорите мне, что нулевые байты не могут произойти!)readLine()
возвращает указатель на локальную переменную, которая вызывает неопределенное поведение.Обойти можно:
readLine()
line
использованияmalloc()
- в этом случаеline
будет постояннымисточник
Используйте
fgets()
для чтения строки из дескриптора файла.источник
Некоторые вещи не так с примером:
fprintf(stderr, ....
fgetc()
а неgetc()
.getc()
это макрос,fgetc()
это правильная функцияgetc()
возвращаетint
такch
должен быть объявлен какint
. Это важно, так как сравнение сEOF
будет обработано правильно. Некоторые 8-битные наборы символов используют0xFF
в качестве допустимого символа (например, ISO-LATIN-1), и его значениеEOF
равно -1,0xFF
если он присваивается achar
.Существует потенциальное переполнение буфера в строке
Если длина строки ровно 128 символов,
count
это 128 в точке, которая будет выполнена.Как уже отмечали другие,
line
это локально объявленный массив. Вы не можете вернуть указатель на него.strncpy(count + 1)
скопирует в большинствеcount + 1
символов , но будет прекращено , если он попадает'\0'
Потому что вы установили ,lineBuffer[count]
чтобы'\0'
вы знаете , что никогда не получитеcount + 1
. Однако, если бы он это сделал, он не стал бы завершать'\0'
, поэтому вам нужно это сделать. Вы часто видите что-то вроде следующего:если вы
malloc()
хотите вернуть строку (вместо вашего локальногоchar
массива), ваш тип возврата должен бытьchar*
- отброситьconst
.источник
что насчет этого?
источник
Вот мои несколько часов ... Чтение всего файла построчно.
источник
fgetc
вместоfgets
?обратите внимание, что переменная 'line' объявляется в вызывающей функции и затем передается, поэтому ваша
readLine
функция заполняет предварительно определенный буфер и просто возвращает его. Именно так работает большинство библиотек Си.Есть и другие способы, о которых я знаю:
char line[]
как статический (static char line[MAX_LINE_LENGTH]
-> он будет хранить свое значение ПОСЛЕ возвращения из функции). -> плохо, функция не реентерабельна, и может возникнуть условие гонки -> если вы вызовете ее дважды из двух потоков, она перезапишет свои результатыmalloc()
ИНГ полукокса линии [], и освобождая его в вызове функций -> слишком много дорогихmalloc
с, и, делегируя ответственность освободить буфер другой функции (наиболее элегантное решение заключается в вызовеmalloc
иfree
на любых буферов в той же функции)Кстати, «явное» приведение от
char*
кconst char*
излишне.Кстати, lineBuffer не нужен
malloc()
, просто определите егоchar lineBuffer[128]
, так что вам не нужно его освобождатьКстати, не используйте «динамические стековые массивы» (определяя массив как
char arrayName[some_nonconstant_variable]
), если вы точно не знаете, что делаете, это работает только в C99.источник
Вы должны использовать функции ANSI для чтения строки, например. fgets. После вызова вам нужно free () в контексте вызова, например:
источник
Реализуйте метод для чтения и получения содержимого из файла (input1.txt)
Надеюсь, это поможет. Удачного кодирования!
источник
Вы делаете ошибку, возвращая указатель на автоматическую переменную. Строка переменной размещается в стеке и живет только до тех пор, пока функционирует функция. Вам не разрешено возвращать указатель на него, потому что как только он вернется, память будет отдана в другом месте.
Чтобы избежать этого, вы либо возвращаете указатель на память, которая находится в куче, например. lineBuffer, и пользователь должен сам вызывать функцию free (), когда с ним покончено. В качестве альтернативы вы можете попросить пользователя передать вам в качестве аргумента адрес памяти, на который нужно записать содержимое строки.
источник
Я хочу код с нуля, поэтому я сделал это, чтобы прочитать содержание словарного слова построчно.
char temp_str [20]; // вы можете изменить размер буфера в соответствии с вашими требованиями и длиной одной строки в файле.
Примечание. Я инициализирую буфер символом Null каждый раз, когда читаю строку. Эта функция может быть автоматизирована, но поскольку мне нужно подтверждение концепции и я хочу разработать программу Byte By Byte
источник
int main() {
code
char temp_str [20] = {'\ 0'};code
c автоматически заполнит каждый слот нулевым терминатором, так как декларации массива работают так: если массив инициализируется с меньшим количеством элементов, чем массив, последний элемент будет заполнять оставшиеся элементы.char temp_str[20] = {0}
также считаю , что весь массив символов заполняется нулевыми терминаторами.Мой инструмент с нуля:
источник
fgets
которое можно использовать.Предоставить переносимую и универсальную
getdelim
функцию, тест пройден через msvc, clang, gcc.источник
fgets
существует?getdelim
позволяет настраивать разделители. Кроме того, я заметил, что нет ограничения на длину строки - в этом случае вы можете использовать стек сgetline
. (Оба описаны здесь: man7.org/linux/man-pages/man3/getline.3.html )getdelim
иgetline
было стандартизировано в POSIX.1-2008, кто-то еще упоминает на этой странице).fgets
также стандартный c, а не специфичный для linux