1

What I want to do is to input two words in C but one word can be omitted sometimes. To be more precise there is exactly one word necessarily and the other number of words may vary. which can be zero ,one , two or three As an example sometimes the input can be

Hello world

while sometimes it can be just

Hello

the reason why i want this to be done is I'm taking inputs in a while loop (I have to take input continuously and process according to them) I have used

"%s %[^\n]%*c"

but it waits until I enter another word. (Because its expecting a another word after space)

I tried googling and all the aspects of scanf but didn't find any solution. Any help appreciated ! Thanks...

J...S
  • 5,079
  • 1
  • 20
  • 35
  • Possible duplicate of [How can I scan strings with spaces in them using scanf()?](https://stackoverflow.com/questions/13726499/how-can-i-scan-strings-with-spaces-in-them-using-scanf) – anoopknr Aug 03 '18 at 06:56
  • What does it mean "sometimes" – 0___________ Aug 03 '18 at 06:57
  • scanf gets a string which may or may not contain any number of spaces, to split it into words you need to parse the string once it has arrived - this is why scanf information on the web isn't helping you. – MandyShaw Aug 03 '18 at 06:58
  • 2
    Why not simply [read the whole line](http://en.cppreference.com/w/c/io/fgets) as a single string? – Some programmer dude Aug 03 '18 at 07:00
  • Why don't you just read your strings and don't omit them in the loop? – Alan Aug 03 '18 at 07:01
  • Do you know that you can stop the input by pressing ctr+d on linux? Or does your program do the right thing when you take the input from a file? – hetepeperfan Aug 03 '18 at 07:19

4 Answers4

3

This is a case where not using scanf() is astonishingly simple:

char line[1024];

while (fgets(line, 1024, stdin)) 
{
    char *word = strtok(line, " \t\n");
    while (word)
    {
        // do something with word
        word = strtok(0, " \t\n"); // <- next word
    }
}

As for scanf() and how/why not to use it, I suggest reading my beginners' guide away from scanf().


Side note: strtok() isn't thread-safe. If this is a concern, there are alternatives like the POSIX strtok_r() or the C11 strtok_s(). Beware Microsoft also has a strtok_s() which is different from the standard C version.

2

scanf() does not seem to be the right tool for your purpose, you should instead read one line at a time with fgets() and process it according to the words that are present.

If you insist on using scanf(), "%s %[^\n]%*c" does not work because the space matches newlines. Assuming array sizes of 20 bytes, you could use "%19[^ \t\n]%*[ \t]%19[^ \t\n]" and check the return value to see how many words have been read on a single line (0, 1, 2 or EOF), but if you expect a variable number of words, fgets() is a much preferred solution.

Here is an example for up to 3 words per line:

int scan_input(void) {
    char word1[20], word2[20], word3[20];
    int n, c;

    for (;;) {
        switch (n = scanf("%19[^ \t\n]%*[ \t]%19[^ \t\n]%*[ \t]%19[^ \t\n]",
                          word1, word2, word3)) {
          case EOF:
            return EOF;
          case 0:
            /* no word on the line, skip the empty line */
            break;
          case 1:
            /* one word on the line */
            printf("1 word: %s\n", word1);
            break;
          case 2:
            /* two word on the line */
            printf("2 words: %s %s\n", word1, word2);
            break;
          case 3:
            /* three word on the line */
            printf("3 words: %s %s\n", word1, word2, word3);
            break;
        }
        /* ignore the rest of the line */
        while ((c = getchar()) != EOF && c != '\n')
            continue;
    }
}

Here is an example using fgets():

int scan_input(void) {
    char buf[256];
    int n, pos, len;

    while (fgets(buf, sizeof buf, stdin)) {
        /* scan the line, skipping whitespace */
        for (n = 1, pos = 0; buf[pos += strspn(buf, " \t\n")] != '\0'; n++) {
            /* compute the word length */
            len = strcspn(buf + pos, " \t\n");
            /* found word at offset `pos` of length `len` bytes */
            printf("word %d: %.*s\n", n, len, buf + pos);
            pos += len;
        }
    }
    return EOF;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • 3
    I tend to think `scanf()` is never the right tool ;) But if someone insists using it, what's **always forbidden** is a conversion to a string without a field width. –  Aug 03 '18 at 07:16
  • 1
    @FelixPalmen: of course... I initially had a remark to this end, but will provide an actual example for illustration – chqrlie Aug 03 '18 at 07:57
2

It is not a problem if you want omit one word sometimes. But i would recommend you not using scanf()use fgets()instead and process your string after you have read it.

Syntax

char chr[MAX];
while(i<10){
     fgets(chr,MAX, stdin);
}

If you want to omit your second word, just check for a whitespace in your string and terminate it on that place/index the String with \0.

J...S
  • 5,079
  • 1
  • 20
  • 35
Alan
  • 589
  • 5
  • 29
0

I agree with the others that scanf() is probably not the right tool here.

Another way could be to use fgets() and strchr() and a pointer as in

char str[100], *ptr;

while( (fgets(str, sizeof(str), stdin))!=NULL ){
    if( (ptr=strchr(str, '\n'))!=NULL )
    {
        *ptr=0;
    }   
    if( (ptr=strchr(str, ' '))!=NULL )
    {
        *ptr=0;
        ptr++;
        if( strchr(ptr, ' ')==NULL )
        {
            printf("\nTwo words: %s, %s", str, ptr);    
        }
        else
        {
            printf("\nMore than two words!");
        }
    }   
    else//only one word
    {
        printf("\nOne word: %s", str);
    }
}

fgets() is used to read in the input into a character array str. fgets() returns NULL on error.

Since fgets() also reads in any trailing \n, we check the string for \n if it's there, it's replaced with a \0 to denote end of string in the

if( (ptr=strchr(str, '\n'))!=NULL )
{
    *ptr=0;
}  

part.

strchr() returns NULL if the searched character is not present in the string.

strchr() is again used to check for a space in str. If none is found, only one word was read and otherwise multiple words were input.

If more than one word is there, the space is replaced with a \0 using the pointer returned by strchr() so that doing a

printf("%s", str);

will now print only the first word and the pointer is incremented so that it now points to the beginning of the second word. This is done in

if( (ptr=strchr(str, ' '))!=NULL )
{
    *ptr=0;
    ptr++;

Now, strchr() is once again used to check for another case in which case more than two words were input. Otherwise only two words were input and the second word is output using

printf("%s", ptr);

You could use a similar approach to read more words.

J...S
  • 5,079
  • 1
  • 20
  • 35