Home > OS >  Exception: Access Violation when trying to use fscanf()
Exception: Access Violation when trying to use fscanf()

Time:12-29

I'm trying to read a file, which contains three lines of text, and store its contents into an array.

It should be rather straightforward, but I keep getting an "Exception: Access Violation", as per title.

This is my code:

    #include <stdio.h>
    
    int main(void) {
        FILE *fp;
        fp = fopen("Data", "r");
        char *str_read[3];
        int i;
        for (i = 0; i < 3; i  ){
            fscanf(fp, "%s", &str_read[i]);
            printf("%s\n", str_read[i]);
        }
        fclose(fp);
        return 0;
    }

I'm using Pelles C for Windows, on Windows 11. I don't know whether there's a mistake in my code or if something is off with the program I'm using (e.g. settings, missing components).

I haven't touched C in 13 years and figuring out how to compile anything was hard enough, so I doubt I'm going to figure this out on my own.

I expect the output to be three lines of text, corresponding to the contents of the "Data" file.

The code works if I get rid of fscanf() and manually set the contents of str_read, so I'm fairly sure the issue is in line 9.

I think I'm passing variables in the correct form, but I've tried messing around with & and * prefixes in pretty much every combination I could think of, in case I misunderstood the syntax.

If I choose "execute", I get "CRT: unhandled exception (main) -- terminating *** Process returned 255 ***". "Go/debug" has the aforementioned results.

Edit:

    #include <stdio.h>
    #define BUFLEN 80

    int main(void) {
        FILE *fp;
        if ((fp = fopen("Data", "r")) == NULL) {
            perror("fopen failed");
            return 1;
        }
        char str_read[3][BUFLEN];
        for (int i=0;  i<3;  i  ) {
            if (fgets(str_read[i], sizeof str_read[i], fp) == NULL) {
                perror("read failed");
                return 1;
            }
            printf("%s\r\n", str_read[i]);
        }

        fclose(fp);
        return 0;
    }

This is my current code, accounting for the answers I received. I appreciate the magnitude of my mistakes and I'm aware that there's still room for improvement, but this is more than good enough for its scope.

Getting the code to work for multiple lines (in variable numbers) with fscanf() would be nice as a way to better understand the function, but fgets() seems to work better for this purpose.

I'm marking this as solved.

CodePudding user response:

There are multiple problems here:

  1. You need to check to see if fopen failed.
  2. You need to allocate your string buffer correctly.
  3. You need to ensure you don't OVERWRITE your buffer.
  4. &str_read[i] forms a char** but fscanf(fp, "%s", ... requires a char*, so:
    fscanf(fp, "s", str_read[i]);
    // 19 if your buffer has size 20 to not write out of bounds
    

EXAMPLE:

#include <stdio.h>

#define BUFLEN 80

int main(void) {
    FILE *fp;
    char buffer[BUFLEN];
    int i;
    if ((fp = fopen("Data", "r") == NULL) {
      perror("fopen failed");
      return 1;
    }
    
    if (fgets(buffer, BUFLEN, fp) == NULL) {
      perror("read failed");
      return 1;
    }
    
    printf("%s", buffer);
    fclose(fp);
    return 0;
}

CodePudding user response:

The scanf() function never allocates space for an input string. You must do that ahead of time.

You shouldn’t be using scanf(), though. I assume you are attempting to read a line of input. Use fgets().

char s[1000];

// Attempt to read 999 characters maximum.
// Guaranteed to be nul-terminated on success.
if (!fgets(s, sizeof s, fp))
  fooey();

// Did we get the entire line?
// (Up-to and including the newline / ENTER key press?)
char * p = strpbrk(s, "\n\r");
if (!p)
  fooey();
*p = '\0'; // if yes then trim the newline

// Great! We got a complete line of text from the user.
printf("Got \"%s\"\n", s);

You may find it useful to put all the get-a-line stuff in a helpful function:

char * get_a_line(FILE *fp)
{
  static char s[1000];
  ...
  return s;
}

And use strdup() on the result.

for (int i=0;  i<3;  i  )
{
  char * s = get_a_line(fp);
  strs[i] = s ? strdup(s) : NULL;
}

Alternate version:

char * get_a_line(FILE *f)
{
  char s[1000] = {0};
  ...
  return strdup(s);
}

And:

for (int i=0;  i<3;  i  )
  strs[i] = get_a_line(fp);

Don’t forget to clean up before you are done:

for (int i=0;  i<3;  i  )
  free(strs[i]);

Of course, you could just allocate an array for your maximum expected string sizes:

char strs[3][500];

...

for (int n=0;  n<3;  n  )
{
  fgets(strs[n], sizeof strs[n], fp);
  char *p = strpbrk(strs[n], "\n\r");
  ...
}

C is much more obnoxious about getting input than you remember, right?

  • Related