3

I want this program to first ask user to start or exit which works fine:

#include <stdio.h>

int main()
{
    int ask;
    char ask2;
    char clip[100];
    
    printf("1.start\n2.exit\n");
    scanf("%d", &ask);
    
    while (ask == 1)
    {
        //options
        printf("what you want to do :\nA.Enter on Clipboard\nB.Check or Edit Clipboard\nC.Exit\n");
        printf("enter A/a,B/b,C/c to select option : ");
        scanf("%s", &ask2);
        printf("\n");
    
        if (ask2 == 'A' || ask2 == 'a')
        {
            //option 1
            printf(":");
            scanf("%s", &clip);
        }
    
        //option 2
        else if (ask2 == 'B' || ask2 == 'b')
        {
            printf("Clipboard:->%s", clip);
        }
    
        //exit
        else if (ask2 =='C' || ask2 == 'c' )
        {
            break;
        }
    
        //error handling
        //else if (ask2 != 'A' || ask2 != 'a' || ask2 != 'B' || ask2 != 'b' || ask2 != 'C' || ask2 != 'c')
        //      {
        //          printf("wrong input !");
        //      }
    }
    
        return 0;
}

...but after that when i input take for while loop the loop runs only once but I want it to ask again and again for input unless user types exit but it terminates the loop after one input which i don't want, help. also there were no errors only while loop gets terminated on first run.

8
  • 1
    scanf("%s", &clip); also, it should be scanf("%99s", clip); but it will only read a single word. Note the removed & as well as the length restriction. Commented Jul 25 at 13:16
  • 1
    Or you might want to use scanf(" %99[^\n]", clip);, instead of scanf("%99s", clip);, to be able to read entire sentences (not only single words). Commented Jul 25 at 13:48
  • 1
    Some explanation: most of the format specifiers for scanf automatically filter leading whitespace, but %c and %[] and %n do not. Adding a space in front of the % instructs scanf to filter leading whitespace here too. The reason is those three specifiers allow you to read every character including whitespace, but a way is provided so they behave like %d and %f and %s (etc) where needed. Also see scanf() leaves the newline char in the buffer. Commented Jul 25 at 14:48
  • 2
    The space is there to discard any white space characters left in the standard input (stdin) by the previous input. In your code for instance, the first scanf reads an integer number, so when the user types 1 and presses Enter in the terminal, two characters are added to stdin '1' and '\n' (new line character), so the scanf which expects to read an int will consume the character '1' and convert it into an int, but the character '\n' will be left in stdin, so without the space before %c to discard it, this character would be read by the second scanf which expects to read a character. Commented Jul 25 at 14:48
  • 1
    You have more issues. If scanf("%d", &ask); returns 0, what does ask contain when you first hit while (ask == 1)? Commented Jul 25 at 20:49

3 Answers 3

3

As noted in the good comments, you probably need to get a bit more familiar with the entry of characters as opposed to strings utilizing the "scanf" function. As noted, one would want to utilize the " %c" formatting for entry of a single character, "%s" for a single string, and "%[^\n]%*c" if multiple words are to be entered into a character array (e.g. a string).

With that in mind, following is a refactored version of your code to include the good suggestions noted in the comments.

#include <stdio.h>

int main()
{
    int ask;
    char ask2, c;       /* Added work character variable "c"    */
    char clip[100];

    printf("1.start\n2.exit\n");
    scanf("%d", &ask);

    while (ask == 1)
    {
        //options
        printf("What you want to do :\nA.Enter on Clipboard\nB.Check or Edit Clipboard\nC.Exit\n");
        printf("Enter A/a,B/b,C/c to select option : ");
        scanf(" %c", &ask2);                /* Entry of character per the good comments     */
        printf("\n");

        printf("Selection: %c\n", ask2);    /* Needed this to clear out the buffer          */

        while ((c = getchar()) != '\n' && c != EOF);

        if (ask2 == 'A' || ask2 == 'a')
        {
            //option 1
            printf("Enter your text: ");
            scanf(" %[^\n]%*c", clip);       /* As noted in the comments for multiple words  */
        }

        //option 2
        else if (ask2 == 'B' || ask2 == 'b')
        {
            printf("Clipboard:-> %s\n", clip);
        }

        //exit
        else if (ask2 =='C' || ask2 == 'c' )
        {
            break;
        }

        //error handling
        //else if (ask2 != 'A' || ask2 != 'a' || ask2 != 'B' || ask2 != 'b' || ask2 != 'C' || ask2 != 'c')
        //      {
        //          printf("wrong input !");
        //      }
    }

    return 0;
}

One other thing to note, when I was running the program on my Linux system, the program would not prompt for the entry of data into the clipboard character array due to leftover data in the input buffer. Therefore, that is the reason for adding the statement "while ((c = getchar()) != '\n' && c != EOF);" to make sure the buffer was clear and ready for the entry of a word or words.

With those bits of refactoring, following is sample input and output at the terminal.

craig@Vera:~/C_Programs/Console/Clip/bin/Release$ ./Clip 
1.start
2.exit
1
What you want to do :
A.Enter on Clipboard
B.Check or Edit Clipboard
C.Exit
Enter A/a,B/b,C/c to select option : a

