0

I'm trying to write a function in C that reads a file into char array passed to it.

void read_file(char* path, char** bufptr, char* buffer){
  /* open the file, and exit on errors */
  FILE *fp = fopen(path, "r");
  if(fp == NULL){
    perror("Failed to open file");
    exit(1);
  }
  /* figure out how long the file is to allocate that memory */
  fseek(fp, 0, SEEK_END);
  long length = ftell(fp);
  rewind(fp);
  /* allocate memory */
  *bufptr = realloc(*bufptr, length+1);
  fread(buffer, length, 1, fp);
  buffer[length] = 0;
}

The idea is that I would use it something like this:

int main(int argc, char** argv){
  char* somestring = malloc(1024);
  core_read_file("/some/file/path", &somestring, somestring);
  printf("In main(): %s\n", somestring);
  free(somestring);
  return 0;
}

However whenever I use it, while the program compiles, the printf prints nothing to the console. I'm starting out and kind of understand the idea of "indirection" to a very very basic degree, but can someone explain to me why my code doesn't work the way I expect it to, and how I should go about implementing this function.

(This isn't a homework assignment so any solution or method that works is perfect)

6
  • 6
    I don't think you need the buffer argument to read_file. Simply write *bufptr anywhere you're currently writing buffer, e.g. fread(*bufptr, ...); (*bufptr)[length] = 0 Commented Oct 2, 2017 at 11:41
  • 2
    You should open the file with rb mode. Also the usual "you're overwriting the old pointer in realloc" complaint... Commented Oct 2, 2017 at 11:46
  • Instead of realloc, could you malloc the right amount initially and return that? Commented Oct 2, 2017 at 11:47
  • 4
    If the realloc moves the data to a new address, then buffer points to an invalid address (memory that is no longer allocated). Commented Oct 2, 2017 at 11:48
  • 2
    you have also check return value of functions you are calling (like malloc, realoc, fread) and your core_read_file function instead of void - make to return number of bytes read of error if something goes wrong Commented Oct 2, 2017 at 11:54

2 Answers 2

2

The last two lines of read_file should be:

  fread(*bufptr, length, 1, fp);
  (*bufptr)[length] = 0;

The pointer in the newly allocated buffer is in *bufptr, not in buffer.

But your program is overly complicated, you don't need to pass three parameters do read_file. Two is enough, like this:

void read_file(char* path, char** bufptr) {
  /* open the file, and exit on errors */
  FILE *fp = fopen(path, "r");
  if (fp == NULL) {
    perror("Failed to open file");
    exit(1);
  }
  /* figure out how long the file is to allocate that memory */
  fseek(fp, 0, SEEK_END);
  long length = ftell(fp);
  rewind(fp);
  /* allocate memory */
  *bufptr = realloc(*bufptr, length + 1);
  fread(*bufptr, length, 1, fp);
  (*bufptr)[length] = 0;
}    

int main(int argc, char** argv) {
  char* somestring = malloc(1024);  //  char* somestring = NULL would be even better here
  read_file("readme.txt", &somestring);
  printf("In main(): %s\n", somestring);
  free(somestring);
  return 0;
}

There is still no error checking for realloc here for brevity.

Sign up to request clarification or add additional context in comments.

Comments

2

If you are going to allocate memory inside the function - there is no need to allocated outside. But there should be documented aggreement - that in case of failure - nothing is left unfreed, in case of success - calling function is responsible to free the buffer pointer.

Your read function has to have a lot more error checking and also has to close the file on any branch.

Here is the sample code that does the reading:

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>

long read_file(const char* path, char** bufptr) {
    char* buffer;
    int res;
    size_t read;
    FILE *fp;
    if (path == NULL || bufptr == NULL) {
        perror("Invalid parameters");
        return -6;
    }
    /* open the file, and exit on errors */
    fp = fopen(path, "rb");
    if (fp == NULL) {
        perror("Failed to open file");
        return -1;
    }
    /* figure out how long the file is to allocate that memory */
    res = fseek(fp, 0, SEEK_END);
    if (res != 0) {
        perror("Failed to seek file");
        fclose(fp);
        return -2;
    }
    long length = ftell(fp);
    if (length <= 0) {
        perror("Failed ftell");
        fclose(fp);
        return -3;
    }
    rewind(fp);
    /* allocate memory */
    buffer = malloc(length + 1);
    if (buffer == NULL) {
        perror("Out of memory");
        fclose(fp);
        return -4;
    }
    read = fread(buffer, 1, length, fp);
    fclose(fp);

    if ((long)read != length) {
        perror("Failed to read whole file");
        free(buffer);
        return -5;
    }
    buffer[length] = 0;
    *bufptr = buffer;
    return length;
}
int main() {
    char* somestring;
    long res = read_file("c:/key.txt", &somestring);
    if (res < 0) {
        //nothing is leaked - everything opened or allocated was closed and freed by the function
        exit(res);
    }
    printf("In main(): %s\n", somestring);
    free(somestring);
    return 0;
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.