1

Working on a C knapsack program that will have a UI like interface, I have come to a point where I need for the user to be able to enter in characters for commands and while all of the ones which require only a simple one character input are quite simple I need to be able to allow the user to enter in a char and an int at the same time in the cases of adding or removing a number from the knapsack. While I know this can be done with two separate inputs from the user I'm wondering how can this be done in the same line without requiring the user to enter in two separate inputs. For example if the user types a 7 then it will add 7 to the knapsack.

CODE

#include <stdio.h>
#include "knapsack.c"
#include <stdlib.h>
#include <string.h>

int main()
{
    listitemptr k2 = NULL;
    char input[100];
    int *returnval;
    while(*input != 'q'){
        printf("> ");
        fgets(input, 100, stdin);

        if(*input == 'p'){
            KnapsackPrint(&k2);
        }
        else if(*input == 'a'){
            printf("test\n");
            sscanf(input, "%d", returnval);
            printf("%d\n", *returnval);

        }
        else if(*input == 'r'){

        }
        else if(*input == 'l'){

        }
        else if(*input == 's'){

        }
    }




}
Bret Hasel
  • 303
  • 1
  • 11
  • Read a char; if it's a command that takes a number, read that. Possibly read an entire line at once and parse that; makes error handling easier. – Shawn Mar 09 '19 at 08:18
  • how would i go about dynamically reading in that char though for an if statement for example? I cant exactly do like *input == 'a %d' – Bret Hasel Mar 09 '19 at 08:19
  • Use `fgets` to read a line, then analyse the line. `scanf` is not suitable for all situations. – Paul Ogilvie Mar 09 '19 at 08:26
  • 1
    `int c; if ((c = getchar()) != EOF) { if (c == 'a') { int d; if (scanf("%d", &d) == 1) { /* do stuff */ } else { /* error reading d */ } } else { /* c is something else */ } } else { /* error reading c */ }` or whatever. – Shawn Mar 09 '19 at 08:28
  • You can also use `%d` to read input - if it doesn't match, use `" %c"` to scan a single character – Antti Haapala -- Слава Україні Mar 09 '19 at 08:33
  • new to fgets, can you show me an example of how to scan in only the next int with sscanf? – Bret Hasel Mar 09 '19 at 08:33
  • Updated my code but getting a segmentation fault that i dont quite understand why. Can you tell me why this may be? – Bret Hasel Mar 09 '19 at 08:41

1 Answers1

1

There are many solutions for your user input proble. I would suggest you read one line at a time with fgets() and parse it with sscanf():

#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "knapsack.c"

int main() {
    char input[100];
    listitemptr k2 = NULL;
    int i, returnval = 0;
    char command;

    for (;;) {
        printf("> ");
        if (!fgets(input, sizeof input, stdin))
            break;
        i = strspn(input, " \t\n");  /* skip blanks */
        command = input[i++];
        if (command == '#' || command == '\0') {
            /* ignore comment lines and blank lines */
            continue;
        }
        if (command == 'q' && input[i] == '\n')
            break;
        }
        if (command == 'p') {
            KnapsackPrint(&k2);
            continue;
        }
        if (command == 'a') {
            int item;
            if (sscanf(input + i, "%i", &item) != 1) {
                printf("invalid input\n");
                continue;
            }
            KnapsackAdd(&k2, item);
            continue;
        }
        // add more commands     
        printf("unknown command: %c\n", command);
    }
    return returnval;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • How could this be reworked so that if the command `quit` was entered that it wouldnt terminate the program? – Bret Hasel Mar 09 '19 at 09:21
  • @BretHasel: you can change the program to perform other tasks after the `for(;;)` loop or you can change the `break` statement and write appropriate code there... – chqrlie Mar 09 '19 at 09:24
  • oh no allow me to rephrase, i dont mean after q is entered i specifically mean after QUIT is entered. So that q is taken as a quitting statement but the PHRASE quit is not. – Bret Hasel Mar 09 '19 at 09:26
  • or any word starting with the desired letters – Bret Hasel Mar 09 '19 at 09:30
  • @BretHasel: if you want word commands, you should test for words instead of single letters. For this you can get the length of the word with `strcspn(input + i, " \t\n")` and compare with the command names with `memcmp()`. Alternately you could use `strtok()` or `strtok_r()`. – chqrlie Mar 09 '19 at 09:34
  • i want to exclude words is what i mean. So for example right now saying `quit` cancels the program just as `q` does but i ONLY want `q` to quit the program and `quit` to be seen as an invalid input – Bret Hasel Mar 09 '19 at 09:38
  • @BretHasel: then you want to check what follows `q` on the input line. Answer amended. – chqrlie Mar 09 '19 at 09:41
  • ohhh okay thank you! always seems its something simple im over thinking. – Bret Hasel Mar 09 '19 at 09:50
  • Didnt realize i unticked it sorry. May i ask one last final question though? If i want to print out the invalid input for add in quotations i know how to do so but when just printing out input + i it prints out the space before it and the new line character between it and the last `"` how could i do that? – Bret Hasel Mar 09 '19 at 10:03