Kredns
Kredns

Reputation: 37221

How do you allow spaces to be entered using scanf?

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

Answers (12)

chux
chux

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

  1. 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.

  2. 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.

  3. If the number of characters available is too many, then those will remain in stdin.

  4. The return value of scanf() should be checked for end-of-file, failure or success.

  5. 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

Vitim.us
Vitim.us

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);

DEMO

Upvotes: 30

Kelly Robins
Kelly Robins

Reputation: 7313

Try

char str[11];
scanf("%10[0-9a-zA-Z ]", str);

Upvotes: 153

paxdiablo
paxdiablo

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

SVA
SVA

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

venkata sandeep
venkata sandeep

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

Always Learning
Always Learning

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

Ed Zavada
Ed Zavada

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

akelec
akelec

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

Anshul garg
Anshul garg

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

getline()

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 freeing the memory.

Upvotes: 7

Christoph
Christoph

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

Related Questions