Selection: a
Enter your text: A short sentence
What you want to do :
A.Enter on Clipboard
B.Check or Edit Clipboard
C.Exit
Enter A/a,B/b,C/c to select option : b

Selection: b
Clipboard:-> A short sentence
What you want to do :
A.Enter on Clipboard
B.Check or Edit Clipboard
C.Exit
Enter A/a,B/b,C/c to select option : c

Selection: c

FYI, I did multiple selections of input and printing of the clipboard variable contents.

The main takeaway from this is probably delve into some more tutorials on the input of characters and/or strings.

Sign up to request clarification or add additional context in comments.

7 Comments

The %*c part of scanf(" %[^\n]%*c", clip); doesn't work, it does nothing, the '\n' still remains in stdin after the function finishes reading the text input (I don't really understand why). You would still need to use another input function after this scanf if you want to discard it.
How do you (think you) determine that a newline remains in the input? I'm confident that you are mistaken, but the program presented in this answer would be insensitive to that anyway.
You are right, my mistake, I was thinking of different situation of when a similar scanf is used to clear stdin, as mentioned here: stackoverflow.com/a/30070821/8298811
When reading strings from input you should always limit the number of character to be read, so that it won't try to store more than the char array's length allows when the input is too long: scanf(" %99[^\n]", clip);
char c --> int c.
@isrnick it's still a poor solution attempting to get rid of a (single) trailing newline. The scanf family is geared towards filtering (all) leading whitespace.
... and if you need to "clear stdin" then scanf is the wrong tool for the job. It suits formatted input not unformatted.
1
char ask2;  

and

scanf("%s", &ask2);  

are a problem.
The %s specifier tells scanf to expect a string. In C, strings are zero terminated and scanf will append a zero to the input. ask2 is a single character so when the zero is appended, it corrupts memory adjacent to ask2.

scanf ( " %c", &ask2);  

will correct the problem. The %c specifier tells scanf to expect a single character. The space before %c tells scanf to scan and discard whitespace.

Another issue with %s is it will scan a series of non-whitespace characters, stopping at the next whitespace character. If the input could contain whitespace, then something else is needed.

scanf ( " %99[^\n]", clip);  

could be used. Note the 99 to limit the number characters allowed. The scanset [^\n] tells scanf to accept any characters that are not a newline. The scan will stop at a newline or 99 characters.

fgets is another option. It takes a pointer to an array, the size of the array and the stream to read from.

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

int parseint ( char *line, int *value) {
    char *end = NULL;
    long int number = 0;

    errno = 0;
    *value = 0;
    number = strtol ( line, &end, 10);
    if ( end == line) { // nothing was parsed. no digits
        fprintf ( stderr, "problem parsing an integer\n");
        return 0; // return failure
    }
    if ( 0 != end[strspn ( end, " \f\n\t\v")]) { // if trailing non-whitespace (6y) is ok, remove this block
        fprintf ( stderr, "problem trailing non-digit characters\n");
        return 0;
    } // if trailing non-whitespace (6y) is ok, remove this block
    if ( errno != 0 || number > INT_MAX || number < INT_MIN) { // parsing error from strtol
        fprintf ( stderr, "problem error from strtol\n");
        return 0;
    }
    *value = number; // assign number to pointer

    return 1;//success
}

int main ( void) {
    int ask = 0;
    char ask2[40] = "";
    char clip[100] = "";

    int retry = 0;
    do {
        if ( retry) {
            printf ( "\t\tenter 1 or 2. try again\n");
        }
        printf("1.start\n2.exit\n");
        if ( ! fgets ( ask2, sizeof ask2, stdin)) {
            fprintf ( stderr, "problem getting input\n");
            return 1;
        }
        if ( 0 == ( parseint ( ask2, &ask))) {
            return 1;
        }
        retry = 1;
    } while ( 1 != ask && 2 != ask);

    while (ask == 1) {
        retry = 0;
        do {
            if ( retry) {
                printf ( "\t\tenter one character. try again\n");
            }
            //options
            printf("what you want to do :\nA.Enter on Clipboard\nB.Check or Edit Clipboard\nC.Exit\n");
            printf("enter A/a,B/b,C/c to select option : ");
            if ( ! fgets ( ask2, sizeof ask2, stdin)) {
                fprintf ( stderr, "problem getting input\n");
                return 1;
            }
            retry = 1;
        } while ( '\n' != ask2[1]);
        printf("\n");

        switch ( ask2[0]) {
        case 'A':
        case 'a':
            printf(":");
            if ( ! fgets ( clip, sizeof clip, stdin)) {
                fprintf ( stderr, "problem getting input\n");
                return 1;
            }
            break;
        case 'B':
        case 'b':
            printf("Clipboard:->%s\n", clip);
            break;
        case 'C':
        case 'c':
            ask = 2;
            break;
        default:
            printf ( "wrong input\n");
        }
    }

    return 0;
}  

This uses fgets with two arrays to obtain input. A function uses strtol to parse an integer. strtol has better error checking than scanf using %d.
This also uses a switch to process each option.

Comments

0
  1. Instead of scanf("%s",&ask2) use scanf("%c",&ask2) for reading a single line of character.

2. And also Better to use the else block after the exit for handling the wrong input .

3. scanf(" %[^\n]", clip); use this for reading full line along with spaces also

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.