Segmentation Fault when accessing char array outside function but noth within - c

so basically, thats the code producing my segmentation fault
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CORRUPT_KEY_FILE "s64581-source-key-corrupt.bin" /* ContainsKey and IV */
#define DEBUG 1
/**
* Reads content of a given file and writes it into a buffer
*
* #param filename Path of the file to be read
* #param buffer Pointer to the buffer to write into
* #param length Variable to store the filelength into
*
* #return EXIT_FAILURE if an error occurred opening th File, otherwise EXIT_SUCCESS
*/
int readFiletoBuffer(const char* filename, unsigned char* buffer, int* length) {
int i;
if(DEBUG) printf("\n\nFunction readFileToBuffer(..) called\n");
FILE *file = fopen(filename, "rb");
if(!file) {
printf("Error opening file %s", filename);
return EXIT_FAILURE;
}
fseek(file, 0 , SEEK_END);
*length = ftell(file);
rewind(file);
if(DEBUG) printf("\tLength of File %s: %d\n",filename ,*length);
buffer = (unsigned char*) malloc(*length+1);
fread(buffer, *length, 1, file);
fclose(file);
for(i=0; i<*length; i++) printf("%d:\t%X\n",14, buffer[14]);
return EXIT_SUCCESS;
}
int main(int argc, char **argv)
{
unsigned char *tmp_char;
int tmp_length, i;
tmp_char=NULL;
readFiletoBuffer(CORRUPT_KEY_FILE, tmp_char, &tmp_length);
for(i=0; i<tmp_length; i++) printf("%d:\t%X\n",i, tmp_char[i]);
return 0;
}
Notice the two for loops printing the content of the buffer. The one inside the function works fine, the one in the main-function produces a segmentations fault. Why is that, and how could I fix this while allocating the needed memory within the function readFiletoBuffer ?
Any help is appreciated! :D

To take the char array you want from the function you have to pass a char** array as argument.
In that way your char* pointer will be returned.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CORRUPT_KEY_FILE "s64581-source-key-corrupt.bin" /* ContainsKey and IV */
#define DEBUG 1
/**
* Reads content of a given file and writes it into a buffer
*
* #param filename Path of the file to be read
* #param buffer Pointer to the buffer to write into
* #param length Variable to store the filelength into
*
* #return EXIT_FAILURE if an error occurred opening th File, otherwise EXIT_SUCCESS
*/
int readFiletoBuffer(const char* filename, unsigned char** buffer, int* length) {
int i;
if(DEBUG) printf("\n\nFunction readFileToBuffer(..) called\n");
FILE *file = fopen(filename, "rb");
if(!file) {
printf("Error opening file %s", filename);
return EXIT_FAILURE;
}
fseek(file, 0 , SEEK_END);
*length = ftell(file);
rewind(file);
if(DEBUG) printf("\tLength of File %s: %d\n",filename ,*length);
*buffer = (unsigned char*) malloc(*length+1);
fread(*buffer, *length, 1, file);
fclose(file);
for(i=0; i<*length; i++) printf("%d:\t%X\n",14, buffer[14]);
return EXIT_SUCCESS;
}
int main(int argc, char **argv)
{
unsigned char *tmp_char;
int tmp_length, i;
tmp_char=NULL;
readFiletoBuffer(CORRUPT_KEY_FILE, &tmp_char, &tmp_length);
for(i=0; i<tmp_length; i++) printf("%d:\t%X\n",i, tmp_char[i]);
return 0;
}
Here is my suggestion.

The problem is, when you call your function readFiletoBuffer with parameter tmp_char, this parameter will be copied! Your tmp_char is NULL after call this function!
You need to work with the pointer to this parameter to change it like this:
tmp_char=NULL;
readFiletoBuffer(CORRUPT_KEY_FILE, &tmp_char, &tmp_length);
So your function will look like this:
int readFiletoBuffer(const char* filename, unsigned char** buffer, int* length)

Related

Writing to file in C overwrites variables

