views:

508

answers:

3

For a project I'm trying to read an int and a string from a string. The only problem is sscanf appears to break reading an %s when it sees a space. Is there anyway to get around this limitation? Here's an example of what I'm trying to do:

#include<stdio.h>
#include<stdlib.h>

int main(int argc, char** argv) {
    int age;
    char* buffer;
    buffer = malloc(200 * sizeof(char));
    sscanf("19 cool kid", "%d %s", &age, buffer);

    printf("%s is %d years old\n", buffer, age);
    return 0;
}

What it prints is: "cool is 19 years old" where I need "cool kid is 19 years old". Does anyone know how to fix this?

+2  A: 

The following line will start reading a number (%d) followed by anything different from tabs or newlines (%[^\t\n]).

sscanf("19 cool kid", "%d %[^\t\n]", &age, buffer);
BrunoLM
Thanks. Also for some reason %d stopped working so I used %[0-9]. Thanks again.
SDLFunTimes
But.. but this is disastrously incorrect! `%[0-9]` specifier (and similar ones) can only be used to read strings. And you are reading an `int` (`age`) with it. This cannot work and will not work.
AndreyT
If you want to read an `int`, you need `%d` (or maybe `%i` or anything int-compatible). But not `%[]`.
AndreyT
Interesting how "will not work" things work. My answer was using `%d` and I changed because of the OP's comment.
BrunoLM
@BrunoLM: You mean that you read an `int` variable with an `%[0-9]` format and then print it as in OP's code and it "works"? Sorry, I have hard time believing that :) No, it doesn't work. I can imagine that you can squeeze a 3-char (or less) string into a 4-byte `int`, but once you print that `int` you'll get garbage. Of course, saying that this accidental hack "works" is an insult to the word "work" :)
AndreyT
+1  A: 

You want the %c conversion specifier, which just reads a sequence of characters without special handling for whitespace.

Note that you need to fill the buffer with zeroes first, because the %c specifier doesn't write a nul-terminator. You also need to specify the number of characters to read (otherwise it defaults to only 1):

memset(buffer, 0, 200);
sscanf("19 cool kid", "%d %199c", &age, buffer);
caf
Well, that's not going to work for my cousin, who is suspiciously named "George Fortescue Aloicious Broomhilda Doreen Beelzebub ... Johanssen MacGregor" :-)
paxdiablo
Indeed - your cousin should complain to the OP for only allocating a buffer of 200 bytes ;)
caf
Good point and, since you've caught the buffer overflow problem with mine and Bruno's answers, +1. Come, join us :-)
paxdiablo
+2  A: 

If you want to scan to the end of the string (stripping out a newline if there), just use:

char *x = "19 cool kid";
sscanf (x, "%d %[^\n]", &age, buffer);

That's because %s only matches non-whitespace characters and will stop on the first whitespace it finds. The %[^\n] format specifier will match every character that's not (because of ^) in the selection given (which is a newline). In other words, it will match any other character.


Keep in mind that you should have allocated enough space in your buffer to take the string since you cannot be sure how much will be read (a good reason to stay away from scanf/fscanf unless you use specific field widths).

You could do that with:

char *x = "19 cool kid";
char *buffer = malloc (strlen (x) + 1);
sscanf (x, "%d %[^\n]", &age, buffer);

(you don't need * sizeof(char) since that's always 1 by definition).

paxdiablo
So over here, your cousin causes a crash instead of suffering the indignity of having his name truncated? Also, my cousin, who is even more suspiciously named (with the 3rd character of his second name being a newline) is unhappy.
caf
@caf ummm what?
SDLFunTimes
The comment needs to be read in the context of the comments to my answer.
caf