简体   繁体   中英

C - 3rd scanf modifies a variable from 2nd scanf

I think I've tried anything (flushing stdin, scanf to consume newline etc.), but nothing works as I had hoped. For some reason a 3rd scanf modifies a variable from 2nd scanf in the following code:

#include <stdio.h>

int main()
{
  char first_name[16], last_name[21];
  char filename[11];
  FILE *opening;

  printf("The program saves your first and last name into a file.\n");

  printf("Enter your first name:");
  scanf("%s", first_name);
  getchar();

  printf("Enter your last name:");
  scanf(" %s", last_name);
  getchar();

  printf("File where you want to save your name:");
  scanf(" %s", filename);

  opening = fopen(filename, "wb");

  fprintf(opening, "%s %s", first_name, last_name);
  printf("\nSuccessfully saved the data!");

  fclose(opening);

  return 0;
}

The output:

The program saves your first and last name into a file.
Enter your first name: John
Enter your last name: Doe
File where you want to save your name: filename.txt

Successfully saved the data!

All fine and dandy except that the contents of filename.txt is this:

John t

I'm guessing that the 't' character comes from 'txt' somehow, but I've just started learning C and I don't know how to fix this piece of code to work. Could you gurus help me please?

Your filename buffer is too small.

You write filename.txt , which is 12 characters, plus the zero to finish it, makes 13. You only allocate 11. Try like this:

char filename[20];

and it should work.

Be careful though with using scanf , it can lead to very nasty problems, as you are encountering right now. It is good in experimenting and learning C, as it shows you how important correct memory handling is. For any real project you should consider using different functions or frameworks.

If you are entering filename.txt as your file name, then you are overrunning your buffer for filename . That is undefined behaviour and is the cause of the strange results.

To fix, make char filename[11]; larger, remembering to allow 1 extra character for the NULL terminator. In your very specific case, that would be char filename[14]; allowing for the errant space before %s in your scanf call.

Otherwise, all looks fine.

Using scanf() on strings is dangerous, as it may read in more data into the buffer than the buffer provides memory .

If scanning in strings one shall always tell scanf() how much characters to read by adding this number to the format passed to scanf() :

char file_name[11];

...

scanf("%10s", file_name); /* As file_name provides memor for 11 characters, read a
                             maximum of 10 characters into file_name leaving 1 
                             character room for the necessary `0-`terminator indicating 
                             the end of the "string". */

Also your code misses error checking on the fopen system call.

Better do something like this:

opening = fopen(filename, "wb");
if (NULL == opening)
{
  perror("fopen() failed");
  exit(EXIT_FAILURE);
}

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