Mario
Mario

Reputation: 199

getline() memory reallocation fails

After successfully opening a file with FILE * some_file("somefile.txt", "r"), I'm using getline() to read a line. I can provide getline() enough buffer char * line = malloc((size_t) 1024);, which works fine. I can also provide less buffer than needed - char * line = malloc((sizeof(char))) or a NULL-pointer char * line = NULL;, and, as expected, getline() is allocating/reallocating and modifying value of line.

char * line = malloc((sizeof(char)))
size_t n;
n = getline(&line, &n, some_file);

But if I declare a pointer without defining some value or buffer, I get the error not enough space (the system is not crashing!).

char * line ;
size_t n;
n = getline(&line, &n, some_file); // Error: Not enough space

Where's the difference between providing a specific buffer char * line = malloc(sizeof(char))) - which should be a pointer to a char (I know I'm allowed to use this memory due to malloc()) and char * line; - which should also be a pointer to a char (of course I don't know if I'm allowed to use this memory, but the program is not crashing)?

Upvotes: 0

Views: 201

Answers (1)

The problem is the lack of initialization of variables, which leads to values not expected by getline. If unitialized, variables with automatic storage duration have indeterminate values. Using those values will lead to undefined behaviour.

The proper way to initialize line is to set it to NULL and let getline do the malloc it seems fit,

or if you already have allocated some memory that you insist you want to reuse again here, then n needs to be set to the size of the memory allocation. I.e. either:

char * line = malloc(1);
size_t n = 1;
ssize_t rv = getline(&line, &n, some_file);

OR

char * line = NULL
size_t n; // or can explicitly initialize this to `= 0` but it shouldn't matter
ssize_t rv = getline(&line, &n, some_file);

Therefore both excerpts in your question are dead wrong.

Finally, the return value is of type ssize_t and it has nothing to do with n except that upon return the value of that will be strictly less than the value stored in n. You must not store it in the same variable!


To process each and every line in some file with getline it is not necessary to call malloc - and just let getline handle the memory allocation:

char * line = NULL;
size_t n = 0;
while (1) {
    errno = 0;
    ssize_t rv = getline(&line, &n, some_file);
    if (rv < 0) {
        if (feof(some_file)) {
            fprintf(stderr, "end of file, no problemo.");
        }
        else if (ferror(some_file)) {
            perror("an error occurred while reading from the file");
        }
        else {
            perror("some other error occurred");
        }
        free(line);
        break;
    }

    // at this point `line` points to an array
    // of `rv` characters, with possible embedded nulls,
    // meaning one line of data from the file,
    // + the terminating null character
    //
    // `n` is the *total number* of allocated bytes in the 
    // allocation pointed to by `line`.

    printf("I got a line of input: ");
    fwrite(line, 1, rv, stdout);
}

Upvotes: 4

Related Questions