snippetcMinor
Read file into char*
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
``
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
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
Identifier Names
The identifier
Realloc
This is the wrong way to use
As you have noticed, when
Reading
Why are you only reading one byte at a time?
Why not (attempt to) read
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.
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.