scanf() doesn't read whitespaces?

This was my input:
Rie Ishida

but the only one that is saved into the variable nme is Rie. Doesn't scanf() get the whole string until the null terminator? I tried using gets() but when I run it, it didn't even prompt the user to input anything, it just went to the next line of code immediately.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
int addAcct(){
	FILE *fp;
	char nme[60];
	char acn[20];
	char pina[10];
	char pinb[10];
	long int bal = 0;
	int pinstat = 0;
	
	clrscr();
	printHdr(1);
	
	printf("Please enter your Full Name (50 characters max):\n");
	scanf("%s", &nme);
	
	printf("%s", &nme);
	while (pinstat != 1){
		printf("\nPlease key in your 6-digit PIN code: ");
		scanf("%s", &pina);
		
		if ((strlen(pina) > 6) || (strlen(pina) < 6)) {
			printf("\nPlease enter a 6-digit PIN code.");
		} else {
			printf("Please re-enter your new PIN code: ");
			scanf("%s", &pinb);
			
			if (strcmp(pina, pinb) != 0) {
				printf("\nEntered PIN codes do not match.\n");
			} else {
				pinstat = 1;
			}
		}
	}
	
	itoa(rand()%MAXACT, acn, 10);
	
	fp = fopen("/acctinfo.txt", "w+");
	if (NULL != fp) {
		printf("\nYour account information is as follows:\n");
		printf("Account Name:    %s\n", nme);
		printf("Account Number:  %s\n", acn);
		printf("Current Balance: %ld", bal);
		
		fprintf(fp, "%s\n%s\n%s\n%ld", nme, acn, pina, bal);
	} else {
		printf("\nERROR!");
		printf("\nAccount information not found.");
		exit(EXIT_FAILURE);
	}

	printf("\n\nEnrollment complete!");
	
	getch();
	
	return 1;
}
All formatted input functions stop at whitespace, both in C and C++.

Your scanf()s should also have safeguards on how many characters can be input. For example:

1
2
  char name[20];
  scanf( "%19s", name );  /* There's only room to read 19 characters + '\0' */


Switching to gets() was a good idea, but the problem was that you had used scanf() some time before. Consider the following input:

    5\nyoroshite kudasai\n

Notice the newlines in there? If you use scanf() to read "5", the first newline is not eaten up, but remains. So the input now looks like:

    \nyoroshite kudasai\n

When you now try to fgets() the string, it thinks that you are done because of that newline. You have to get rid of it first.

In C++ there's a routine to do that, but in C you have to write your own.

1
2
3
4
5
void ignoref( FILE* f, size_t n, char c )
  {
  while (n-- && (fgetc( f ) != c))
    ;
  }

User input will always end with an Enter Key press, meaning a newline, so it is good to keep those out of the way.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  int age;
  char name[20];
  char* p;

  printf( "What is your age? " );
  fflush( stdout );
  scanf( "%d", &age );
  ignoref( stdin, (-1), '\n' );  /* get rid of the Enter Key that the user just pressed */

  printf( "What is your name? " );
  fflush( stdout );
  fgets( name, 20, stdin );
  /* Of course, now you must get rid of the newline in your string. */
  p = strchr( name, '\n' );
  if (p) *p = '\0';
  else ignoref( stdin, (-1), '\n' );  /* but if it wasn't in the string then you must still get it from input */


Another way of handling input is typically to fgets() the user's input entirely, then sscanf() the stuff you want out of it.

Sorry it isn't any simpler. It really is a very obnoxious way to handle input, but that's the way it has always been in C and C++. It might be worth your time writing a function which gets the thing you want (like an integer) and cleans up the newline. Then you only need to call your special function and you'll know that input is synchronized with newlines.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int get_int( FILE* stream, int default_value )
  {
  int result;
  if (!fscanf( stream, "%d", &result )) result = default_value;
  ignoref( stream, (-1), '\n' );
  return result;
  }

int main()
  {
  int n;
  puts( "How many times?" );
  n = get_int( stdin, 0 );
  while (n--)
    puts( "Yeah!" );
  return 0;
  }


Good luck!
scanf("%[%s ]", nme);

EDIT: Corrections
scanf("%[a-zA-Z ]", nme);

1
2
3
4
5
int main() {
	char name[60];
	scanf("%[a-zA-Z ]", name);
	puts(name);
}


input: David Gotye
output: David Gotye
Last edited on
@Smac89
What?
Fixed :D
@Smac89: Thank you. I tried you code but unfortunately, it didn't work. I'm using Turbo C, by the way (I keep forgetting to mention that, sorry).

@Duoas: I would just like to confirm, in your code:

1
2
3
4
5
6
7
int get_int( FILE* stream, int default_value )
  {
  int result;
  if (!fscanf( stream, "%d", &result )) result = default_value;
  ignoref( stream, (-1), '\n' );
  return result;
  }


It looks as if you're getting input text from a file, not user input (please correct me if I'm wrong, as I'm not used to using fgets for getting user input).
Yes, it is the same thing.

1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
  {
  int age = 0;
  printf( "%s", "How old are you? " );
  while (1)
    {
    fflush( stdout );
    age = get_int( stdin, -1 );
    if (age >= 0) break;
    printf( "%s", "What? Try again: " );
    }
  return 0;
  }

