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!
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, ... ]);
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.
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.
The bug is that `sscanf` (`vsscanf` actually) is very slow on large strings.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With