1

I have the following line in my code:

char y[] = "a";
scanf("Letter: %s", y);
printf("%s\n", y);

The second line does not impact the output of the third line at all. I've included <stdio.h>, I can't think of what is wrong...

paddy
  • 60,864
  • 6
  • 61
  • 103
user2407894
  • 427
  • 1
  • 4
  • 10
  • 3
    Would you normally expect `scanf` to print something? – Ed S. Jun 19 '13 at 03:54
  • 1
    Sure, but you wouldn't use a function without having some idea of what it does, right? – Ed S. Jun 19 '13 at 04:15
  • Since you don't test the return value from `scanf()`, you've got no idea whether it succeeded or not. If it didn't succeed, you don't have anything reliable in `y`. You've also only allocated enough space for a single-character string. As long as that's what you intend, it is fine, but you would be well advised to specify the maximum length with `%1s`, especially when the length is only 1. – Jonathan Leffler Jun 19 '13 at 04:54
  • 1
    Exactly the same issue as [C Scanf suddenly stopped reading in values](http://stackoverflow.com/questions/16994747/c-scanf-suddenly-stopped-reading-in-values) – AnT stands with Russia Jun 19 '13 at 04:58
  • 1
    check my answer, you will get what u want... – Mayank Tiwari Jun 19 '13 at 05:16

4 Answers4

9

One of the biggest mistakes one does, is to include any string in the scanf function between the quotes other than format specification(like %s or %d).The code should be scanf("%s",y).If you take any other character then you will have to scratch your head looking to find out problems.

(Even if you include any character then you have to input that character,e.g- if you write scanf("letter: %s",y); then on input you have to write like C:\>letter: "letter which you will enter") which is obviously not a wise idea .Also the scanf function is not there to print things out, its just to read input from the terminal.To print out you should use printf("letter"); that's it.

Just suppose you have to take inputs from two int variables using one scanf() then you will use like scanf("%d%d",&a,&b); as you can see i have put nothing except format specification in the quotes.

0decimal0
  • 3,884
  • 2
  • 24
  • 39
  • 3
    It is not necessarily a mistake to include spaces or other characters in a `scanf()` format string. Sometimes it is necessary. It is always necessary to understand what it means, and the role of white space in particular (especially trailing white space) is not obvious. But it is incorrect to say that you should never include any other characters than conversion specifications in format strings. In the case of `"%d%d"`, there is no need for spaces in the format string, but there is no harm in either or both of the spaces in `" %d %d"`, though a trailing space is almost always inappropriate. – Jonathan Leffler Jun 19 '13 at 05:46
  • @jonathan yeah its not necessarily a mistake but are you sure that it works in all situation, i mean on all the machines.The input (on the prompt)should be the same as inside scanf() and in the case of whitespace its not important.Obviously its not a wise idea to include anything in the scanf() and then writing it on the input prompt accordingly.Anyway i have considered your opinion and included in the answer.thanks!! – 0decimal0 Jun 19 '13 at 11:09
  • 1
    and to understand what it means one can add lines in printf(), and it definitely lets you avoid inputting as you would have to after adding lines in scanf(), i didn't mean "never" as you interpreted.i meant, its a "mistake" not an "error". – 0decimal0 Jun 19 '13 at 11:38
  • 3
    The `scanf()` family of functions are some of the most complex in Standard C; they are extremely hard to understand. It is difficult to teach the correct use of the functions. You'll find me on record in SO stating that it is frequently better to use `fgets()` and `sscanf()` rather than plain `scanf()`; it usually gives better control, especially for retries and error reporting. You are correct that `scanf()` does not emit a prompt, which is clearly what the OP thinks will happen. – Jonathan Leffler Jun 19 '13 at 11:54
  • This would be fine as long as they put "Letter: " before whatever was entered which will work but was probably not the desired effect – Mitch Sep 11 '17 at 01:20
3

I assume you wanted a prompt, not a format string:

printf("Letter: ");
fflush(stdout);
scanf("%s", y);

Just beware that your string will only hold one character. If you enter a longer string, you will have a buffer overrun.

You should also get in the habit of testing the return value of scanf. It returns the number of items successfully read. So, in your example, if it reads a string it should return 1. Because you didn't test it, you spent ages trying to work out what's wrong, when in fact it would have been telling you that no items were read.

paddy
  • 60,864
  • 6
  • 61
  • 103
  • is it because I didn't do fflush? – user2407894 Jun 19 '13 at 03:53
  • 1
    No, it's because `scanf` was looking for an input that looks like `Letter: ` followed by more characters which it would then put into your array `y`. – paddy Jun 19 '13 at 03:56
  • 1
    By the way, you should read this: http://stackoverflow.com/questions/4023895/how-to-read-string-entered-by-user-in-c/4023921#4023921 – paddy Jun 19 '13 at 03:59
2

Other answers have correctly diagnosed that scanf() does not output any data (and, in particular, does not generate any prompt), whereas the question seems to expect that scanf("Letter: %s", y) will output a prompt Letter: and then read a response. There are also problems such as not checking the return value from scanf() and a buffer overflow if more than one character is typed.

One of the answers suggested that characters other than conversion specifications should not be present in the format string. This answer is primarily a counter-example showing how other characters can be crucial. You can take this example code and make modifications to it to improve your understanding of how the scanf() family of functions works. Note that it is not an interactive program; it is converting data using sscanf(), almost as if the data had been read by fgets(). Exercise: why is it only 'almost as if' and not simply 'as if'?

Context

Consider that you are dealing with a file formatted with lines such as:

centre (23, 41) size (19, 42)

Assuming you want to read the four numbers, your format string is likely to be a variant of:

"centre (%d,%d) size (%d,%d)"

This is nearly sound. However, there is no way with that format to spot that the second close parenthesis is missing. To be sure that the final parenthesis is present, you'd need a format string like:

"centre (%d ,%d ) size (%d ,%d %1[)]"

where the spaces allow for many variations in the spacing of the input, and the scan set (%1[)]) requires a close parenthesis. You would test that the scanf() returned 5 fields. Note that if you suppressed the assignment with the scan set (%*1[)]), you would not get an error indication if the parenthesis is missing. It is a judgement call as to how flexible you want to be in what you accept as valid input.

