HiveBrain v1.2.0
Get Started
← Back to all entries
snippetcMinor

Read file into char*

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
intofilecharread

Problem

Because I use the task so often, I wrote a C header for reading a file. I never formally learned C, so I'd really appreciate a code review on the code.

As a matter of personal taste, I do not put a space between the final parenthesis and an opening brace (){).

readfile.h

``
#ifndef _READ_FILE_INCL
#define _READ_FILE_INCL
#include / for FILE, fopen, getc, fclose, EOF /
#include / for malloc, realloc /

// the amount of bytes the file is initially guessed to be
#ifndef _READFILE_GUESS
#define _READFILE_GUESS 256
#endif

/*
* function
read_file
arguments: a file name (char)
returns: the contents of the file (char) or NULL if:
* 1. the file does not exist
* 2. memory allocation failed
* return value must be freed
*/
char read_file(char name){
FILE* file;
file = fopen(name, "r");

// 1. the file does not exist: return null
if(!file)
return NULL;

// allocate memory according to the initial guess
// (+ 1) for trailing null byte
char result = malloc(sizeof(char) _READFILE_GUESS + 1);

// 2. memory allocation failed
if(result == NULL)
return NULL;

// the position in the string to write the character to
size_t pos = 0;

// the amount of memory allocated for the string
size_t capacity = _READFILE_GUESS;

// character to hold the currently-read character from the file
char ch;

// until the character is the EOF character
while((ch = getc(file)) != EOF){
// update the character at position
pos to ch`
result[pos++] = ch;

// if the next position would exceed bounds
if(pos >= capacity){
// add the guess to the capacity
capacity += _READFILE_GUESS;

// allocate memory accordingly
// (+ 1) for trailing null byte
result = realloc(result, sizeof(char) * capacity + 1);

// 2. memory allocation failed
if(result == NULL)
ret

Solution

Getting Size of File

You can get the size of file (without asking the filesystem) by using fseek() and ftell().

if (fseeko(file, 0, SEEK_END) != 0) {
    // Error State do something
}
off_t sizeOfFile = ftello(file);
if (fseeko(file, 0, SEEK_SET) != 0) {
    // Error State do something
}

// Your file is now ready to be read and the size of the file is
// in `sizeOfFile`


Identifier Names

The identifier _READFILE_GUESS is reserved for the implementation. Don't use _ (underscore) as the first character in an identifier name.

Realloc

This is the wrong way to use realloc:

result = realloc(result, sizeof(char) * capacity + 1);


As you have noticed, when realloc fails it returns NULL. But it does not free the result value in this case. This means you have overwritten the value of result with null and thus leaked the memory it was pointing at.

char* newArea = realloc(result, sizeof(char) * capacity + 1);
if (newArea == NULL) {
    // Error condition handle it
    // You should probably release `result` by calling `free()`
    // before returning result
}
result = newArea;


Reading

Why are you only reading one byte at a time?

while((ch = getc(file)) != EOF)


Why not (attempt to) read capacity bytes at a time?

size_t blocksRead= 0;
size_t totalRead = 0;

while(1) {
    size_t read = fread(result + (blocksRead * capacity) + totalRead, 1, capacity - totalRead, file);
    if (ferror(file) != 0) {
        // Error State Deal with it.
    }
    totalRead += read;
    if (feof(file)) {
        break;
    }
    if (totalRead == capacity) {
        ++blocksRead;
        totalRead = 0;
        // Handle resize of block if you need too.
    }
}


License

Also note that by pasting the code into any Stack Exchange site you are already dual licensing your code under the CC license (see the bottom of the page for details).

So though your MIT License is valid it is not the only license this code is now available under.

Code Snippets

if (fseeko(file, 0, SEEK_END) != 0) {
    // Error State do something
}
off_t sizeOfFile = ftello(file);
if (fseeko(file, 0, SEEK_SET) != 0) {
    // Error State do something
}

// Your file is now ready to be read and the size of the file is
// in `sizeOfFile`
result = realloc(result, sizeof(char) * capacity + 1);
char* newArea = realloc(result, sizeof(char) * capacity + 1);
if (newArea == NULL) {
    // Error condition handle it
    // You should probably release `result` by calling `free()`
    // before returning result
}
result = newArea;
while((ch = getc(file)) != EOF)
size_t blocksRead= 0;
size_t totalRead = 0;

while(1) {
    size_t read = fread(result + (blocksRead * capacity) + totalRead, 1, capacity - totalRead, file);
    if (ferror(file) != 0) {
        // Error State Deal with it.
    }
    totalRead += read;
    if (feof(file)) {
        break;
    }
    if (totalRead == capacity) {
        ++blocksRead;
        totalRead = 0;
        // Handle resize of block if you need too.
    }
}

Context

StackExchange Code Review Q#163424, answer score: 9

Revisions (0)

No revisions yet.