Russell Shaw said:
Sometimes you don't know how much data you're going to read, so you
just have to plonk stuff on the stack regardless:
char* getfile(FILE *infile)
{
size_t i = 0;
char myarray[0];
while(!feof(infile)) {
myarray[i++] = fgetc(infile);
}
alloca(i);
char *buf = malloc(i);
memcpy(buf, myarray, i);
return buf;
}
It is worse than that: it does not even work, crashing right after
reading sufficiently long lines (even when using gcc on Linux on
an i386).
Indeed.
How about:
char* getfile(FILE *infile)
{
size_t i = 0;
while(!feof(infile)) {
char *ptr = alloca(sizeof(char));
*ptr = fgetc(infile);
if(*ptr == EOF) {
return NULL;
}
}
char *buf = malloc(i);
memcpy(buf, ptr, i);
return buf;
}
This one has the advantage of "almost working" on some machines.
It still behaves very oddly on a SPARC. (Try it! It breaks even
on a SPARC running Linux, using gcc.)
The reason is that alloca() on the SPARC rounds the size up to
the nearest multiple of 8, as required by the architecture. Each
alloca(1) -- sizeof(char) is necessarily 1 -- allocates 8 bytes.
The text winds up strangely spaced.
It also fails when run on a few other, in another peculiar way: it
adds a mysterious '\377' character to the file. The reason is that
fgetc(infile) returns EOF, which is stored in *ptr, which has
type (plain) char, which is unsigned char. The test *ptr==EOF
compares 255 against -1; they are not equal and we make one more
trip through the loop. This time, feof(infile) is true -- because
the last fgetc() failed due to EOF -- and we believe that the
file ended with a '\377' byte.
It also fails mysteriously (on those machines) when run with input
redirected to a file that is on a floppy with a bad sector. This
time, it loops forever. The reason is that, as before, fgetc()
returns EOF, which is stored in the plain (and thus unsigned)
"char", and then we compare 255 vs -1, so we continue to loop.
This time, however, feof(infile) is false, because the failure was
due to an I/O error rather than EOF.
There are a number of "morals of the story", as it were. The main
two are:
Never use feof(). (For the advanced C programmer: "Well, hardly
ever.")
Do not depend on undocumented "features" like alloca() returning
contiguous bytes, because these are not always true.
Of course, there is a way to do this without using alloca() at all,
so that the code will work on any system supporting C89 or C99; but
if the goal is "to use alloca()", using only the standard C89/C99
features will not suffice, since alloca() is not one of them.
