0

I am new to C, so I am likely not implementing the advice regarding removing trailing newlines located here correctly, but I have experimented for about an hour now and I'm still confused.

Here's the basic program, it's from a C Programming Absolute Beginner's Guide.

  4 main()
  5 {
  6   int ctr;
  7   char c;
  8   struct bookInfo books[3]; // array of three structure variables
  9
 10   // get info about each book from user
 11   for (ctr = 0; ctr < 3; ctr++)
 12   {
 13     printf("What is the name of book #%d?\n", (ctr+1));
 14     fgets(books[ctr].title, sizeof(books[ctr].title), stdin);
 15     books[ctr].title[strcspn(books[ctr].title, "\r\n")] = 0;
 16
 17     puts("Who is the author? ");
 18     fgets(books[ctr].author, sizeof(books[ctr].title), stdin);
 19     books[ctr].author[strcspn(books[ctr].author, "\r\n")] = 0;
 20
 21     puts("How much did the book cost? ");
 22     scanf(" $%f", &books[ctr].price);
 23
 24     puts("How many pages in the book? ");
 25     scanf(" %d", &books[ctr].pages);
 26   }

The book uses gets() for lines 14 and 18, but I have done enough reading to know that this is not good and have replaced it with fgets(). I feel like I am misunderstanding how either strcspn() works, or how scanf() interacts with the results of the previous code.

The top-voted answer to the link I've referenced above specifically uses this strcspn() technique:

books[ctr].title[strcspn(books[ctr].title, "\r\n")] = 0; as buffer[strcspn(buffer, "\n")] = 0;

but clearly I am not implementing this correctly. I wondered if it had something to do with the Struct, but I doubt that.

I also tried just capturing the extra input in the buffer in this way:

3     printf("What is the name of book #%d?\n", (ctr+1));
14    fgets(books[ctr].title, sizeof(books[ctr].title), stdin);
15    getchar();

but I get the same behavior.

Here's my output:

What is the name of book #1?
hobbit
Who is the author?
tolkien
How much did the book cost?
14.99                        <-- scanf() captures the newlines
How many pages in the book?  <-- this scanf() gets "skipped"
What is the name of book #2?
Who is the author?
  • 2
    `scanf(" $%f"` What input do you expect to match with `$`? You should always check return value of `scanf` and all other I/O functions to see if they were successful. – Gerhardh May 11 '22 at 13:51
  • 4
    As you were quite busy searching SO for useful answers (which is good!), you might also come acros many posts stating that mixing `fgets` and `scanf` isn't really best idea. You could use `fgets` for all input and use `sscanf` in cases where you want to extract numbers. – Gerhardh May 11 '22 at 13:54
  • You indirectly solved my problem. It was an oversight when I was inputting 14.99 as opposed to $14.99, hence the `scanf(" $%f")` - this is the book's convention, not mine. I became so myopic with the `fgets()` I had missed that entirely. – Quincy Tennyson May 11 '22 at 13:59
  • 3
    "I had missed that entirely" ... program safely in the future -- `if (scanf(...) != expected_value) { printf("scanf error at line %d\n", __LINE__); exit(EXIT_FAILURE); }` – pmg May 11 '22 at 14:01
  • Thank you, that is useful to know! This book leaves a lot to be desired. I have a supplemental text from Robert Seacord called *Effective C*, which covers a lot of the mistakes from this book, but this C for Absolute Beginners is the text recommended for the course I'm taking so I'm trying to work through it all before the class begins. There's actually a separate SO conversation about the book which is how BubbleSort is not implemented correctly, so I learned to write that properly as a result of that mistake :D – Quincy Tennyson May 11 '22 at 14:03

1 Answers1

0

@Gerhardh solved my problem indirectly in their comment. In my scanf() the format was meant to match a leading $ symbol, and I neglected to include that when I was actually running the program.

Classic tunnel vision.