7

How to scanf() full sentence in C without using fgets() or gets()

I want to scan a command line from the user and based on the first word recognize the command. For example: mkdir

so I need to recognize that the user wants to create a new dir with the name "dir_name".

My code:

int main(){
  char *ch=malloc(sizeof("50");
  while (strcmp(ch,"exit")!=0){
     scanf("%[^\n]",ch);
  } 

when i ran this code after i input the first sentence and press enter it went to infinity loop i don't know why?

verbose
  • 7,827
  • 1
  • 25
  • 40
Dkova
  • 1,087
  • 4
  • 16
  • 28
  • 2
    Why don't you want to use `fgets`? Using it to read a full line then `sscanf` to later parse the line sounds much easier. – simonc Aug 31 '13 at 10:22

4 Answers4

12

Your problem is most likely here:

char *ch=malloc(sizeof("50");

To begin with, you're missing one close parentheses. But assuming that this was a typo in posting the question and not in your actual code, there is a deeper issue.

"50" inside double quotes is a string literal. When sizeof() is applied to the string literal, you're going to get the number of characters in the string, including terminating NUL. So you are only allocating space for three characters in ch.

When you try to scanf() the input, you're writing past the end of your three-character buffer ch. Leave out sizeof() and simply say:

char* ch = malloc (50);

Also, the scan set %[^\n] does not skip leading whitespace. Your first scanf() will stop at the newline, which will remain in the buffer. Subsequent scanf() calls in your while loop will encounter that newline character and dutifully stop, as it's excluded from your scan set. So the loop condition

while (strcmp (ch, "exit"))

will never become true, and you'll get an infinite loop. Consume the newline after the scanf() to avoid this problem:

scanf ("%[^\n]%*c", ch);

The %*c means "read a character and then discard it." So it will read the \n that is left in the buffer, and then not save it anywhere. Your next scanf() will therefore not encounter a \n at the beginning of the buffer, and your program will work as you intend.

verbose
  • 7,827
  • 1
  • 25
  • 40
  • Thanks, it's working now :) this was the problem : "scanf ("%[^\n]%*c", ch);" what is the meaning of the "%*c"? thanks again – Dkova Aug 31 '13 at 10:46
  • Better to use `scanf ("%49[^\n]%*1[\n]", ch);` to limit input and only toss a `'\n'` with a long line. Even that will not read anything if input is `"\n"` as it leaves the `'\n'` in `stdin`. Suggest `fgetc()`. Yet this answer well deals with OP's primary issue. – chux - Reinstate Monica Jan 02 '15 at 22:09
3
#include<stdio.h>
int main()
{
    char  input_string[100];
    scanf("%[^\n]s",&input_string);
    printf("Hello ,world.\n");
    printf("%s",input_string);
    return 0;
}
  • 1
    Hiya, this may well solve the problem... but it'd be good if you could edit your answer and provide a little explanation about how and why it works :) Don't forget - there are heaps of newbies on Stack overflow, and they could learn a thing or two from your expertise - what's obvious to you might not be so to them. – Taryn East Jun 30 '16 at 04:04
1
int main() {
    int MAX_LEN = 100;
    char ch ; 
    char s [MAX_LEN]; 
    char sen [MAX_LEN]; 
    scanf("%c",&ch); 
    scanf("%s \n",&s); 
    scanf("%*[\n] %[^\n]", sen); 
    printf("%c \n",ch); 
    printf("%s \n",s); 
    printf("%s \n",sen); 
    return 0 ; 
    }
Chinedu
  • 11
  • 2
  • With this the new line character have been taken care of. You can still use scanf("\n"); scanf("%[^\n]%*c", sen); This works just fine – Chinedu Sep 30 '22 at 22:34
  • 2
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 05 '22 at 04:40
0

scanf("%[^\n]s",s); this will do you can also use scanf("%[^\n]%*c", s); where s is defined as char s[MAX_LEN] where MAX_LEN is the maximum size of s . Here, [] is the scanset character. ^\n stands for taking input until a newline isn't encountered. Then, with this %*c, it reads the newline character and here, the used * indicates that this newline character is discarded.

Bean
  • 67
  • 7