Code

#include <stdio.h>

int main(void)
{
    int x1, y1, x2, y2;
    char str[10];
    const char *data[] =
    {
        "centre ( 19, 43 ) size ( 21, 37 )",
        "centre (19, 43) size (21, 37)",
        "centre (19, 43) size (21, 37",
        "centre(19,43) size(21,37)",
        "centre(19,43) size(21,37",
        "centre ( 19 , 43 ) size ( 21 , 37 )",
    };
    enum { NUM_DATA = sizeof(data) / sizeof(data[0]) };

    const char *format5[] =
    {
        "centre (%d ,%d ) size (%d ,%d %[)]",
        "centre (%d,%d) size (%d,%d%[)]",
    };
    enum { NUM_FORMAT5 = sizeof(format5) / sizeof(format5[0]) };

    const char *format4[] =
    {
        "centre (%d ,%d ) size (%d ,%d )",
        "centre (%d,%d) size (%d,%d)",
    };
    enum { NUM_FORMAT4 = sizeof(format4) / sizeof(format4[0]) };

    printf("Format 5\n");
    for (int i = 0; i < NUM_FORMAT5; i++)
    {
        printf("Format:    <<%s>>\n", format5[i]);
        for (int j = 0; j < NUM_DATA; j++)
        {
            int rc;
            printf("   Data:   <<%s>>\n", data[j]);
            if ((rc = sscanf(data[j], format5[i], &x1, &y1, &x2, &y2, str)) != 5)
                printf("!! Failed: scanf() returned %d\n", rc);
            else
                printf("== Passed: centre(%d,%d) size(%d,%d)\n", x1, y1, x2, y2);
        }
    }

    printf("\nFormat 4\n");
    for (int i = 0; i < NUM_FORMAT4; i++)
    {
        printf("Format:    <<%s>>\n", format4[i]);
        for (int j = 0; j < NUM_DATA; j++)
        {
            int rc;
            printf("   Data:   <<%s>>\n", data[j]);
            if ((rc = sscanf(data[j], format4[i], &x1, &y1, &x2, &y2)) != 4)
                printf("!! Failed: scanf() returned %d\n", rc);
            else
                printf("== Passed: centre(%d,%d) size(%d,%d)\n", x1, y1, x2, y2);
        }
    }

    return 0;
}