Description:
I have created a small program that stores the name and checksum of a file in a struct, for each file in a directory. When output is written to stdout with printf, everything seems fine, but if we write to a file with either fputs or fprintf, values get overwritten, perhaps because of some buffer overflow?
Output from main with print.
Name: 2.txt. Checksum: fc769d448ed4e08bd855927bad2c8e43efdf5315a6daa9f28577758786d52eaf
Name: 1.txt. Checksum: 2d46cffd0302c5537ddb4952a9cca7d66060dafecd56fe3a7fe8e5e5cabbbbf9
Name: 3.txt. Checksum: 37bb2e5563e94eee68fac6b07501c44f018599482e897a626a94dd88053b4b7e
However, if we print the values of checksumMaps[0] to a file,
the value checksumMaps[0].filename gets overwritten (with the last 2 bytes of the checksum string) as seen by:
FILE *fp = fopen("mychecksums.txt", "w");
char formatted_bytes[32*2+1];
char *filename = checksumMaps[0].filename;
format_bytes(formatted_bytes, checksumMaps[0].checksum);
fputs(filename, fp);
fputs(formatted_bytes, fp);
// We print the value of `filename` again in order to see that it has been overwritten.
printf("%s \n", filename);
fclose(fp);
The program writes aftxt to stdout instead of 2.txt.
Using gdb, I can see that the value of filename changes from 2.txt to aftxt after the line fputs(formatted_bytes, fp);. What could be the reason for this?
Minimal Reproducible Example
ArchiveFile.h
typedef struct ArchiveFile{
char *uuid;
char *checksum;
char *relative_path;
int is_binary;
} ArchiveFile;
typedef struct file_content{
unsigned char* bytes;
unsigned long file_size;
} file_content;
void set_uuid(ArchiveFile *file, char* uuid);
char* get_absolute_path(ArchiveFile *file, char* root);
char* get_file_text(ArchiveFile *file, char* root);
void get_bytes(ArchiveFile *file, char* root, unsigned char *buffer, size_t fsize);
long get_file_size(ArchiveFile *file, char *root);
ArchiveFile.c
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include "ArchiveFile.h"
#include <string.h>
void set_uuid(ArchiveFile* file, char* uuid){
file->uuid = uuid;
}
char* get_absolute_path(ArchiveFile *file, char* root){
/* Allocate space according to the relative path +
the root path + null terminating byte.*/
char* absolute_path = malloc(strlen(file->relative_path) + strlen(root) + 1);
// Add the root path.
strcpy(absolute_path, root);
// Concatonate the root with the rest of the path.
strcat(absolute_path, file->relative_path);
return absolute_path;
}
char* get_file_text(ArchiveFile *file, char* root){
char* absolute_path = get_absolute_path(file, root);
FILE *fp = fopen(absolute_path, "r");
if(fp == NULL)
printf("Could not open file %s \n", absolute_path);
// Platform independent way of getting the file size in bytes.
fseek(fp, 0, SEEK_END);
long fsize = ftell(fp);
fseek(fp, 0, SEEK_SET); /* same as rewind(f); */
char *buffer = malloc(fsize);
if(fp){
fread(buffer, sizeof(char), fsize, fp);
}
fclose(fp);
free(absolute_path);
return buffer;
}
void print_bytes2(unsigned char* md, size_t size){
for (size_t i = 0; i < size; i++) {
printf("%02x ", md[i]);
}
printf("\n");
}
void get_bytes(ArchiveFile *file, char *root, unsigned char *buffer, size_t fsize){
char* absolute_path = get_absolute_path(file, root);
FILE *fp = fopen(absolute_path, "rb");
if(fp){
fread(buffer, 1, fsize, fp);
}
free(absolute_path);
fclose(fp);
}
long get_file_size(ArchiveFile *file, char *root){
char* filepath = get_absolute_path(file, root);
FILE *fp = fopen(filepath, "rb");
fseek(fp, 0, SEEK_END);
long fsize = ftell(fp);
fseek(fp, 0, SEEK_SET); /* same as rewind(f); */
free(filepath);
fclose(fp);
return fsize;
}
checksum/checksum.h
// Used to store information about filename and checksum.
typedef struct ChecksumMap{
char* filename;
unsigned char checksum [32];
} ChecksumMap;
int calculate_checksum(void* input, unsigned long length, unsigned char* md);
checksum/checksum.h
#include <stdio.h>
#include <openssl/sha.h>
#include "checksum.h"
int calculate_checksum(void* input, unsigned long length, unsigned char* md){
SHA256_CTX context;
if(!SHA256_Init(&context))
return 0;
if(!SHA256_Update(&context, (unsigned char*)input, length))
return 0;
if(!SHA256_Final(md, &context))
return 0;
return 1;
}
main.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include "ArchiveFile.h"
#include "checksum/checksum.h"
void format_bytes(char* buffer, unsigned char* md){
for (int i = 0; i < 32; i++) {
sprintf(&buffer[i*2], "%02x", md[i]);
}
buffer[32*2] = '\0';
}
void *listdir(char *name, int count, ChecksumMap *checksumMaps)
{
DIR *dir;
struct dirent *direntry;
if (!(dir = opendir(name)))
return NULL;
while ((direntry = readdir(dir)) != NULL) {
// If we reach a directory (that is not . or ..) then recursive step.
if (direntry->d_type == DT_DIR) {
char path[1024];
if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0)
continue;
snprintf(path, sizeof(path), "%s/%s", name, direntry->d_name);
listdir(path, count, checksumMaps);
} else {
unsigned char md[32];
ArchiveFile file;
file.relative_path = direntry->d_name;
// Get the full path of the file:
char parent_name[strlen(name)+1];
memset(&parent_name[0], 0, sizeof(parent_name));
strcat(parent_name, name);
strcat(parent_name, "/");
size_t fsize = get_file_size(&file, parent_name);
unsigned char *bytes = malloc(sizeof(char) * fsize);
get_bytes(&file, parent_name, bytes, fsize);
calculate_checksum((void*) bytes, fsize, md);
ChecksumMap checksumMap = {.filename=file.relative_path};
memcpy(checksumMap.checksum, md,
sizeof(checksumMap.checksum));
free(bytes);
}
}
closedir(dir);
return NULL;
}
int main(int argc, char const *argv[]) {
FILE *fp = fopen("mychecksums.txt", "w");
char formatted_bytes[32*2+1];
char *filename = checksumMaps[0].filename;
format_bytes(formatted_bytes, checksumMaps[0].checksum);
fputs(filename, fp);
fputs(formatted_bytes, fp);
// We print the value of `filename` again in order to see that it has been overwritten.
printf("%s \n", filename);
fclose(fp);
}
Compile with gcc:
gcc -Wall -Wextra main.c ArchiveFile.c checksum/checksum.c -lcrypto
The program writes aftxt to stdout instead of 2.txt. Using gdb, I can see that the value of filename changes from 2.txt to aftxt after the line fputs(formatted_bytes, fp);. What could be the reason for this?
Hard to say, because we're in the domain of UB (undefined behavior). But there are two obvious candidates here.
formatted_bytes is not properly terminated, causing fputs to read past the array, invoking UB.
fp is not a valid stream. The reason could be that it's not initialized, or changed, or the stream is closed or something.
Enable -Wall -Wextra -fsanitize=address. You could also try -fsanitize=undefined.
Check all return values. malloc, fopen and fputs returns a value that can be used for error checking.
Replace formatted_bytes with a hardcoded string that have the value you think it has.
Learn how to create a Minimal, Reproducible Example and how to debug small c programs. It's a guide I wrote a while ago.
Update
It seems that there was some different problems with the code.
First thing to notice is file.relative_path = direntry->d_name;, however the value that direntry points to changes in each iteration, thus the value file.relative_path points to, also changes. Furthermore, the size of the string stored in file.relative_path has never been specified, which would be a problem, if we use strcpy.
The solution is to specify a size for file.relative_path and use strcpy to copy the value of direntry->d_name. Also, no need for the checksumMap struct, since ArchiveFile already can store the same information (again, specify a size for the checksum).
Thing to keep in mind when you work with strings, buffers, arrays in C:
Remember that strings in C are based on char arrays, themselves based on a pointer to the first element. Assigning the value of one string to another might return in unexpected behavior when you actually want to copy the value of the string, not the address to the first element.
One bug here:
char parent_name[strlen(name)+1];
memset(&parent_name[0], 0, sizeof(parent_name)); // could have been parent_name[0]='\0'; instead
strcat(parent_name, name); // Now the parent_name buffer is full and null terminated.
strcat(parent_name, "/"); // this overwrites the null terminator and writes a new one out-of-bounds
You should have done something like this:
size_t length = strlen(name);
char parent_name[length+1+1];
memcpy(parent_name, name, length); // copies characters only (fast) but not the null term
parent_name[length] = '/'; // append this single character 1 symbol past "name" string
parent_name[length+1] = '\0'; // add manual null termination

