事实证明,编写一个fgets()
重复使用以返回malloc()
ed 字符串的函数并不容易。
该函数没有正确报告错误:如果使用realloc()
or发生错误fgets()
,则返回到目前为止检索到的数据。
除此之外,该功能被证明非常有用。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char * read_one_line(FILE * in)
{
size_t alloc_length = 64;
size_t cumulength = 0;
char * data = malloc(alloc_length);
while (1) {
char * cursor = data + cumulength; // here we continue.
char * ret = fgets(cursor, alloc_length - cumulength, in);
printf("r %p %p %zd %zd %zd\n", data, cursor, cumulength, alloc_length, alloc_length - cumulength);
if (!ret) {
// Suppose we had EOF, no error.
// we just return what we read till now...
// there is still a \0 at cursor, so we are fine.
break;
}
size_t newlength = strlen(cursor); // how much is new?
cumulength += newlength; // add it to what we have.
if (cumulength < alloc_length - 1 || data[cumulength-1] == '\n') {
// not used the whole buffer... so we are probably done.
break;
}
// we need more!
// At least, probably.
size_t newlen = alloc_length * 2;
char * r = realloc(data, newlen);
printf("%zd\n", newlen);
if (r) {
data = r;
alloc_length = newlen;
} else {
// realloc error. Return at least what we have...
// TODO: or better free and return NULL?
return data;
}
}
char * r = realloc(data, cumulength + 1);
printf("%zd\n", cumulength + 1);
return r ? r : data; // shrinking should always have succeeded, but who knows?
}
int main()
{
char * p = read_one_line(stdin);
printf("%p\t%zd\t%zd\n", p, malloc_usable_size(p), strlen(p));
printf("%s\n", p);
free(p);
}