0

I'm trying to write a function that receives a pointer to a file and two strings (a filename and a mode). It should ask for a filename, and open a file while error-checking. But the code doesn't compile and I've spent a couple of hours looking for a reason.

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

#define LEN 41

char* s_gets(char *str, int len);
void openFilename(FILE* fp, char* fname, char* mode);

int main(void)
{
  char fname[LEN];
  FILE *fp = NULL;
  int ch;

  // This works
  printf("Enter a filename: ");
  s_gets(fname, LEN);
  fp = fopen(fname, "r");

  // This does not
  // openFilename(fp, fname, "r");

  while ((ch = getc(fp)) != EOF)
    putchar(ch);

  fclose(fp);

  return 0;
}

char* s_gets(char *str, int len)
{
  char* ret_val;
  char* newline;
  
  ret_val = fgets(str, len, stdin);
  if (ret_val) {
    newline = strchr(str, '\n');
    if (newline)
      *newline = '\0';
    else
      while (getchar() != '\n') continue;
  }

  return ret_val;
}

void openFilename(FILE *fp, char *fn, char *mode)
{
  printf("Enter a filename: ");
  s_gets(fn, LEN);

  printf("Opening %s... ", fn); // This never runs!

  if ((fp = fopen(fn, mode)) == NULL) {
    fprintf(stderr, "Couldn't open %s. Quitting.\n", fn);
    exit(EXIT_FAILURE);
  }
}

The s_gets() function works fine if I call it from main, but as soon as I call it from openFilename() I get a Segmentation fault: 11 which usually has to do with arrays out of bounds, right? So I'm assuming that I'm not passing properly the string argument for the filename to openFilename(), but how can I do that?

Bobby Wan-Kenobi
  • 885
  • 9
  • 18
  • 1
    The issue is the pointer changes locally in the function that is called but not for the caller. If you are allocating/changing a pointer in a seperate function you need to pass a double pointer. `void openFilename(FILE** fp, char* fname, char* mode)` – Irelia Oct 18 '20 at 18:11
  • Hmm, so the issue is with the FILE pointer? Not sure what to use when I invoke the function, ``openFilename(&fp, fname,"r");`` ? – Bobby Wan-Kenobi Oct 18 '20 at 18:15
  • 1
    That is correct. – Irelia Oct 18 '20 at 18:15
  • Ooooooh, it works! Do you want to put it in an answer? – Bobby Wan-Kenobi Oct 18 '20 at 18:18

1 Answers1

0

When passing a variable into a function, it's passed by value not be reference. SO when the value of the variable is changed in the function, a copy passed onto the stack is changed but not the actual value of the variable from the caller. When you pass by reference, rather than a copy being passed onto the stack, its address is passed onto the stack and the value at that address is changed.

The same applies to pointers, when you pass a pointer the copy of the pointer is passed onto the stack though the value they point to is still the same; however, if you wanted to change the pointer itself you would then need to pass the address of the pointer into the function.

Change openFilename(FILE* fp, char* fname, char* mode) to openFilename(FILE** fp, char* fname, char* mode) and call the function with openFilename(&fp, fname,"r");

Irelia
  • 3,407
  • 2
  • 10
  • 31