Segmentation Fault While Reading File in C

I am still very new to the c language and I am playing with reading files for the first time. I had similar code to this code which used to run perfectly fine but now I am running into issues. I keep getting the error Segmentation fault (core dumped) every time I try to run this program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student {
char first[30];
char last[30];
char ssn[9];
};
void make_arrays() {
FILE *fp = fopen("students.db", "r");
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
fseek(fp, 0, SEEK_SET);
long num_students = size / sizeof(struct student);
printf("There are %ld students in the file", num_students);
fclose(fp);
}
int main(int argc, char **argv[]) {
make_arrays();
return 0;
}
The segmentation fault might be caused by fopen failing to open the file.
You should always test for such failures and exit with an informative message.
Also note that, if the file is indeed binary, it should be open in binary mode to avoid end of line translation:
FILE *fp = fopen("students.db", "rb");
Also change the prototype for main to int main(int argc, char *argv[]) or simply int main(). There are too many stars in char **argv[].
You don't have to mark my answer as accepted, just want to inspire people to write code so that it is readable and safe. Don't be lazy to write code like this where quality is a factor.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
struct student /* Magic numbers everywhere */
{
char first[30];
char last[30];
char ssn[9];
};
void* handle_nullptr_error (void* ptr, char *action, int code)
{
if(ptr == NULL)
{
fprintf(stderr, "Failed to %s\n", action);
exit(code);
}
printf("Succeeded to %s\n", action);
return ptr;
}
int handle_nonzero_error (int val, char *action, int code)
{
if(val != 0)
{
fprintf(stderr, "Failed to %s\n", action);
exit(code);
}
printf("Succeeded to %s\n", action);
return val;
}
int handle_negval_error (int val, char *action, int code)
{
if(val < 0)
{
fprintf(stderr, "Failed to %s\n", action);
exit(code);
}
printf("Succeeded to %s\n", action);
return val;
}
/** This function is not guaranteed to be portable and work (but it will at least fail properly),
* because not all systems and/or library implementations support `SEEK_END` in files
* opened in text mode, as specified by #mode
* Moreover, in binary mode it will behave in an undefined manner, because different systems
* may store files data completely differently. In most cases it will succeed, just don't
* write code that crashes if not.
*/
long int get_file_charcount (const char *filename, char* mode)
{
FILE* fp = NULL;
long int fpSize = 0L;
/* Alignment for complicated function calls (for e.g where functions are passed as arguments) */
fp = handle_nullptr_error (fopen(filename, mode), "open file.", 1);
(void)handle_nonzero_error (fseek(fp, 0, SEEK_END), "seek end position.", 2);
fpSize = handle_negval_error (ftell(fp), "tell position.", 3);
fclose(fp); /* - May fail, as well */
return fpSize;
}
/** This function depends on POSIX headers and it is unix-conformant, although there are still
* some exceptions.
*
* Note that the value returned is the length of the contents of the symbolic link,
* and does not count any trailing null pads. The value is ought to be system-specific.
*/
_off64_t get_file_size (const char *filename)
{
struct stat st = {0};
(void)handle_negval_error(stat(filename, &st), "get file size.", (-1));
return st.st_size;
}
/** A validation function should first determine whether file's size is
* actually dividable by `sizeof(struct STUDENT_DESCRIPTION);`.
*
* Further more you can use `get_file_size()` as an alternative to
* `get_file_charcount()`. In the latter case, make sure you to specify the
* appropriate mode, "r" for text files and "rb" for binary files.
*/
void make_arrays ()
{
long int size = get_file_charcount("myfile.txt", "r");
long int num_students = size / sizeof(struct STUDENT_DESCRIPTION);
printf("size of file: %ld\n", size);
printf("There are %ld students in the file", num_students);
}
int main (void)
{
make_arrays();
return EXIT_SUCCESS;
}

