0

Hey I've been trying to resolve this issue I'm having. The second scanf doesn't allow input for an integer. I've checked to make sure everything is correct, but it's still the same thing. Am I missing something? Output stops at "Enter your age at the end of this year: "

int main() {

    int age;
    char usrname;
    
    printf("Hello, Welcome to the birth year calculator!");
    printf("\n\nEnter Your Name: ");
    scanf("%c", &usrname);

    printf("Enter your age at the end of this year: ");
    scanf("%d", &age);

    return 0;
}
tadman
  • 208,517
  • 23
  • 234
  • 262
John Doe
  • 21
  • 3
  • 3
    Are you aware of the fact that the code you have only accepts a single character for the name? – Thomas Jager Sep 22 '22 at 01:55
  • Questions seeking debugging help should generally provide a [mre] of the problem, which includes the exact input required to reproduce the problem. – Andreas Wenzel Sep 22 '22 at 01:56
  • This is just C code. If you're intending to use C++ then you need `std::string name` and `std::cin >> name`. Way easier. – tadman Sep 22 '22 at 01:59
  • What is your input? If it's `"Jo 20"` the name is too long, and the space isn't accounted for. – tadman Sep 22 '22 at 02:00
  • 2
    Duplicate of https://stackoverflow.com/q/73806464/2410359 – chux - Reinstate Monica Sep 22 '22 at 02:01
  • @ThomasJager No it does not I can type more than a single character – John Doe Sep 22 '22 at 02:01
  • 1
    "I can type more than a single character" --> Don't do that. Try `"X 123"` as input. – chux - Reinstate Monica Sep 22 '22 at 02:02
  • 2
    @JohnDoe The format specifier `"%c"` accepts a single character. If you're giving it more than one character to read, you're probably not going to scan the input you expect, – Thomas Jager Sep 22 '22 at 02:04
  • 1
    Note it's best not to argue with people trying to help, and instead check your code more carefully. You "can" type more than one character, however this code, as it stands, can't handle it. `"%c"` gets one character, and `char` can only hold one character. – tadman Sep 22 '22 at 02:06
  • Is this asking for a (possibly?) C++ solution or strictly a C one? You tagged this as C++, but there's absolutely no C++ code here, so I removed the tag, awaiting clarification. – tadman Sep 22 '22 at 02:07
  • @ThomasJager Apologies I had read your question wrongly – John Doe Sep 22 '22 at 02:09
  • @tadman It's just for C. New to using stack so I assumed I had to put for c++ to get more attention to the post – John Doe Sep 22 '22 at 02:10
  • 1
    The only "attention" that will get you is people expressing their frustration. Shalofty put together a good C++ answer that, apparently, is a waste of time, so please don't. – tadman Sep 22 '22 at 02:11
  • 1
    @tadman As I said I'm new to using SO. I'll note your comment for future posts/questions – John Doe Sep 22 '22 at 02:15
  • No problem. Hope you find an answer that helps. Don't forget to upvote any that are useful, and accept the one that best solved the problem. – tadman Sep 22 '22 at 02:16
  • 1
    ThomasJager and chux's Inputs were helpful and I have resolved the issue. Thanks I'll learn from this. – John Doe Sep 22 '22 at 02:23

5 Answers5

3

Other than the odd choice of char usrname it works for me. If you type more than 1 letter before enter in it will cause the 2nd scanf() to fail which you will see with error checking. If you don't want any input for the first prompt to bleed into the 2nd then you need to flush the input stream between. Minimized scope of variables:

#include <stdio.h>

int main() {
    printf("\n\nEnter Your Name: ");
    char usrname;
    if(scanf("%c", &usrname) != 1) {
        printf("usrname failed\n");
        return 1;
    }
    printf("Enter your age at the end of this year: ");
    int age;
    if(scanf("%d", &age) != 1) {
        printf("age failed\n");
        return 1;
    }
    printf("name=%c, age=%d\n", usrname, age);
    return 0;
}

You probably want to use a string instead a char for the usrname. If your user name contains space then you are better off reading a line with fgets() instead of scanf(). Also changed age to an unsigned.

