Supertecnoboff
Supertecnoboff

Reputation: 6606

Whats wrong with my SIMPLE C program?

I am writing a super simple command line based program in C. It's just a small test and the code is very simple. So what it is meant to do is to ask the user for their name, maths grade, english grade, computing grade. Then it figures out their average grade and also tells them the name they entered. Yes I know this is an extremely simple program, but I'm still doing something wrong.

The problem is, one part of my code will run first telling the user to enter their name and then once they do this and press enter the rest of my code will run all at once and then stop working. It's weird I just don't understand what is wrong.

#include <stdio.h>

int main(int argc, const char * argv[])
{
    char chr;
    char firstname;
    int mathsmark, englishmark, computingmark, averagemark;

    printf("What is your name?\n");
    scanf("%c", &firstname);
    printf("\n");

    printf("What is your maths mark?\n");
    scanf("%d", &mathsmark);
    printf("\n");

    printf("What is your english mark?\n");
    scanf("%d", &englishmark);
    printf("\n");

    printf("What is your computing mark?\n");
    scanf("%d", &computingmark);
    printf("\n");

    printf("Your name is: %c", firstname);
    printf("\n");

    averagemark = (mathsmark + englishmark + computingmark) / 3;
    printf("%d", averagemark);
    printf("\n");

    chr = '\0';

    while (chr != '\n') {

        chr = getchar ();
    }

    return 0;
}

Upvotes: 1

Views: 1035

Answers (4)

user1668559
user1668559

Reputation: 181

You have (at least) two choices.

char firstname[number_big_enough_to_hold_long_name];
/*or */

char *firstname = malloc(sizeof(char) * number_big_enough_to_hold_long_name);
/* ... code ... */
free(firstname);

Further it would be best to limit width of read. scanf() does not know the size (available space) of firstname.

scanf("%number_big_enough_to_hold_long_names", ...
/* i.e. */

char firstname[32];
if(scanf("%31s", firstname) == EOF) {
     perror("bad");
     return 1;
}

Further you should check if there is anything left before trying next read. I.e. If someone enters "My Name" then only "My" will end up in firstname and "Name" will be left in input stream.

And getchar() returns an int not a char.

  • getchar
  • scanf

  • And search "ansi c char arrays tutorial" or similar.

Upvotes: 1

Mike
Mike

Reputation: 49403

You might want to look at a few tutorials. Maybe one on Format specifiers and one on strings in C

scanf() reads data from stdin and stores them as specified by the format specifiers. In this case:

char firstname;    
scanf("%c", &firstname); 

Read 1 character from stdin and store it to firstname:

>> What is your first name?
Mike

Now firstname == 'M' because scanf() read 1 character as we requested.

What you wanted to do was read a string (a bunch of characters):

char firstname[5];        // an array of characters
scanf("%s", firstname);  // store as a string
firstname[4] = '\0';      // Truncate the result with a NULL to insure no overflow

>> What is your first name?
Mike

Now firstname is [M][i][k][e][\0] because scanf() read 1 string, as we requested. Note the same holds true for printf(), a printf with a %c will give you one character where as a printf() with a %s will give you all the characters until the NULL terminator.

Upvotes: 1

John Bode
John Bode

Reputation: 123488

One major problem is that you've declared firstname to be a single character long, and when you try to read the name from the console, you're using the %c conversion specifier, which reads the next single character from the input stream and stores it to firstname. The remainder of the name is left in the input stream to foul up the remaining scanf calls.

For example, if you type "Jacob" as a first name, then the first scanf call assigns J to firstname, leaving "acob\n" in the input stream.

The next scanf call attempts to convert "acob\n" to an integer value and save it to mathsmark, which fails ("acob\n" is not a valid integer string). Same thing happens for the next two scanf calls.

The last loop

while (chr != '\n')
{
   chr = getchar();
}

finally consumes the rest of "acob\n", which contains the newline character (because you hit Enter after typing the name), causing the loop and program to exit.

How do you fix this?

First, you need to declare firstname as an array of char:

char firstname[SOME_SIZE] = {0};

where SOME_SIZE is large enough to handle all your cases. The you need to change scanf call to

scanf("%s", firstname);

This tells scanf to read characters from the input stream up to the next whitespace character and store the results to the firstname array. Note that you don't need to use the & operator here; under most circumstances, an expression of array type will be converted ("decay") to an expression of pointer type, and the value of the expression will be the address of the first element in the array.

Note that scanf is not very safe, and it's not very robust. If you enter more characters than your buffer is sized to hold, scanf will happily store those extra characters to memory following the array, potentially clobbering something important. You can guard against this by using an explicit field width in the conversion specifier, like

scanf(*%29s", firstname);

but in general it's a pain.

scanf is also not very good at detecting bad input. If you enter "12er" as one of your marks, scanf will convert and assign the "12", leaving the "er" in the stream to foul up the next read.

scanf returns the number of successful assignments, so one way to guard against bad input is to check the return value, like so:

if (scanf("%d", &mathmarks) != 1)
{
  printf("Bad input detected for math marks\n");
}

Unfortunately, scanf won't remove bad characters from the stream; you'll have to do that yourself using getchar or similar.

Upvotes: 5

Cloud
Cloud

Reputation: 19333

This is a common mistake amongst newer C/C++ developers. The scanf function detects you hitting the ENTER/RETURN key to signal the end of input, but it also catches the \n character as well at the end of the input string, so you essentially get two RETURNS being detected.

Please read up on an example of using fgets and sscanf here:

http://www.linuxforums.org/forum/programming-scripting/67560-problem-scanf.html


It will resolve this issue very quickly for you. In the meantime, I strongly urge you to check out this book:

http://www.amazon.com/Primer-Plus-5th-Stephen-Prata/dp/0672326965


It is the most commonly used C programming book in high school and colleges in North America, and has TONS of examples for you to work through, including this specific program you demonstrated above. The print version has more examples than the e-book, so I would just cough up the $30.00 for the printed version.

Good luck!

Upvotes: 1

Related Questions