Using od command

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char* argv[]) {
char *filename = argv[1];
char *store = malloc(2);
FILE *fh = fopen(filename, "wb");
for(int i = 0; i < 100; i++) {
sprintf(store, "%u", i);
if (fh != NULL) {
fwrite (store, sizeof (store), 1, fh);
}
}
fclose (fh);
return 0;
}
I want my output to look like this -> https://imgur.com/a/nt2ly. The output it produces currently is all garabge.
The real reason for the garbage is the size of your data on the fwrite statement
fwrite (store, sizeof (store), 1, fh);
sizeof(store) is not the size of the string. It's the size of the pointer.
Aside, allocating 2 bytes for store is wrong. You're forgetting that a 2-digit number as a string needs space for a nul-terminator, so you're writing one char too many.
More minor issue: why testing the handle against NULL in the loop? you could exit in that case.
Also test the argument length (argc).
int main(int argc, char* argv[]) {
if (argc<2) exit(1); // protect against missing arg
char *filename = argv[1];
char store[50]; // use auto memory, faster & simpler, don't be shy on the size, don't shave it too close
FILE *fh = fopen(filename, "wb");
if (fh != NULL) { // test file handle here, not in the loop
for(int i = 0; i < 100; i++) {
// sprintf returns the number of printed chars, use this
// also use the proper format specifier for int
int nb_printed = sprintf(store, "%d", i);
// you may want to check the return value of fwrite...
fwrite (store, nb_printed, 1, fh);
}
fclose (fh);
return 0;
}
Note that this code will create a binary file with all numbers collated:
01234567891011...
so hardly useable. I would perform a sprintf(store, "%d ", i); instead to add spacing between the numbers.
Also note that if you wanted to write characters in a file, you'd be better off with:
fprintf(fh,"%d ",i);
(but I suppose the main point is to learn to use fwrite)

C program to reverse content of a file and write that to another file

I'm having issues with an assignment where I have to take the contents of one file into a buffer, reverse those contents, and write them to another file. This program NEEDS to utilize two functions that look like this:
int read_file( char* filename, char **buffer );
int write_file( char* filename, char *buffer, int size);
so far my files look like this:
file_utils.h
#ifndef UTILS_H
#define UTILS_H
int read_file(char* filename, char **buffer);
int write_file(char* filename, char *buffer, int size);
#endif
file_utils.c
#include "file_utils.h"
#include <stdlib.h>
#include <stdio.h>
#include <font1.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
int read_file(char* filename, char **buffer) {
FILE* file1;
file1 = fopen(filename, "r");
//gets the size of the file
struct stat st;
stat(filename, &st);
int size = st.st_size;
buffer = malloc(size);
read(file1, &buffer, 1);
return size;
}
int write_file(char* filename, char*buffer, int size) {
FILE* file2;
file2 = fopen(filename, 'w');
for (int k = size - 1; k >= 0; k--) {
char* x = &buffer + k;
fprintf(file2, "%s", x);
}
printf(filename, '\O');
return 1;
}
reverse.c
#include "file_utils.h"
#include <stdlib.h>
#include <stdio.h>
#include <font1.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
char* buffer;
char* filename1;
char* filename2;
int filesize;
filename1 = argv[1];
filename2 = argv[2];
filesize = read_file(filename1, &buffer);
write_file(filename2, buffer, filesize);
return 0;
}
and that's all there is. I run it using "clang file_utils.c reverse.c" and I get warnings for file_utils.c like
incompatible integer to pointer conversion passing 'int" to parameter of type 'const char *' (for the line file1 = fopen(filename, 'r')
incompatible pointer to integer conversion passing 'FILE *' (aka 'struct_IO_FILE*') to parameter of type 'int' (for the line read(file1, &buffer, 1);)
the same warning as the first one but for the line file2 = fopen(filename, 'w');
and incompatible pointer types initializing 'char *' with an expression of type 'char **'; dereferences with * (for the line char* x = &buffer + k;)
on top of all this when I continue on to run the executable as such
./a.out file1 file2
where file 1 has text that should be reversed into file 2, I get a segmentation fault.
Any insight into things I can fix will be much appreciated.
Just off the top of my head, without testing, I see these bugs:
buffer = malloc(size); should be *buffer = malloc(size);
... because buffer is a pointer to pointer to char, you need to
dereference it once.
read(file1, &buffer, 1); should be fread(*buffer, 1, size, file1);
... because you opened file1 with fopen, so it's FILE *. read is
Unix I/O, not stream I/O, and doesn't use FILE *.
file2 = fopen(filename, 'w'); should be file2 = fopen(filename, "w");
The second argument should be a "string" (pointer to char or array of
char). 'w' is a single char.
char* x = &buffer + k; should be char *x = buffer + k;
buffer is a pointer to char, so you want to use it directly, not
take its address. Also note the style of putting * next to the
variable instead of the type. This is a good habit, because these
do not mean the same thing:
char *a, *b, *c; /* three pointers */
char* a, b, c; /* one pointer, two chars */
fprintf(file2, "%s", x); should be fprintf(file2, "%c", *x);
The first form treats x as the beginning of a string and will output
everything from that point onward until it hits a NUL terminator. You
want to output only one char, so use the %c specifier, and
dereference x to get a char.
A better way would be fwrite(x, 1, 1, file2);
printf(filename, '\O'); is not needed and doesn't do what you think.
It looks like you intended to write a NUL at the end. That would be
'\0' (zero), not '\O' (letter O). In any case, it's not needed or
wanted. NUL is used to terminate a string in C, not a file. Your output
file will be one character longer than it should be if you do this.
The most important issue with your code is here
char* x = &buffer + k;
fprintf(file2, "%s", x);
perhaps you mean
char *x = buffer + k;
fprintf(file2, "%c", *x);
You also, are mixing IO functions. For a FILE * object you should use fread() instead of read(), there should be an incompatible arguments warning from the compiler.
If there are no warnings (BTW char *x = &buffer + k should trigger another warning), then you should probably enable them explicitly so that your compiler can help you figure out other problems.
Also, check that file1 is not NULL after fopen(), check that fread() did read the requested amount, in general check for every possible error which you can easily infer from the return value of the implied function, if you don't know the meaning of such value then READ THE DOCUMENTATION before using such function.
And finally all together:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
int read_file(char* filename, char **buffer) {
FILE* file1;
file1 = fopen(filename, "r");
//gets the size of the file
struct stat st;
stat(filename, &st);
int size = st.st_size;
*buffer = malloc(size);
fread(*buffer, size, 1, file1);
fclose(file1);
return size;
}
void write_file(char* filename, char*buffer, int size) {
FILE* file2 = fopen(filename, "w"); int k;
for (k = size - 1; k >= 0; k--) {
fwrite(buffer + k, 1, 1, file2);
}
fclose(file2);
}
int main(int argc, char *argv[]) {
char* buffer;
char* filename1;
char* filename2;
int filesize;
filename1 = "input.txt";
filename2 = "reverse.txt";
filesize = read_file(filename1, &buffer);
write_file(filename2, buffer, filesize);
free(buffer);
return 0;
}
with a live demo. Please add checks for all return values, like malloc() does not return NULL.

