简体   繁体   中英

How to use fscanf() for two strings (of ANY length) and dynamically allocate/de-allocate the memory properly

I need to read an input.txt file and print out two separate strings from each line in the file. I used a while loop and a fscanf function to get each string and ignore blank space between. If the strings in a line of the input file are too long, I get a segmentation fault . However, I am also getting a munmap_chunk(): invalid pointer error when I run my executable.

If I don't allocate memory for string1 and string2, fscanf doesn't work properly. I believe fscanf is changing the pointers to string1 and string2, which is causing the munmap_chunk() error. However, I need to de-allocate the memory I gave string1 and string2 so I don't have memory leaks.

How do I scan this file for strings ( of ANY length ) and de-allocate the memory properly?

int main(int argc, char *argv[]) 
{
  char *string1;
  char *string2;
  string1 = (char *)malloc(sizeof(string1)); //these strings need memory allocated for the fscanf to function properly
  string2 = (char *)malloc(sizeof(string2)); 
  FILE* file = fopen(argv[1], "r");
  
  while (fscanf(file, "%s %s", string1, string2) != EOF)
    {
      printf("%s %s\n", string1, string2);
    }
  fclose(file);

  //Deallocating memory
  free(string1);
  free(string2);
  return 0;
}

'fscanf' does not change pointers but it can corrupt memory if you do not allocate enough space for your input.

And you are not allocating the memory correctly: string1 and string2 are pointers, so all you are allocating is a size of a pointer (4 or 8 bytes depending on your system).

If you need to read a line from a file and you do not know the maximum length of the line in advance, you can not use fscanf .

You need to allocate a starting buffer, say something like:

string1 = malloc(512 * sizeof(char));

Were 512 is an arbitrary but reasonably large length for a line. You then use fread to read one byte at a time in a loop, and check for end of line (usually '\n').

You must also count how much you read, and if the line is longer than 512 bytes, use realloc to increase the size of your buffer, like so:

if (bytesRead == (string1Size - 1) && curByte != '\n') {
    string1Size += 512;
    string1 = realloc(string1, string1Size);
}

Here, bytesRead is an int variable counting how many bytes you successfully read so far, and string1Size is also int variable used to track the size of string1 buffer.

string1 = (char *)malloc(sizeof(string1)); allocates memory for just 4 or 8 characters because string1 is a char * and that's how big a pointer is.

To allocate memory for let's say 100 characters you need to do char *string1 = malloc(sizeof(char) * 100) .

How do I scan this file for strings (of ANY length) and de-allocate the memory properly?

You can't with fscanf because it mixes reading input with parsing input. You don't know what's going to be read before you parse it.

Instead, read the line into a large buffer where you can examine it. Once you know how big the pieces are you can allocate just the right amount of memory and copy to it.

Because we are reusing the line buffer, and throwing it away when we're done, we can make it as large as we think we'll ever need. 1024 or 4096 are often good choices. I like BUFSIZ .

char line[BUFSIZ];
while( fgets(line, sizeof(line), file) ) {
  // now parse line
}

The parsing can be done in various ways. A simple one is strtok (STRing TOKenize). This tokenizes line in place. Copy them to the right amount of memory with strdup .

char line[BUFSIZ];
while( fgets(line, sizeof(line), file) ) {
  char words[2];
  int i = 0;

  for(
    char *word = strtok(line, " ");
    word;
    word = strtok(NULL, " ")
  ) {
    words[i] = strdup(word);
    i++;
  }

  printf("%s %s", words[0], words[1]);
  free(words[0]);
  free(words[1]);
}

line and words are allocated on the stack, they will be freed automatically. But the memory allocated by strdup is on the heap, it needs to be freed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM