0

I'm looking for a way to write an input loop that continues to print prompts until the user enters a blank line.

This is what I want to do:

Loop starts, prints prompt > to the command line. User enters a line that ends with '\n', my program does whatever with that line, and then prints > again. This continues until the user enters a blank line (\n), at this point the loop terminates.

4
  • Using recursion is better because it makes the code simpler. However, it also makes the code more unreadable. Commented May 15, 2015 at 1:08
  • 4
    @QuipYowert No it isn't. What if the user enters 100,000 lines? A simple while loop would handle this case easily, while a recursive program could crash because the recursion would be too deep (leading to a stack overflow and a segmentation fault). Commented May 15, 2015 at 1:13
  • 1
    @QuipYowert: why recursion when a simple loop would do just fine? Commented May 15, 2015 at 1:13
  • In that case, I might as well write a Bayesian static analysis program to catch segfaults. (in Haskell) Commented May 15, 2015 at 1:31

2 Answers 2

2

Would something along these lines answer your needs?

int ret;
// Basically, in order, 1 to indicate the file descriptor of the standard output
// ">" as the string you want to print
// 1 as the number of characters you want printed.
write(1, ">", 1);
while ((ret = read(0, buff, SizeBuff)) > 0) {
    buff[ret] = 0;
    if (buff[0] == '\n' && strlen(buff) == 1)
        return (0);
    /*Do your stuff*/
    write(1, ">", 1);
} 
Sign up to request clarification or add additional context in comments.

5 Comments

Could you explain how this works? I thought write() was for files, rather than command line printing.
@PythonNewb Comments are in the code, explains simply the write parameters. If any other questions, just ask.
Why write when there is printf? (In this case, followed by fflush to ensure the prompt appears. Or doesn't write need flushing?)
@Jongware Why write? Because we want one character. Screw it. Why call printf and THEN call flush for one character? Write will write whatever happens. I generally find it more reliable than printf. Except when you are formatting. :-) Oh and also i much prefer using basic calls when possible. Printf inits va-args before even starting to think about what it has to print.
@Jongware Actually... Now that i just wrote that, why in the world would you use printf? O_o
1

A very simple scanf version can also be used:

#include <stdio.h>

#define MAXL 64

int main (void) {

    char str[MAXL] = {0};

    printf ("\n Enter a string ([enter] alone to quit)\n");

    while (printf (" > ") && scanf ("%63[^\n]%*c", str) == 1)
    {
        /* do whatever in your code */
        printf ("   result: %s\n", str);
    }

    return 0;
}

Use/Output

$ ./bin/scanf_enter_quits

 Enter a string ([enter] alone to quit)
 > string
   result: string
 > another
   result: another
 >

Note: MAXL-1 added as maximum width specifier for scanf to prevent write beyond end of array.


getline Example

getline by dynamically allocating the line buffer allows you to accept a line as long as you want to give it. It can be billions of characters (up to the extent of your memory). This is a strength and a weakness. If you need to limit the amount of data you accept, it is up to you to check/validate/etc....

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

int main (void) {

    char *str = NULL;
    size_t n = 0;
    ssize_t nchr = 0;

    printf ("\n Enter a string ([enter] alone to quit)\n");

    while (printf (" > ") && (nchr = getline (&str, &n, stdin)) > 1)
    {
        str[--nchr] = 0;                /* strip newline from input */
        printf ("   (str: %s)\n", str); /* do whatever in your code */
    }

    if (str) free (str);

    return 0;
}

Use/Output

$ ./bin/getline_enter_quits

 Enter a string ([enter] alone to quit)
 > string one as long as you want
   (str: string one as long as you want)
 > string 2 make it 1000 chars.........................................
   (str: string 2 make it 1000 chars.........................................)
 >

scanf Dynamic Allocation

You can also have scanf dynamically allocate the space for you by using the m conversion specifier (older versions of scanf use the a conversion specifier for this purpose). You must also provide a pointer-to-pointer to accept the address in this case. (e.g. scanf ("%m[^\n]%*c", &str) ).

#include #include

int main (void) {

    char *str = NULL;

    printf ("\n Enter a string ([enter] alone to quit)\n");

    while (printf (" > ") && scanf ("%m[^\n]%*c", &str) == 1)
    {
        printf ("   (str: %s)\n", str); /* do whatever in your code */
        if (str) free (str);            /* you must free each loop  */
        str = NULL;
    }

    if (str) free (str);

    return 0;
}

Use/Output

$ ./bin/scanf_dyn_enter_quits

 Enter a string ([enter] alone to quit)
 > some string as long as you want
   (str: some string as long as you want)
 > another string any length .......... ............. .............
   (str: another string any length .......... ............. .............)
 >

7 Comments

Maybe use fgets instead of scanf? Then you wouldn't have to worry about buffer overflows, and you wouldn't have to hardcode the length into the format string.
True, but then I would need to include code to strip the newline from the line buffer. It's a trade-off. I do it with scanf, fgets, and getline. All have there pluses and minuses... scanf is by far the simplest for a one-off prompt situation.
@DavidC.Rankin If I didn't know how long the user-entered string will be, how could I alter your code to account for this? Would I simply malloc str after the user enters their input?
Easy, use getline. You could give it billions of chars (until you run out of memory). I'll add an example.
@PythonNewb I added both a getline example and an example showing dynamic allocation with scanf. You will find competing view as to which one is better. scanf implementations can vary, but within the reasonable past, either should work for you.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.