Question: I wrote a function in C that reads an entire line from a stream into a dynamically allocated buffer. What would you suggest I should do to improve its performance? Also, are there any errors that could occur and are not handled?

This is the code:

```
#define ERRALLOC(ptr)                                        \
if (ptr == NULL) {                                           \
    printf("Unable to allocate memory for %s", #ptr);        \
    exit(1);                                                 \
}

#define PACK_SIZE 512

size_t readLine(FILE *istream, char **line_buffer, size_t *bufsize) {
    size_t line_size = 0;
    int eol_flag = 0;
    char temp_buffer[PACK_SIZE];
    while (fgets(temp_buffer, PACK_SIZE, istream) != NULL) {
        size_t temp_len = strlen(temp_buffer);
        line_size += temp_len;

        if (line_size+1 > *bufsize) {
            *bufsize = line_size+1;
            *line_buffer = realloc(*line_buffer, *bufsize * sizeof(char));
            ERRALLOC(*line_buffer)
        }

        if (temp_buffer[ temp_len - 1 ] == '\n') {
            temp_buffer[ temp_len - 1 ] = '\0';
            eol_flag = 1;
        }
        strcpy(*line_buffer + (line_size-temp_len), temp_buffer);

        if (eol_flag) break;
    }

    return line_size;
}

```

Answer: 
Overall, it's a lot of effort (perhaps not in the right place) for one line. Textual data typically has lines that are very short, on the order of 80 bytes. If you're so deeply concerned about performance, you need to back out of this function and look at the I/O pattern of the calling program for more context. You'll very likely find that it's more efficient to have a buffer much larger than your current `PACK_SIZE`, perhaps 4MB. Read the file into it one such chunk at a time with `fread`, not `fgets`; then iterate through to find and split on newlines. Roughly,

1. Allocate a large buffer
2. `fread` as much as possible
3. `memchr` your way to a newline
4. Set that newline to `'\0'`
5. Consume the line
6. Repeat 3-5 until you're at the end of the buffer
7. If there is a partial line segment at the end, then `memcpy` the segment to the beginning of the buffer and plan for the next `fread` to use a buffer write position that starts after the end of the segment
8. Repeat until end of file

The principle to heed here is that I/O (particularly disk I/O) is expensive, and frequent calls to the I/O layer are expensive even when cached at the operating system level. Doing as much in RAM as possible is strongly preferred.

If you want a convenience interface, then consider accepting a `FILE*` and a callback function, making the buffer locally rather than accepting it, and invoking the callback for each line when found.
> 
> 
> ```
> #define ERRALLOC(ptr)                                        \
> if (ptr == NULL) {                                           \
>     printf("Unable to allocate memory for %s", #ptr);        \
>     exit(1);                                                 \
> }
> 
> ```
> 
> 

That's a poor way to handle allocation failure, and makes your function pretty much unusable in any realistic program context. It's very rude to simply `exit()` from within a library function, and it's unhelpful to write to `stdout`, rather than `stderr` that's designed for such messages. And why are you not writing a complete line, with `\n` at the end?

> 
> 
> ```
>             *line_buffer = realloc(*line_buffer, *bufsize * sizeof(char));
> 
> ```
> 
> 

Don't do this; when allocation fails then the pointed-to memory is still allocated, but inaccessible. The standard pattern is

```
void *new_mem = realloc(buffer, newsize);
if (!new_mem) {
    return buffer;
    /* or free(buffer); return new_mem; */
}
buffer = new_mem;

```

Note also that `sizeof (char)` is 1 by definition, so multiplying by it has no effect.