1

So my shell project has been coming along, but my latest speedbump is introducing user input. I'm trying to tokenize an input string, but after the first token strtok only returns NULL. But if I hard-write the string in the program, everything works flawlessly. How I can I treat the user input so that strtok will tokenize the whole string (instead of the first)?

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

int main ()
{
  char input[100];
  scanf("%s", input); //input entered is "echo 1 2 3 4"
  char *temp=strtok(input, " "); //this is "echo"
  printf("temp1: %s\n", temp);
  temp=strtok(NULL, " "); //this is (null)
  printf("temp2: %s\n", temp); 

}
user1209326
  • 795
  • 3
  • 8
  • 17

2 Answers2

3

The problem is with scanf("%s"...) which stops reading at the first whitespace character and returns the string. In other words, scanf("%s"...) will not read more than one word.

See here under '%s': http://www.cplusplus.com/reference/clibrary/cstdio/scanf/

scanf("%[^\n\r]", string_variable) might be a better idea.

Update: As mentioned by Seth in the comments, "%[^\n\r]" means read all characters until any of the characters after the ^ is encountered.

Agnel Kurian
  • 57,975
  • 43
  • 146
  • 217
  • Thank you! Your fix worked perfectly, but would you mind translating `%[^\n\r]` for me? Does the `^` character mean "until?" – user1209326 Feb 27 '12 at 03:31
  • 1
    @user1209326 it means "not". It gobbles up characters that match the pattern `[^\r\n]`, which matches "not any of the following: carriage return, newline". – Seth Carnegie Feb 27 '12 at 03:32
  • Oh wow. That's pretty clever. I thought K&Rs mygetline() was an elegant little function, but this is so much simpler. Thanks for your help guys – user1209326 Feb 27 '12 at 03:37
  • 1
    Beware buffer overflows when the user types more than 99 characters on the command line. – Jonathan Leffler Feb 27 '12 at 03:58
  • @JonathanLeffler Thanks for the heads up. What's the best practice to avoid buffer overflows in this context? – user1209326 Feb 27 '12 at 04:11
  • @user1209326 for that, you need to use the method I linked to in my answer. It's unfortunately complicated, but it's very solid, and there's no other way to do it without setting a hard limit. If you're ok with setting a hard limit, you can use [`fgets`](http://www.cplusplus.com/reference/clibrary/cstdio/fgets/). – Seth Carnegie Feb 27 '12 at 04:13
  • Alright, I guess I should just bite the bullet then. I'll get on that now. Thanks for your help @SethCarnegie! – user1209326 Feb 27 '12 at 04:25
2

Make sure to read the documentation of the functions you use. The %s format specifier "will read subsequent characters until a whitespace is found (whitespace characters are considered to be blank, newline and tab)". That means input will only hold the string echo.

See this answer for how to properly read a line from a file.

Community
  • 1
  • 1
Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249
  • Ugh. I think the hardest part of this project so far is just basic reading comprehension. Thanks for your help! – user1209326 Feb 27 '12 at 03:28