1

I have some functions like push, pop, delete etc. for a singly linked list and implemented the following function to get user input:

void user_input(){
char input[10];
while(fgets(input, 9, stdin)){
    if(strncmp(input, "add", 3) == 0){
        int x;
        printf("Number to add: ");
        scanf("%d", &x);
        push(x);
        printf("%d added.\n", x);
    }
    else if(strncmp(input, "del", 3) == 0){
        int x;
        printf("Number to delete: ");
        scanf("%d", &x);
        delete(x);
        printf("%d deleted.\n", x);
    }
    else if(strncmp(input, "q", 1) == 0){
        printf("Program terminated.\n");
        break;
    }
    // and some other if else statements...
}

So I can input a string like "add", then strncmp will compare it and I get another prompt asking me to enter the number I want to add and stores in x using scanf. Something like this:

add
Number to add: 5
5 added.

However I am looking for a way to be able to enter something like this:

add 5
del 2
etc.

Basically a string and int value in one line separated by space, instead of writing "add" first, pressing enter and writing the number. I tried using sscanf but had no luck yet.

NightWish
  • 51
  • 2
  • 9
  • Possible duplicate of [How to read numbers separated by space using scanf](https://stackoverflow.com/questions/10425953/how-to-read-numbers-separated-by-space-using-scanf) – Bo Persson Mar 15 '18 at 18:31
  • What I normally do is (1) read whole lines using `fgets` or the equivalent, (2) break up the line into whitespace-separated "words". (3) use `strcmp` or the equivalent on the first word to decide what to do, and (4) use `atoi` or the equivalent on words that I want to treat as numbers. Obviously (2) is the slightly tricky part. Library functions like `strtok` can help, but you still have to do some work. I find it useful to write one function that does all the work. See [here](http://www.eskimo.com/~scs/cclass/notes/sx10h.html) for details. – Steve Summit Mar 15 '18 at 18:39
  • Thanks for the tips @SteveSummit I figured it out exactly as you suggested with help of the answer posted. :) – NightWish Mar 15 '18 at 23:48

3 Answers3

2

You could use scanf() like

char str[10];
int c;
if( scanf("%9s %d", str, &c)!=2 )
{
    perror("Something went wrong.");
}

The width for %s is one less than the size of str. The extra character is for the \0.

scanf() returns the number of successful assignments that it made which in this case should be 2.

Now if you enter an input like

del 2

str will have "del" and c will have 2.

J...S
  • 5,079
  • 1
  • 20
  • 35
  • Thanks I did already, but couldn't get it to work with a while loop, but I finally did it with sscanf :) – NightWish Mar 15 '18 at 23:50
2

It is much easier to step past input errors if you use fgets and then sscanf. You simply read another input string instead of messing around unblocking the input when invalid data was entered.

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

void push(int x) {
}

void delete(int x) {
}

void triple(int x, int y, int z) {
}

int main(void) 
{
    char input[100];
    char oper[20];
    int x, y, z;        // romantic expansion for more than one argument
    int res;
    int err;

    while(1) {
        err = 0;
        if(fgets(input, sizeof input, stdin) != NULL) {
            res = sscanf(input, "%19s%d%d%d", oper, &x, &y, &z);

            if(res == 2 && strcmp(oper, "add") == 0){
                push(x);
                printf("%d added.\n", x);
            }
            else if(res == 2 && strcmp(oper, "del") == 0) {
                delete(x);
                printf("%d deleted.\n", x);
            }
            else if(res == 4 && strcmp(oper, "trip") == 0) {  // fantasy
                    triple(x, y, z);
                printf("%d %d %d tripled.\n", x, y, z);
            }
            else if(res == 1 && strcmp(oper, "q") == 0){
                printf("Program terminated.\n");
                break;
            }
            // some other if else statements...

            else {
                err = 1;
            }
        }

        else {
            err = 1;
        }

        if(err) {
            printf("Bad operation.\n");
        }
    }
    return 0;
}
Weather Vane
  • 33,872
  • 7
  • 36
  • 56
1

A good strategy for what are trying to do would be:

  1. Read the input line by line.
  2. Process each line.
  3. Continue until there is no input or the user chose to quit.

Here's the core outline.

// Make LINE_SIZE big enough for your needs
#define LINE_SIZE 100

void processLine(char line[]);    

int main()
{
   char line[LINE_SIZE];
   while ( fgets(line, LINE_SIZE, stdin) != NULL )
   {
      processLine(line);
   }
}


void processLine(char line[])
{
}

In processLine, your first job is to pull the command. Do the needful based on the command.

void processLine(char line[])
{
    char command[20];
    int num = 0;

    // Read the command and gather the number of characters read
    // This allows you to read more data from (line + num)
    int n = sscanf(line, "%19s%n", command, &num);
    if ( n != 2 )
    {
       // Problem
       exit(0);
    }

    // The command is to quit, exit.
    if ( isQuitCommand(command) )
    {
       exit(0);
    }

    char* commandData = line + num;
    if ( isAddCommand(command) )
    {
       processAdd(commandData);
    }
    else if ( isDeleteCommand(command) )
    {
       processDelete(commandData);
    }
    else { ... }
}

Here's a version of the program with stubs used for couple of functions.

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

// Make LINE_SIZE big enough for your needs
#define LINE_SIZE 100

void processLine(char line[]);    

int isQuitCommand(char command[]);

int isAddCommand(char command[]);

int isDeleteCommand(char command[]);

void processAdd(char commandData[]);

void processDelete(char commandData[]);


int main()
{
   char line[LINE_SIZE];
   while ( fgets(line, LINE_SIZE, stdin) != NULL )
   {
      processLine(line);
   }
}


void processLine(char line[])
{
   char command[20];
   int num = 0;

   // Read the command and gather the number of characters read
   // This allows you to read more data from (line + num)
   int n = sscanf(line, "%19s%n", command, &num);
   if ( n != 2 )
   {
      // Problem
      exit(0);
   }

   // The command is to quit, exit.
   if ( isQuitCommand(command) )
   {
      exit(0);
   }

   char* commandData = line + num;
   if ( isAddCommand(command) )
   {
      processAdd(commandData);
   }
   else if ( isDeleteCommand(command) )
   {
      processDelete(commandData);
   }
   else
   {
      // ...
   }
}

int isQuitCommand(char command[])
{
   return (command[0] == 'q');
}

int isAddCommand(char command[])
{
   return (strcmp(command, "add") == 0);
}

int isDeleteCommand(char command[])
{
   return (strcmp(command, "del") == 0);
}

void processAdd(char commandData[])
{
   // Add code to process commandData
}

void processDelete(char commandData[])
{
   // Add code to process commandData
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Thank you for this detailed answer and useful information. It's a little more than what I have intended to do but the information are very useful and I will keep them in mind for the next time :) – NightWish Mar 15 '18 at 19:19