Search code examples
carraysuser-inputscanfdynamic-memory-allocation

Dynamically allocate user inputted string


I am trying to write a function that does the following things:

  • Start an input loop, printing '> ' each iteration.
  • Take whatever the user enters (unknown length) and read it into a character array, dynamically allocating the size of the array if necessary. The user-entered line will end at a newline character.
  • Add a null byte, '\0', to the end of the character array.
  • Loop terminates when the user enters a blank line: '\n'

This is what I've currently written:

void input_loop(){
    char *str = NULL;

    printf("> ");

    while(printf("> ") && scanf("%a[^\n]%*c",&input) == 1){

        /*Add null byte to the end of str*/

        /*Do stuff to input, including traversing until the null byte is reached*/

        free(str);
        str = NULL;
    }
    free(str);
    str = NULL;
}

Now, I'm not too sure how to go about adding the null byte to the end of the string. I was thinking something like this:

last_index = strlen(str);
str[last_index] = '\0';

But I'm not too sure if that would work though. I can't test if it would work because I'm encountering this error when I try to compile my code:

warning: ISO C does not support the 'a' scanf flag [-Wformat=]

So what can I do to make my code work?

EDIT: changing scanf("%a[^\n]%*c",&input) == 1 to scanf("%as[^\n]%*c",&input) == 1 gives me the same error.


Solution

  • First of all, scanf format strings do not use regular expressions, so I don't think something close to what you want will work. As for the error you get, according to my trusty manual, the %a conversion flag is for floating point numbers, but it only works on C99 (and your compiler is probably configured for C90)

    But then you have a bigger problem. scanf expects that you pass it a previously allocated empty buffer for it to fill in with the read input. It does not malloc the sctring for you so your attempts at initializing str to NULL and the corresponding frees will not work with scanf.

    The simplest thing you can do is to give up on n arbritrary length strings. Create a large buffer and forbid inputs that are longer than that.

    You can then use the fgets function to populate your buffer. To check if it managed to read the full line, check if your string ends with a "\n".

    char str[256+1];
    while(true){
        printf("> ");
        if(!fgets(str, sizeof str, stdin)){
            //error or end of file
            break;
        }
    
        size_t len = strlen(str);
        if(len + 1 == sizeof str){
            //user typed something too long
            exit(1);
        }
    
        printf("user typed %s", str);
    }
    

    Another alternative is you can use a nonstandard library function. For example, in Linux there is the getline function that reads a full line of input using malloc behind the scenes.