#include <stdio.h>
#define TADMAN_IS_NOT_STINGY 254
#define str(s) str2(s)
#define str2(s) #s

int main() {
    printf("\n\nEnter Your Name: ");
    char usrname[TADMAN_IS_NOT_STINGY+1];
    if(scanf("%" str(TADMAN_IS_NOT_STINGY) "s", usrname) != 1) {
        printf("usrname failed\n");
        return 1;
    }
    printf("Enter your age at the end of this year: ");
    unsigned age;
    if(scanf("%u", &age) != 1) {
        printf("usrname failed\n");
        return 1;
    }
    printf("name=%s, age=%u\n", usrname, age);
    return 0;
}
Allan Wind
  • 23,068
  • 5
  • 28
  • 38
  • `char[10]` is a bit stingy. Why not something a bit more lenient like `char[255]`? Nice with `%9s` though, most omit that. – tadman Sep 22 '22 at 02:16
  • 1
    @tadman Fixed in your honor :-) – Allan Wind Sep 22 '22 at 02:17
  • I guess that works?? – tadman Sep 22 '22 at 02:22
  • 1
    It's a good call and I wanted to cite your input. – Allan Wind Sep 22 '22 at 02:22
  • Your `str` macro is interesting. Is there a way to adapt that to incorporate the `%s` part as well? Might look really tidy with `SCANF_SPAT(c)` for a given constant `c`. I've never seen that trick before, but it is neat, and surely avoids a lot of "oh, right" bugs. – tadman Sep 22 '22 at 02:25
  • It's bog standard macro to stringify a number in c. You could, but you usually need to stringify other things besides format strings. – Allan Wind Sep 22 '22 at 02:27
  • I get that part, I mean using it in the context of `scanf` to size the `%s` argument correctly. – tadman Sep 22 '22 at 02:27
3

The problem is the following two lines:

printf("\n\nEnter Your Name: ");
scanf("%c", &usrname);

You are telling the user to enter something that consists of more than a single character, but you are only extracting a single character from the input stream and writing it to usrname.

For example, if you enter Michael, then you will extract the M from the input stream, leaving ichael on the stream.

Afterwards, you will execute the line

scanf("%d", &age);

which will attempt to convert what is left on the input stream to an integer. However, this will fail, because it is not possible to convert ichael to an integer.

It is generally not recommended to use scanf for line-based user input. This is because scanf does not behave in an intuitive manner. For example, as demonstrated above, it does not always read one line of input in one function call, which can cause trouble, as it did with you.

For this reason, it is generally recommended to use the function fgets instead, which will always read exactly one line of input, if possible. After reading one line of input as a string, you can attempt to convert it to an integer, for example using the function strtol.

Note that fgets will also write the newline character at the end of the line to the string, so you will probably want to remove it. You may want to read this question on how to do that:

Removing trailing newline character from fgets() input

Here is an example:

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

int main()
{
    char usrname[200];
    char line[200];
    int age;
    
    printf("Hello, Welcome to the birth year calculator!");

    printf("\n\nEnter Your Name: ");
    fgets( usrname, sizeof usrname, stdin );

    //remove newline character
    usrname[strcspn(usrname,"\n")] = '\0';

    printf("Enter your age at the end of this year: ");
    fgets( line, sizeof line, stdin );
    age = strtol( line, NULL, 10 );

    return 0;
}
Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
1

Before DV'ing this C++ answer, read the comments below.


This is what I did and it seemed to work just fine.

I created a class, not sure if that's even necessary

class Person {
    std::string userName;
    int age;
}

main() {
    Person shalofty;
    std::cout << "Enter name and age" << std::endl;
    std::cin >> shalofty.userName;
    std::cin >> shalofty.age;
}
Fe2O3
  • 6,077
  • 2
  • 4
  • 20
