Reputation: 19
I'm attempting to write a small program that a user input book information in the "struct bookinfo" and then print what the user writes.
I use 'scanf' and 'gets' to induce user's input but the for
loop is skipping the 3rd and 4th questions/answer.
Here is my code
#include <stdio.h>
#include <stdlib.h>
struct bookInfo {
char title [40];
char author [25];
float price;
int pages;};
main ()
{
int ctr;
struct bookInfo books[3];
for (ctr = 0 ; ctr< 3; ctr++)
{
printf("What is the name of the book #%d?\n", (ctr+1));
gets( books[ctr]. title);
puts("who is the author?");
gets(books[ctr].author);
puts("How much did the book cost? ");
scanf(" $%f ", &books[ctr].price);
puts("How many pages in the book? ");
scanf(" %d", &books[ctr].pages);
getchar();
}
output is here.
What is the name of the book #1?
cosmos
who is the author?
kal caygon
How much did the book cost?
14.99
How many pages in the book?
What is the name of the book #2?
who is the author?
Am I wrong with scanf? In order to avoid skipping, I use getchar()
and put a space front of %f
and %d
.
Upvotes: 1
Views: 408
Reputation: 753735
You should check the result from scanf()
.
You have:
scanf(" $%f ", &books[ctr].price);
You say you enter:
14.99
There's no dollar sign in what you enter, so the conversion fails. The return value from scanf()
is 0
, telling you that you've got problems. The number of pages is then read as 14
. And the next book title is read as 99
(the getchar()
used the .
). Probably, you should simply remove the $
from the format string.
Note that the getchar()
is not reliable if the user enters, for example, a space or a dot after the number of pages. Consider a loop like:
int c;
while ((c = getchar()) != EOF && c != '\n')
;
to read the rest of the line.
The spaces in front of %d
and %f
are harmless but unnecessary. The only conversion specifiers for scanf()
that do not skip leading spaces are %c
, %[…]
(scan sets) and %n
. All the other conversion specifications skip leading white space, including newlines, automatically.
I didn't previously notice that you also have a space after the %f
conversion specifier. That's a disaster — see The effect of trailing white space in a scanf()
format string. Remove it. That's a necessary step.
I never use gets()
, and fgets()
keeps the newline in the data it reads, so I created a surrogate for gets()
called alt_gets()
that takes a size as well as a the buffer. It returns 0 or EOF, whereas gets()
and fgets()
return a pointer to the buffer or a null pointer. I updated the code to error check each input — both the calls to alt_gets()
and to scanf()
.
I also created a crude (but effective) error reporting routine. The production-ready version of the error reporting code is available in my SOQ (Stack Overflow Questions) repository on GitHub as files stderr.c
and stderr.h
in the src/libsoq sub-directory.
Revised code, including printing (which needs a terminal that's at least 110 characters wide to avoid line-wrapping):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct bookInfo
{
char title[40];
char author[25];
float price;
int pages;
};
static void err_exit(const char *msg);
static int alt_gets(size_t buflen, char buffer[buflen]);
int main(void)
{
struct bookInfo books[3];
for (int ctr = 0; ctr < 3; ctr++)
{
printf("What is the name of the book #%d?\n", (ctr + 1));
if (alt_gets(sizeof(books[ctr].title), books[ctr].title) == EOF)
err_exit("Failed to read the title");
puts("who is the author?");
if (alt_gets(sizeof(books[ctr].author), books[ctr].author) == EOF)
err_exit("Failed to read the author");
puts("How much did the book cost? ");
if (scanf("%f", &books[ctr].price) != 1)
err_exit("Failed to read the price");
puts("How many pages in the book? ");
if (scanf("%d", &books[ctr].pages) != 1)
err_exit("Failed to read the number of pages");
getchar();
}
putchar('\n');
for (int i = 0; i < 3; i++)
{
printf("Title: %-40s Author: %-25s Cost: $%5.2f Pages: %3d\n",
books[i].title, books[i].author, books[i].price, books[i].pages);
}
return 0;
}
static int alt_gets(size_t buflen, char buffer[buflen])
{
if (fgets(buffer, buflen, stdin) == 0)
return EOF;
buffer[strcspn(buffer, "\n")] = '\0';
return 0;
}
static void err_exit(const char *msg)
{
fprintf(stderr, "%s\n", msg);
exit(1);
}
Sample output (source book41.c
, program book41
):
$ book41
What is the name of the book #1?
Pride and Prejudice
who is the author?
Jane Austen
How much did the book cost?
14.99
How many pages in the book?
522
What is the name of the book #2?
The End of Eternity
who is the author?
Isaac Asimov
How much did the book cost?
12.99
How many pages in the book?
256
What is the name of the book #3?
The C Programming Language
who is the author?
B Kernighan & D Ritchie
How much did the book cost?
32.99
How many pages in the book?
232
Title: Pride and Prejudice Author: Jane Austen Cost: $14.99 Pages: 522
Title: The End of Eternity Author: Isaac Asimov Cost: $12.99 Pages: 256
Title: The C Programming Language Author: B Kernighan & D Ritchie Cost: $32.99 Pages: 232
$
Upvotes: 1