Необходимо сделать пару замечаний (1) никогда не экономить на размере буфера .20
ужасно недостаточно для большого процента используемых имен.64
может быть разумного размера, и затем вы берете этот разумный размер и double it.
Далее, (2) неясно, что name
делает в вашем коде, нотак как он используется в ограничении цикла for
, это число имен, которыми вы хотите ограничить чтение.Вы должны контролировать свой цикл чтения, чтобы он завершался, когда 1 - ваш индекс чтения не меньше, чем ваш name
limit &&
fgets () возвращает действительный указатель, например
#include <stdio.h>
#include <string.h>
#define MAXNM 128 /* if you need a constant, #define one (or more) */
#define NUMNM 10 /* ( Don't skimp on buffer size! ) */
int main (int argc, char **argv) {
char buffer[MAXNM];
size_t ndx = 0, name = NUMNM;
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
...
while (ndx < name && fgets (buffer, MAXNM, fp)) {
buffer[strcspn (buffer, "\n")] = 0; /* overwrite \n with nul-char */
fprintf (stdout, "name[%2zu] : %s\n", ndx++ + 1, buffer);
}
Выше простого *Переменная 1016 * (index) используется вместе с возвратом из fgets
для управления циклом чтения.Это устраняет вашу проблему с наличием в файле меньшего количества строк, чем names
, но затем вслепую подталкивает чтение из потока в состоянии ошибки до тех пор, пока не будут выполнены итерации name
.Используя ndx < NUMNM && fgets (buf, MAXC, fp)
в качестве элемента управления циклом, вы корректно завершаете работу, когда любое из условий перестает быть истинным, избегая Неопределенное поведение .
(3), если вы намереваетесь сохранить имя из каждого buffer
, затем вам нужно выделить хранилище для каждого имени и скопировать buffer
в новое хранилище до следующей итерации, или предыдущее имя будет потеряно при повторном заполнении buffer
.
(4) fgets
читает до и включает конечный '\n'
в конце заполненного буфера.Вы не хотите хранить свои имена с '\n'
s, свисающими с конца.strcspn
- это один из самых простых и надежных способов определения количества символов в buffer
перед '\n'
и последующей перезаписи '\n'
с помощью nul-символа .Вам не нужно ничего больше, чем показано выше, например,
buffer[strcspn (buffer, "\n")] = 0; /* overwrite \n with nul-char */
Обратитесь к strspn (3) - страница руководства Linux и посмотрите, сможете ли вы выяснить, как именно это работает.
(5) Всегда проверять возвращение при каждом открытии файла (и закрытии после записи в поток), а всегда проверять возврат каждые функция пользовательского ввода.В вашем коде нет более важного шага, чем проверка данных, которые вы получаете из файла или пользователя До вы пытаетесь обработать эти данные.В противном случае вы просто приглашаете Неопределенное поведение с небольшим нажатием клавиши или одним ошибочным написанием.
Помещение всего этого в программу, которая принимает имя файла для открытия в качестве первого аргументав программу (или читает из stdin
по умолчанию, если не указан аргумент), вы можете сделать что-то вроде:
#include <stdio.h>
#include <string.h>
#define MAXNM 128 /* if you need a constant, #define one (or more) */
#define NUMNM 10 /* ( Don't skimp on buffer size! ) */
int main (int argc, char **argv) {
char buffer[MAXNM];
size_t ndx = 0, name = NUMNM;
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
while (ndx < name && fgets (buffer, MAXNM, fp)) {
buffer[strcspn (buffer, "\n")] = 0; /* overwrite \n with nul-char */
fprintf (stdout, "name[%2zu] : %s\n", ndx++ + 1, buffer);
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
}
Пример входного файла
Сейчасупражняйте вашу подпрограмму ввода с файлом, содержащим 11 имен, более чем NUMNM позволяет читать, например,
$ cat dat/namesonly.txt
Zeda'Taxu
Khano'Balme
Goni
Ryan,Elizabeth
McIntyre,Osborne
DuMond,Kristin
Larson,Lois
Thorpe,Trinity
Ruiz,Pedro
Ali,Mohammed
Vashti,Indura
Пример использования / Вывод
Чтение и остановкаNUMNM имена
$ ./bin/fgetsnames <dat/namesonly.txt
name[ 1] : Zeda'Taxu
name[ 2] : Khano'Balme
name[ 3] : Goni
name[ 4] : Ryan,Elizabeth
name[ 5] : McIntyre,Osborne
name[ 6] : DuMond,Kristin
name[ 7] : Larson,Lois
name[ 8] : Thorpe,Trinity
name[ 9] : Ruiz,Pedro
name[10] : Ali,Mohammed
Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.