Shalofty
  • 29
  • 4
  • Why have you given a *very* C++ answer to a C question? – Thomas Jager Sep 22 '22 at 02:03
  • @ThomasJager: The question was also tagged C++ 5 minutes ago. – Andreas Wenzel Sep 22 '22 at 02:04
  • 4
    There was a c++ tag when I wrote it!! – Shalofty Sep 22 '22 at 02:04
  • 1
    Fair enough, I've removed my downvote, though I would consider replacing the C-style printing and scanning with the C++ ones to not be a particularly good and complete answer, since it doesn't do anything to show why what's in the question is wrong. – Thomas Jager Sep 22 '22 at 02:06
  • 1
    Sorry to say, using c++, implementing a class will not help to understand what is wrong in the code of the question. It works but makes it more complicated. – Ahmad Yeaseen Khan Sep 22 '22 at 02:10
  • 1
    @AhmadYeaseenKhan Implementing a super simple class like this is a great idea and doesn't make things "more complicated". C++ gets way, way harder than this even doing routine things. It's never too early to be learning about proper data encapsulation and *separation of concerns*. – tadman Sep 22 '22 at 02:12
  • Sometimes when someone has a problem with their code I like to think of how I would do it instead of trying to bend their code to my will. I'm not a cpp master though, I'm sure you're right. I just showed what worked for me. I was scrolling stack while working on my own. – Shalofty Sep 22 '22 at 02:21
1

First scanf read only 1 char from stdin(cuz usrname is char instead of char array), after then, if stdin is empty -> the second scanf will then wait for input, otherwise the second scanf will be executed automatically after the second prompt printing.

In your case, I suppose at the first prompt, you have inputted more than 1 chars, in that situation, the second scanf will not wait but run with extra input which was not read by first scanf. e.g if you enter john for the first prompt, then the first scanf takes j, the second scanf takes ohn and try to convert to int.

To fix this, use char array for the usrname e.g char usrname[128] = {0} or don't input more than 1 char at the first prompt (for the name).

int main() {

    int age;
    char usrname[128] = {0};
    
    printf("Hello, Welcome to the birth year calculator!");
    printf("\n\nEnter Your Name: ");
    scanf("%s", usrname);

    printf("Enter your age at the end of this year: ");
    scanf("%d", &age);

    return 0;
}
S Dao
  • 555
  • 4
  • 7
0

Different people see different priorities and offer different advice. Here, in commented code, is another version close to your original version but embellished

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

int main()
{
    char usrname[200] = { 0 }; // ALWAYS initialise variables
    
    printf("Hello, Welcome to the birth year calculator!");

    printf("\n\nEnter Your Name: ");

    if( scanf( "%[^\n]", usrname ) != 1 ) { // test return codes
        fprintf( stderr, "Scanf failed\n" );
        exit( EXIT_FAILURE );
    }

    // remove trailing '\n' from the name entered
    usrname[ strcspn( usrname, "\n" ) ] = '\0';

    int usrage = 0; // define and initialise variables close to use
    printf("Enter your age at the end of this year: ");

    if( scanf( "%d", &usrage ) != 1 ) { // test return codes
        fprintf( stderr, "Scanf failed\n" );
        exit( EXIT_FAILURE );
    }

    // do something with the user's input
    printf( "Hello %s, who will be %d years old at year's end\n", usrname, usrage );

    return 0;
}

Output

Hello, Welcome to the birth year calculator!

Enter Your Name: Foo Bar
Enter your age at the end of this year: 42
Hello Foo Bar, who will be 42 years old at the end of this year
Fe2O3
  • 6,077
  • 2
  • 4
  • 20
  • `scanf( "%[^\n]"`, without a width limit, is worse than [`gets()`](https://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used). – chux - Reinstate Monica Sep 22 '22 at 03:57
  • @chux-ReinstateMonica Understood... but, this answer was written with the target audience dial set to "beginner"... I thought showing how to read strings (embedded whitespace) using `scanf()` and testing return values was most significant. AND, declaring and initialising variables close to their use... Starting to develop a persecution complex here on SO, noting the absence of 'particular' criticism leveled at other answers... All good. For a beginner reader, I think this alternative will be _broadening_ enough for one day... `:-)` – Fe2O3 Sep 22 '22 at 04:19