Output

Format 5
Format:    <<centre (%d ,%d ) size (%d ,%d %[)]>>
   Data:   <<centre ( 19, 43 ) size ( 21, 37 )>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre (19, 43) size (21, 37)>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre (19, 43) size (21, 37>>
!! Failed: scanf() returned 4
   Data:   <<centre(19,43) size(21,37)>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre(19,43) size(21,37>>
!! Failed: scanf() returned 4
   Data:   <<centre ( 19 , 43 ) size ( 21 , 37 )>>
== Passed: centre(19,43) size(21,37)
Format:    <<centre (%d,%d) size (%d,%d%[)]>>
   Data:   <<centre ( 19, 43 ) size ( 21, 37 )>>
!! Failed: scanf() returned 2
   Data:   <<centre (19, 43) size (21, 37)>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre (19, 43) size (21, 37>>
!! Failed: scanf() returned 4
   Data:   <<centre(19,43) size(21,37)>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre(19,43) size(21,37>>
!! Failed: scanf() returned 4
   Data:   <<centre ( 19 , 43 ) size ( 21 , 37 )>>
!! Failed: scanf() returned 1

Format 4
Format:    <<centre (%d ,%d ) size (%d ,%d )>>
   Data:   <<centre ( 19, 43 ) size ( 21, 37 )>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre (19, 43) size (21, 37)>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre (19, 43) size (21, 37>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre(19,43) size(21,37)>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre(19,43) size(21,37>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre ( 19 , 43 ) size ( 21 , 37 )>>
== Passed: centre(19,43) size(21,37)
Format:    <<centre (%d,%d) size (%d,%d)>>
   Data:   <<centre ( 19, 43 ) size ( 21, 37 )>>
!! Failed: scanf() returned 2
   Data:   <<centre (19, 43) size (21, 37)>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre (19, 43) size (21, 37>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre(19,43) size(21,37)>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre(19,43) size(21,37>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre ( 19 , 43 ) size ( 21 , 37 )>>
!! Failed: scanf() returned 1

Note how the format strings under 'Format 4' accept the data when the second close parenthesis is missing. Even though the character is missing, the 4 conversion specifications are satisfied. The 'Format 5' formats reject those data lines.

The example code and data does not demonstrate it, but the code would also happily read multiple close parentheses (because it uses %[)]). This could be avoided by using %1[)] to stipulate that only a single close parenthesis is at the end. You could also use the %n conversion specification and a sixth argument (another int *) to get the number of characters processed. This would allow you to detect where the scanning stopped, and hence whether there are unprocessed characters after the required input. Note that %n conversion specifications are not counted in the return value from scanf() et al. This fragment could be pasted at the end of the main() function in the code:

printf("\nFormat 6\n");
int len, rc;
const char data6[] = "centre ( 19 , 43 ) size ( 21 , 37 )))";
const char format6[] = "centre (%d ,%d ) size (%d ,%d %1[)]%n";
printf("Format:    <<%s>>\n", format6);
printf("   Data:   <<%s>>\n", data[5]);
if (sscanf(data6, format6, &x1, &y1, &x2, &y2, str, &len) != 5)
    printf("!! Failed: scanf() returned %d\n", rc);
else
    printf("== Passed: centre(%d,%d) size(%d,%d) len=%d <<%s>>\n",
           x1, y1, x2, y2, len, &data6[len]);

It generates the output:

Format 6
Format:    <<centre (%d ,%d ) size (%d ,%d %1[)]%n>>
   Data:   <<centre ( 19 , 43 ) size ( 21 , 37 )))>>
== Passed: centre(19,43) size(21,37) len=35 <<))>>

Summary

If you understand why each of the results is obtained, you have a decent understanding of scanf(). If you aren't sure why, experiment and read the specification (e.g. POSIX sscanf()) until you are sure you understand it.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
-2

In your Case

char y[] = "a";
scanf("Letter: %s", y);
printf("%s\n", y);

You should give input like this.

Letter: abcd

It will work correctly

for example if the scanf is written like that

int y;
scanf("y=%d", &y);

then you should give input like

y=10

not 10

i think u got what u want... :) now enjoy

Mayank Tiwari
  • 2,974
  • 5
  • 30
  • 52