Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sscanf - get nth word in a sentence

I'm new to C, and I'm trying to scan a line from stdin and extract the nth word from it. Right now I've hard-coded it where you can store the first, second, or third entry in the sentence, and this is what it looks like:

int set_to_nth_word(char* word, char* input, int n)
{
    char word1[20];
    char word2[20];
    char word3[20];
    if(sscanf(input, "%s %s %s", word1, word2, word3) < n)
    {
        printf("You didn't enter enough values\n");
        return 0;
    }
    else
    {
        if(n == 1) strcpy(word, word1);
        else if(n == 2) strcpy(word, word2);
        else if(n == 3) strcpy(word, word3);
        return 1;
    }
}

The code that calls this method is:

char *input = (char *) malloc (1);
if(getline(&input, (size_t)0, stdin) != -1)
{
    char word[20];
    if(set_to_nth_word(word, input, 1))
    {
        printf("Success");
    }
}

Besides finding a solution to this problem, I'd be happy if anyone points out any bad style or bad coding practices!

like image 397
Petwoip Avatar asked Nov 29 '10 03:11

Petwoip


People also ask

What does sscanf mean in C?

The sscanf() Function in C The sscanf() function allows us to read formatted data from a string rather than standard input or keyboard. Its syntax is as follows: Syntax: int sscanf(const char *str, const char * control_string [ arg_1, arg_2, ... ]);

What value does sscanf return?

Return Value The sscanf() function returns the number of fields that were successfully converted and assigned. The return value does not include fields that were read but not assigned. The return value is EOF when the end of the string is encountered before anything is converted.

How do you use %s on a Scanf?

In scanf() you usually pass an array to match a %s specifier, then a pointer to the first element of the array is used in it's place. For other specifiers like %d you need to pass the address of the target variable to allow scanf() to store the result in it.

Is sscanf slow?

The bug is that `sscanf` (`vsscanf` actually) is very slow on large strings.


2 Answers

You can make use of %n conversion specifier supported by sscanf(). It requires an int * parameter, and returns the number of characters consumed from the input into that int.

int set_to_nth_word(char *word, const char *input, int n)
{
    int chars_used;

    word[0] = '\0';    /* In case n < 1 */

    while (n > 0 && sscanf(input, "%s%n", word, &chars_used) > 0)
    {
        input += chars_used;
        n--;
    }

    if (n > 0)
    {
        printf("You didn't enter enough values\n");
        return 0;
    }

    return 1;
}

As far as style goes, you should make the input parameter const char *, since the characters pointed to are not being modified in the function.

In terms of safety, word should be allocated with a length of strlen(input) + 1, rather than declared as a fixed-size array, since the words may be up to that length.

like image 65
caf Avatar answered Oct 04 '22 01:10

caf


Here are a few pieces of advice:

  • instead of scanning a fixed number of words, loop n times scanning a single word

  • use strtok instead of sscanf for this; it will make your life much easier

  • try to avoid compiled-in limits on how long a word can be (20), especially when you're not checking to see if those limits are being exceeded

  • avoid copying string data unnecessarily when scanning it, especially (as stated above) when you're not enforcing length limits on your strcpy calls. Using strtok will locate words within the input with zero copies.

like image 22
David Gelhar Avatar answered Oct 04 '22 02:10

David Gelhar