Function mallocs a pointer and reads data into it, but caller can not access it

I have a specific problem: I have an issue when I try to use my own function to load file on memory.
load_file_on_memory() receives a filename and a pointer. It just opens the file, allocates memory dynamically for file content and fills it, and passes the pointer to the caller using destiny as an argument.
But I have a problem: Inside load_file_on_memory() function, I have success on malloc space for content. I can put data on pointer and get it, too.
When I try to use the pointer outside function, the caller just gets trash. I will post my code (shortly) here.
I can't understand why this happen. I am using Windows 7 with Tiny C Compiler. I don't know if that environment can cause errors.
Here's my source
#include <stdio.h>
#include <stdlib.h>
int load_file_on_buffer(char filename[], void *buffer_destiny){
FILE *file_loaded;
unsigned int file_size;
file_loaded = fopen(filename, "rb");
if(file_loaded == NULL)
return -1;
fseek(file_loaded, 0, SEEK_END);
file_size = ftell(file_loaded);
fseek(file_loaded, 0, SEEK_SET);
buffer_destiny = (void *) malloc(file_size);
fread((char *) buffer_destiny, file_size, 1, file_loaded);
printf("BEGIN DEBUG FILE\n");
printf("%s", buffer_destiny);
printf("\n\nEND DEBUG FILE\n");
fclose(file_loaded);
return 0;
}
int main(int argc, char *argv[]){
char *buffered_input_file;
///First, load input file
if(load_file_on_buffer("test.txt", (void *)buffered_input_file) != 0)
return -1;
printf("Input file loaded successfully\n");
printf("This function must print file content: \n\n");
printf("%s", buffered_input_file);
}
You are passing a parameter void* buffer_destiny. Once the function is entered, this is just a normal variable. Which you overwrite using a malloc () call. This has no effect on the calling function. Instead declare the function as
int load_file_on_buffer(char filename[], void **pbuffer_destiny)
call it as
void* buffered_input_file;
load_file_on_buffer("test.txt", &buffered_input_file)
and in the function write
void* buffer_destiny = malloc (...);
*pbuffer_destiny = buffer_destiny;
The pointer buffer_destiny is a local variable in the function load_file_on_buffer. Changing buffer_destiny has no effect on the pointer buffer_input_file in main. One way to fix the problem is to return the pointer to main.
Another problem is that you're using "%s" to print the files content. In order for that to work, you need to properly NUL terminate the buffer. In other words, the buffer needs to be one byte bigger than the file size and a NUL terminator '\0' needs to be placed in that extra byte.
#include <stdio.h>
#include <stdlib.h>
char *load_file_on_buffer( const char *filename )
{
FILE *file_loaded;
unsigned int file_size;
file_loaded = fopen(filename, "rb");
if(file_loaded == NULL)
return NULL;
fseek(file_loaded, 0, SEEK_END);
file_size = ftell(file_loaded);
fseek(file_loaded, 0, SEEK_SET);
char *buffer_destiny = malloc(file_size + 1);
fread( buffer_destiny, file_size, 1, file_loaded );
buffer_destiny[file_size] = '\0';
printf("BEGIN DEBUG FILE\n");
printf("%s", buffer_destiny);
printf("\n\nEND DEBUG FILE\n");
fclose(file_loaded);
return buffer_destiny;
}
int main(int argc, char *argv[])
{
char *buffered_input_file;
///First, load input file
if( (buffered_input_file = load_file_on_buffer("test.txt")) == NULL )
return -1;
printf("Input file loaded successfully\n");
printf("This function must print file content: \n\n");
printf("%s", buffered_input_file);
}
If you still want to pass the buffered_input_file as a parameter then this will work for you, I commented the code at some parts I believe clarification is required.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int load_file_on_buffer(char filename[], void **buffer_destiny)
{
FILE *file_loaded;
unsigned int file_size;
if (buffer_destiny == NULL)
return -1;
*buffer_destiny = NULL; /* to check in the calling function */
file_loaded = fopen(filename, "r"); /* rb is no longer needed in new code */
if(file_loaded == NULL)
return -1;
fseek(file_loaded, 0, SEEK_END);
file_size = ftell(file_loaded);
fseek(file_loaded, 0, SEEK_SET);
*buffer_destiny = malloc(1 + file_size); /* +1 for the null terminator */
if (*buffer_destiny == NULL)
{
fclose(file_loaded);
return -1;
}
/* add a null terminator so the string is acceptable by printf */
memset(*buffer_destiny + file_size, '\0', 1);
/* you got this wrong
*
* fread((char *) buffer_destiny, file_size, 1, file_loaded);
*
* the correct way is
*
* fread(void *ptr, size_t size, size_t count, FILE *fp);
*
* where size is the size of each element and count is the number of elements.
*/
if (fread(*buffer_destiny, 1, file_size, file_loaded) != file_size)
{
free(*buffer_destiny);
*buffer_destiny = NULL;
fclose(file_loaded);
return -1;
}
printf("BEGIN DEBUG FILE\n");
printf("%s", (char *)*buffer_destiny);
printf("END DEBUG FILE\n");
fclose(file_loaded);
return 0;
}
int main(int argc, char *argv[])
{
char *buffered_input_file;
if (load_file_on_buffer("data.dat", (void **)&buffered_input_file) != 0)
return -1;
printf("Input file loaded successfully\n");
printf("This function must print file content: \n\n");
printf("%s", buffered_input_file);
free(buffered_input_file);
return 0;
}
buffered_input_file is NULL initially in main() and passed to load_file_on_buffer() by value. buffer_destiny initially got NULL from main() but inside function after memory allocation it should behave normally as you mentioned. However buffer_destiny is a local variable not a pointer for passed variable, hence at the end of function it loses its information and buffered_input_file in main() is still NULL.

Resources