Не используйте feof()
в качестве условия цикла; он не вернет true, пока вы не попытаетесь прочитать за концом файла, то есть ваш цикл будет выполняться слишком много раз. Проверьте результат вашего входного вызова (независимо от того, используете ли вы fgets()
или fscanf()
), чтобы убедиться, что он успешен, , а затем проверьте feof()
, если у вас возникла ошибка.
if (fgets(buffer, sizeof buffer, stream) != NULL)
{
// process the input buffer
}
else if (feof(stream)
{
// handle end of file
}
else
{
// handle read error other than EOF
}
fgets()
читает целые строки, а не отдельные символы, поэтому вы не хотите передавать адрес каждого отдельного символа в вашей строке. Назовите это так вместо этого:
if (fgets(list[i], sizeof list[i], stream) != NULL)
{
// process input address
}
А теперь, для обычной болтовни Боде о массивах и указателях ...
Когда выражение массива появляется в большинстве контекстов, тип выражения неявно преобразуется из «массива N-элемента T» в «указатель на T», а значением выражения является адрес первого элемента массив. Исключениями из этого правила являются случаи, когда выражение массива является операндом операторов sizeof
или &
или это строковый литерал, который используется в качестве инициализатора в объявлении. Когда вы слышите, как люди говорят «массивы и указатели - это одно и то же», они используют это правило. Массивы и указатели - совершенно разные животные, но в некоторых контекстах они могут использоваться взаимозаменяемо.
Обратите внимание, что в приведенном выше коде я передал list[i]
в качестве первого аргумента функции fgets () без каких-либо украшений (например, оператора &
). Хотя тип list[i]
является «массивом из 12 элементов char», в этом контексте он неявно преобразуется в тип «pointer to char», а значением будет адрес list[i][0]
. Обратите внимание, что я также передал это же выражение оператору sizeof
. В этом случае тип выражения массива - , а не , преобразованный в тип указателя, и оператор sizeof возвращает количество байтов в типе массива (12).
Просто прибить это:
Expression Type Implicitly converted to
---------- ---- ----
list char [100][12] char (*)[12] (pointer to 12-element array of char)
list[i] char [12] char *
list[i][j] char N/A
Все это означает, что fgets()
будет считывать до следующих 12 символов (при условии, что он не попадет на новую строку или EOF в первую очередь) и будет сохранять его, начиная с list[i][0]
. Обратите внимание, что fgets()
запишет завершающий нулевой символ (0) в конец вашей строки. Также обратите внимание, что если fgets()
встречает символ новой строки и , в целевом массиве есть место для него и завершающего nul, fgets()
будет хранить завершающий символ новой строки перед нулевым символом. Так что, если ваш входной файл имеет строку типа
1.1.1.1\n
тогда содержимое вашего входного буфера после чтения будет "1.1.1.1\n\0xxx"
, где x
- какое-то случайное значение. Если вы не хотите, чтобы новая строка находилась там, вы можете использовать функцию strchr()
, чтобы найти ее, а затем заменить ее на 0:
char *newline;
...
if ((newline = strchr(input[i], '\n')) != NULL)
{
*newline = 0;
}
Поскольку fgets()
останавливается на следующей новой строке, и поскольку ваш входной буфер имеет размер 12 символов, вы можете столкнуться с ситуацией, когда у вас есть новая строка в качестве следующего входного символа в файле; в этом случае fgets()
будет записывать только эту новую строку во входной буфер, поэтому у вас будет несколько пустых записей, что, вероятно, не то, что вам нужно. Возможно, вы захотите добавить дополнительный байт во входной буфер, чтобы избежать этой ситуации.
Собираем все вместе:
char list[100][13];
...
for (i = 0; i < 100; ++)
{
if (fgets(list[i], sizeof list[i], stream) != NULL)
{
char *newline = strchr(list[i], '\n');
if (newline != NULL)
*newline = 0;
printf("Read address \"%s\"\n", list[i]);
count++;
}
else if (feof(stream))
{
printf("Reached end of file\n");
break;
}
else
{
printf("Read error on input; aborting read loop\n");
break;
}
}