views:

2286

answers:

6

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

+12  A: 

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

Hope that helps.

Edited because I forgot what language we are using.

apocalypse9
I didn't even know `scanf()` accepted regex's! Thanks!!!!!
Lucas McCoy
note, it doesn't do general regexes, just character classes
rampion
@rampion: Excellent side note (but still that's pretty cool).
Lucas McCoy
(1) Obviously to accept spaces, you need to put a space in the character class. (2) Note that the 10 is the maximum number of characters which will be read, so str has to point to a buffer of size 11 at least. (3) The final s here isn't a format directive but scanf will try here to match it exactly. The effect will be visible on an entry like 1234567890s where the s will be consumed but put no where. An other letter won't be consumed. If you put another format after the s, it will be read only if there is an s to be matched.
AProgrammer
Another potential problem, the use of - at other place than the first or the last is implementation defined. Usually, it is used for ranges, but what the range designate is dependent on the charset. EBCDIC has holes in the letter ranges and even when assuming an ASCII derived charsets it is naïve to think that all lower case letters are in the a-z range...
AProgrammer
I'd go with `"%[^\n]"` as format string
Christoph
"%[^\n]" has the same problem as gets(), buffer overflow. With the additional catch that the \n final isn't read; this will be hidden by that fact that most formats start by skipping white spaces, but [ isn't one of them. I don't understand the instance at using scanf to read strings.
AProgrammer
+11  A: 

People (and especially beginners) should never use scanf() or gets() or any of those functions that do not have buffer overflow protection.

Just 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() to get your input into a string and sscanf() to evaluate it. Since you just want what the user entered, 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 (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;
}
paxdiablo
I didn't know about `fgets()`. It actually looks easier to use then `scanf()`. +1
Lucas McCoy
If you just want to get a line from the user, it is easier. It's also safer since you can avoid buffer overflows. The scanf family is really useful for turning a string into different things (like four chars and an int for example with "%c%c%c%c%d") but, even then, you should be using fgets and sscanf, not scanf, to avoid the possibility of buffer overflow.
paxdiablo
You can put maximum buffer size in scanf format, you just can't put runtime computed one without building the format at runtime (there isn't the equivalent of * for printf, * is a valid modificator for scanf with another behavior: suppressing assignation).
AProgrammer
+2  A: 

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);
}
Christoph
+1  A: 

getline()

Now in the standard library, 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.

dmckee
Standard? In the reference you cite: "Both getline() and getdelim() are GNU extensions."
AProgrammer
POSIX 2008 adds getline. So GNU wen ahead and changed their headers for glibc around version 2.9, and it is causing trouble for many projects. Not a definitive link, but look here: https://bugzilla.redhat.com/show_bug.cgi?id=493941 . As for the on-line man page, I grabbed the first one google found.
dmckee
A: 

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];
    scanf("%[^\n]s",name);
    printf("%s\n", name);
    return 0;
}
SVA
A: 

Refer Accepting Paragraph using Scanf : Click Here

c4learn.com