Do not use feof()
as your loop condition; it will not return true until after you've tried to read past the end of the file, meaning your loop will execute one time too many. Check the result of your input call (whether you use fgets()
or fscanf()
) to see if it succeeded, then check feof()
if you got an error condition.
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()
reads entire strings, not individual characters, so you don't want to pass the address of each individual character in your string. Call it like so instead:
if (fgets(list[i], sizeof list[i], stream) != NULL)
{
// process input address
}
And now, for Bode's usual spiel about arrays and pointers...
When an array expression appears in most contexts, the type of the expression is implicitly converted from "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element of the array. The exceptions to this rule are when the array expression is the operand of the sizeof
or &
operators, or it is a string literal that is being used as an initializer in a declaration. When you hear people say "arrays and pointers are the same thing", they're garbling that rule. Arrays and pointers are completely different animals, but they can be used interchangeably in some contexts.
Note that in the code above I passed list[i]
as the first argument to fgets() without any decoration (such as the &
operator). Even though the type of list[i]
is "12-element array of char", in this context it is implicitly converted to type "pointer to char", and the value will be the address of list[i][0]
. Note that I also passed that same expression to the sizeof
operator. In that case, the type of the array expression is not converted to a pointer type, and the sizeof operator returns the number of bytes in the array type (12).
Just to nail it down:
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
What all this means is that fgets()
will read up to the next 12 characters (provided it doesn't hit a newline or EOF first) and store it starting at list[i][0]
. Note that fgets()
will write a terminating nul character (0) to the end of your string. Note also that if fgets()
encounters a newline and there's room in the target array for it and the terminating nul, fgets()
will store the terminating newline before the nul character. So if your input file has a line like
1.1.1.1\n
then the contents of your input buffer after the read will be "1.1.1.1\n\0xxx"
where x
is some random value. If you don't want the newline there, you can use the strchr()
function to find it and then overwrite it with a 0:
char *newline;
...
if ((newline = strchr(input[i], '\n')) != NULL)
{
*newline = 0;
}
Since fgets()
stops at the next newline, and since your input buffer is sized for 12 characters, it's possible for you to run into a situation where you have a newline as the next input character in the file; in that case, fgets()
will write only that newline to the input buffer, so you'll have some empty entries, which is probably not what you want. You might want to add an extra byte to your input buffer in order to avoid that situation.
Putting it all together:
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;
}
}