All I/O is done through streams. A disk file is one type of stream. User input is another. But from your point of view, they work very similarly.

Hope this helps.
just try the inverted scanf and it'll work :)
1
2
printf("Please enter your Full Name (50 characters max):\n");
	scanf("%[^\n]", nme);

this kind of scanf reads every thing except those specified in the square brackets (with the '^' symbol, sr i don't know what it is in English, i'm Vietnamese :D lol)

EDIT: it's not necessary to use the ampersand (&) to read strings in scanf
EDIT2: Thank Smac89, i just copied his code and forgot that 's' :))
Last edited on
Not sure why the one I posted didn't work for you, but this one you have, looks interesting. I think it should be scanf("%[^\n]", nme); no?
@Smac89: Tbh, I'm not sure? I was initially using fgets(). Do you mind looking if I'm using it incorrectly? Because the fgets() didn't copy the spaces either. Here is my code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
int addAcct(){
	FILE *fp;
	char nme[60];
	char acn[10];
	char pina[10];
	char pinb[10];
	long int bal = 0;
	int pinstat = 0;
	
	clrscr();
	printHdr(1);
	
	printf("Please enter your name (50 characters max): ");
	do{
		//fgets(nme, sizeof(nme), stdin);
		scanf("%[^\n]", nme);
	}while(nme[0] == '\n');

	while (pinstat != 1){
		printf("\nPlease key in your 6-digit PIN code: ");
		fgets(pina, sizeof(pina), stdin);

		if ((strlen(pina) > 6) || (strlen(pina) < 6)) {
			printf("\nPlease enter a 6-digit PIN code.");
		} else {
			printf("Please re-enter your new PIN code: ");
			fgets(pinb, sizeof(pinb), stdin);

			printf("%s %s %s", nme, pina, pinb);
			getch();
			
			if (strcmp(pina, pinb) != 0) {
				printf("\nEntered PIN codes do not match.\n");
			} else {
				pinstat = 1;
			}
		}
	}
	
	itoa(random(1000), acn, 10);
	
	fp = fopen("/acctinfo.txt", "w+");
	if (NULL != fp) {
		printf("\nYour account information is as follows:\n");
		printf("Account Name:    %s\n", nme);
		printf("Account Number:  %s\n", acn);
		printf("Current Balance: $ %ld.00", bal);
		
		fprintf(fp, "%s\n%s\n%s\n%ld", nme, acn, pina, bal);
	} else {
		printf("\nERROR!");
		printf("\nAccount information not found.");
		exit(EXIT_FAILURE);
	}

	printf("\n\nEnrollment complete!");
	fclose(fp);
	getch();
	
	return 1;
}


EDIT: Does anyone know the format for sscanf() wherein you have to identify the width of the input string? I was thinking of getting the complete length of the input string and then taking out the '\n' either by replacing it with a null or just removing it altogether...
Last edited on
http://www.cplusplus.com/reference/cstdio/sscanf/

If you want to use that condition on line 17, then set name[0] to newline character.

To ignore numbers as well as newline character, do %[^\n0-9]
That's the thing. I can't get fgets() to work. Not sure if it's with my compiler (using Turbo C in DOSBox on a Win 7 x64 terminal), but the program, when executed, simply passes through the fgets without even prompting the user to input anything:

1
2
3
4
	printf("Please enter your name (50 characters max): ");
	fgets(nme, sizeof(nme), stdin);
	sscanf(nme, "%[^\n]", str);
	printf("%d", str);


"If you want to use that condition on line 17, then set name[0] to newline character."

The do-while loop will perform the code inside the do-while block once and then test for the condition, right? So, it will stop looping the dw block once a user input is made.
Last edited on
What you need is a good ide or a nice text editor. I just pulled up netbeans and tried this code and it worked for me. Your turbo c thingy is experiencing code withdrawal, so best you move on to another ide
May I ask which compiler/IDE you're using? I heard bad things about Dev C++ and some functions (like clrscr()) are not working with Visual C++
I don't use ide's mostly text editors, but I have to say go for good ol' eclipse. People say it doesn't work for them, but the times I have used it, it seems to work very well. Netbeans is also another good one but you will have to download the c/c++ plugin which is something you can easily do from withiin the IDE itself. There are other good ones and some even os specific. Even typing it on google will give you sites which have already done the comparison for you, so you gotta pick the one you like best.

http://www.cplusplus.com/forum/windows/2573/
http://www.cplusplus.com/forum/beginner/78825/
http://www.cplusplus.com/forum/general/25033/
http://www.cplusplus.com/forum/general/72649/

You are not alone
Thanks, I'm using Code::Blocks + MingGW right now. And I was able to fix the fgets() problem. Seems like the only problem was that I didn't flush the stream before using the fgets():

1
2
3
4
5
6
7
8
9
10
11
	nme[0] = '\n';
	do {
		printf("Please enter your name (50 characters max): ");
		fflush(stdin);
		fgets(nme, sizeof(nme), stdin);
		
		len = strlen(nme);
		if(nme[len-1] == '\n') {
			nme[len-1] = '\0';
		}
	} while(nme[0] == '\n');
Topic archived. No new replies allowed.