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 <stdio.h> /* for FILE, fopen, getc, fclose, EOF */
#include <stdlib.h> /* 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)
return NULL;
}
}
// close the file
fclose(file);
// remove extra memory
result = realloc(result, sizeof(char) * pos);
// 2. memory allocation failed
if(result == NULL)
return NULL;
// `pos` now points to the index after the last character read
result[pos] = '\0';
return result;
}
#undef _READFILE_GUESS
/*
* MIT License
*
* Copyright (c) 2017 Conor O'Brien
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#endif