Reputation: 37221
Using the following code:
char *name = malloc(sizeof(char) + 256);
printf("What is your name? ");
scanf("%s", name);
printf("Hello %s. Nice to meet you.\n", name);
A user can enter their name but when they enter a name with a space like Lucas Aardvark
, scanf()
just cuts off everything after Lucas
. How do I make scanf()
allow spaces
Upvotes: 183
Views: 484072
Reputation: 154174
How do you allow spaces to be entered using scanf?
fgets()
is the better approach as in this answer, especially if code needs to read a line of input into a string.
char name[80];
if (fgets(name, sizeof name, stdin)) {
// Lop off potential trailing '\n'
name[strcspn(name, "\n"] = '\0';
printf("Hello '%s'. Nice to meet you.\n", name);
}
If scanf()
is obliged, read on
As many scanf()
specifiers leave the prior input's '\n'
in stdin
, that '\n'
likely needs to be read (and tossed) first. Using a " "
reads any number of white-space including a '\n'
, yet is often acceptable if the input desired does not begin with a space.
A specifier width is needed to limit the number of characters saved in the buffer and prevent the undefined behavior (UB) of a buffer overflow. When reading text to form a string, scanf()
appends a null character, so the buffer size is at least 1 more than the specifier's width.
If the number of characters available is too many, then those will remain in stdin
.
The return value of scanf()
should be checked for end-of-file, failure or success.
Input that consists of no characters and then has a '\n'
are a problem too as scanf("%99[^\n]", buffer);
will not read anything and leave buffer[]
unchanged when input begins with a '\n'
.
#include <stdio.h>
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define NAME_LENGTH_MAX 79
int main(void) {
char name[NAME_LENGTH_MAX + 1];
// If desired, consume and toss any 0 or 1 prior '\n'.
scanf("%*1[\n]");
printf("What is your name? ");
// Set name[] to "" to handle the case of only a '\n' is entered.
name[0] = '\0';
// Read up to NAME_LENGTH_MAX characters or a '\n' or end-of-file.
int count = scanf("%" TOSTRING(NAME_LENGTH_MAX) "[^\n]", name);
// `count` is expected to be EOF, 0 or 1
if (count == EOF) {
printf("End-of-file or rare input error.\n");
} else {
printf("Hello '%s'. Nice to meet you.\n", name);
}
// If desired, consume and toss any 0 or 1 trailing '\n'.
scanf("%*1[\n]");
}
Advanced: additional code needed to consume excess input and with displaying name[]
when a null character was read.
Standard C lacks a really good read_a_line_to_a_string()
function.
Upvotes: 1
Reputation: 22198
You can use this
char name[20];
scanf("%19[^\n]", name);
Or this
void getText(char *message, char *variable, int size){
printf("\n %s: ", message);
fgets(variable, sizeof(char) * size, stdin);
sscanf(variable, "%[^\n]", variable);
}
char name[20];
getText("Your name", name, 20);
Upvotes: 30
Reputation: 882316
People (and especially beginners) should never use scanf("%s")
or gets()
or any other functions that do not have buffer overflow protection, unless you know for certain that the input will always be of a specific format (and perhaps not even then).
Remember than scanf
stands for "scan formatted" and there's precious little less formatted than user-entered data. It's ideal if you have total control of the input data format but generally unsuitable for user input.
Use fgets()
(which has buffer overflow protection) to get your input into a string and sscanf()
to evaluate it. Since you just want what the user entered without parsing, you don't really need sscanf()
in this case anyway:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Maximum name size + 1. */
#define MAX_NAME_SZ 256
int main(int argC, char *argV[]) {
/* Allocate memory and check if okay. */
char *name = malloc(MAX_NAME_SZ);
if (name == NULL) {
printf("No memory\n");
return 1;
}
/* Ask user for name. */
printf("What is your name? ");
/* Get the name, with size limit. */
fgets(name, MAX_NAME_SZ, stdin);
/* Remove trailing newline, if there. */
if ((strlen(name) > 0) && (name[strlen (name) - 1] == '\n'))
name[strlen (name) - 1] = '\0';
/* Say hello. */
printf("Hello %s. Nice to meet you.\n", name);
/* Free memory and exit. */
free (name);
return 0;
}
Upvotes: 248
Reputation: 883
This example uses an inverted scanset, so scanf keeps taking in values until it encounters a '\n'-- newline, so spaces get saved as well
#include <stdio.h>
int main (int argc, char const *argv[])
{
char name[20];
// get up to buffer size - 1 characters (to account for NULL terminator)
scanf("%19[^\n]", name);
printf("%s\n", name);
return 0;
}
Upvotes: 69
Reputation: 13
/*reading string which contains spaces*/
#include<stdio.h>
int main()
{
char *c,*p;
scanf("%[^\n]s",c);
p=c; /*since after reading then pointer points to another
location iam using a second pointer to store the base
address*/
printf("%s",p);
return 0;
}
Upvotes: -3
Reputation: 83
If someone is still looking, here's what worked for me - to read an arbitrary length of string including spaces.
Thanks to many posters on the web for sharing this simple & elegant solution. If it works the credit goes to them but any errors are mine.
char *name;
scanf ("%m[^\n]s",&name);
printf ("%s\n",name);
Upvotes: 5
Reputation: 53
While you really shouldn't use scanf()
for this sort of thing, because there are much better calls such as gets()
or getline()
, it can be done:
#include <stdio.h>
char* scan_line(char* buffer, int buffer_size);
char* scan_line(char* buffer, int buffer_size) {
char* p = buffer;
int count = 0;
do {
char c;
scanf("%c", &c); // scan a single character
// break on end of line, string terminating NUL, or end of file
if (c == '\r' || c == '\n' || c == 0 || c == EOF) {
*p = 0;
break;
}
*p++ = c; // add the valid character into the buffer
} while (count < buffer_size - 1); // don't overrun the buffer
// ensure the string is null terminated
buffer[buffer_size - 1] = 0;
return buffer;
}
#define MAX_SCAN_LENGTH 1024
int main()
{
char s[MAX_SCAN_LENGTH];
printf("Enter a string: ");
scan_line(s, MAX_SCAN_LENGTH);
printf("got: \"%s\"\n\n", s);
return 0;
}
Upvotes: -1
Reputation: 4013
You may use scanf
for this purpose with a little trick. Actually, you should allow user input until user hits Enter (\n
). This will consider every character, including space. Here is example:
int main()
{
char string[100], c;
int i;
printf("Enter the string: ");
scanf("%s", string);
i = strlen(string); // length of user input till first space
do
{
scanf("%c", &c);
string[i++] = c; // reading characters after first space (including it)
} while (c != '\n'); // until user hits Enter
string[i - 1] = 0; // string terminating
return 0;
}
How this works? When user inputs characters from standard input, they will be stored in string variable until first blank space. After that, rest of entry will remain in input stream, and wait for next scanf. Next, we have a for
loop that takes char by char from input stream (till \n
) and apends them to end of string variable, thus forming a complete string same as user input from keyboard.
Hope this will help someone!
Upvotes: 0
Reputation: 233
You can use the fgets()
function to read a string or use scanf("%[^\n]s",name);
so string reading will terminate upon encountering a newline character.
Upvotes: 6
Reputation: 101259
Now part of POSIX, none-the-less.
It also takes care of the buffer allocation problem that you asked about earlier, though you have to take care of free
ing the memory.
Upvotes: 7
Reputation: 169723
Don't use scanf()
to read strings without specifying a field width. You should also check the return values for errors:
#include <stdio.h>
#define NAME_MAX 80
#define NAME_MAX_S "80"
int main(void)
{
static char name[NAME_MAX + 1]; // + 1 because of null
if(scanf("%" NAME_MAX_S "[^\n]", name) != 1)
{
fputs("io error or premature end of line\n", stderr);
return 1;
}
printf("Hello %s. Nice to meet you.\n", name);
}
Alternatively, use fgets()
:
#include <stdio.h>
#define NAME_MAX 80
int main(void)
{
static char name[NAME_MAX + 2]; // + 2 because of newline and null
if(!fgets(name, sizeof(name), stdin))
{
fputs("io error\n", stderr);
return 1;
}
// don't print newline
printf("Hello %.*s. Nice to meet you.\n", strlen(name) - 1, name);
}
Upvotes: 10