Thread: Simply Library Catalog Program not working

  1. #1
    Registered User
    Join Date
    Jan 2009
    Posts
    22

    Simple Library Catalog Program not working

    I have written what is my largest program to date, a simple library catalog:

    Code:
    #include "stdio.h"
    #include "conio.h"
    #include "string.h"
    
    void enter(char *c1);
    void findAuthor(char *c2);
    void findTitle(char *c3);
    
    void main(void)
    {
         char choice, *p;
         char catalog[100][3][50];     
         p = (char *) catalog;
              
         do {
             printf("Card Catalog:\n");
             printf("1. Enter\n 2. Search by Author\n 3. Search by Title\n 4. Quit\n");
             printf("Enter your choice here: ");
             choice = getch();
         
             while(choice!=1||choice!=2||choice!=3||choice!=4)
             printf("Invalid choice. Try again.");
             
             switch(choice) {
               case(1):
                 enter(p);
                 break;
            
               case(2):
                 findAuthor(p);
                 break;
               
               case(3):
                 findTitle(p);
                 break;
              }
            } while(choice!=4);
            
            printf("Thank you for using the Library Catalog. Press any key to exit.");
            getch();        
    }
            
    void enter(char *c1)
    {
         int i;     
         
         for(i=0;i<101;i++){
             printf("Enter the title: ");         
             if(!strcmp(gets(*(c1+(i*150))),"\n")) break;            
             printf("\nEnter the author: ");
             gets(*(c1+(i*150)+50)));
             printf("\nEnter the publisher: ");
             gets(*(c1+(i*150)+100)));        
         }
    }
    I omitted the rest of the program which contains the body of the other two functions prototyped.

    When I compile it, I get several warnings.

    The first says [Warning] return type of 'main' is not `int' and refers to the line below 'void main(void)'. I'm not sure how this is an error, I thought I'd point it out anyway if it is some sort of mistake.

    The main problem is that I get several of these kind of messages: "[Warning] passing arg 1 of `gets' makes pointer from integer without a cast" during each of the gets lines (there are more such lines in the other two functions).

    Clearly there is some problem with my use of pointers but I can't figure out what.

    EDIT: I corrected a few mismatched bracketing issues and the program now runs, but pressing any key after the menu is displayed causes an infinite stream of garbage characters to be output to the console.
    Last edited by Bakster; 08-31-2009 at 02:55 PM.

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    So there isn't such a thing as "void main". There is "int main", however, which you can use.

    gets requires a "string" -- a pointer to memory. c1+(i*150) is such a thing. *(c1+(i*150)) is not. Although why you don't just pass your array in as an array, and read in to things like "library[0][0]", or "library[2][1]" I don't know.

  3. #3
    Registered User
    Join Date
    Jan 2009
    Posts
    22
    I didn't think you could pass an array into a function, only a pointer. I previously tried indexing the pointer passed into the function like I would index an array, but that didn't compile either.

  4. #4
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by Bakster View Post
    I didn't think you could pass an array into a function, only a pointer. I previously tried indexing the pointer passed into the function like I would index an array, but that didn't compile either.
    Of course you can pass an array into a function. You will need to specify the size of the array (except optionally the first size).

  5. #5
    Registered User
    Join Date
    Jan 2009
    Posts
    22
    I rewrote the program:

    Code:
    #include "stdio.h"
    #include "conio.h"
    #include "string.h"
    
    void enter(char c1[100][3][50]);
    void findAuthor(char c2[100][3][50]);
    void findTitle(char c3[100][3][50]);
    
    int main(void)
    {
         char choice;
         char catalog[100][3][50];        
              
         do {
             printf("Card Catalog:\n");
             printf("1. Enter\n2. Search by Author\n3. Search by Title\n4. Quit\n");
             printf("Enter your choice here: ");
             choice = getchar();
         
             while(choice!=1||choice!=2||choice!=3||choice!=4)
             printf("Invalid choice. Try again.");
             
             switch(choice) {
               case(1):
                 enter(catalog);
                 break;
            
               case(2):
                 findAuthor(catalog);
                 break;
               
               case(3):
                 findTitle(catalog);
                 break;
              }
            } while(choice!=4);
            
            printf("Thank you for using the Library Catalog. Press any key to exit.");
            getch();  
            return 0;      
    }
            
    void enter(char c1[100][3][50])
    {
         int i;     
         
         for(i=0;i<101;i++){
             printf("Enter the title: ");         
             if(!strcmp(c1[i][1],"\n")) break;            
             printf("\nEnter the author: ");
             gets(c1[i][2]);
             printf("\nEnter the publisher: ");
             gets(c1[i][3]);        
         }
    }
    
    void findAuthor(char c2[100][3][50])
    {
         char author[50];
         int i;
         
         printf("Enter the author: ");
         gets(author);
         
         for(i=0; *c2; i++){
            if(!strcmp(author,c2[i][1])) {
              printf("Title: %.50s\n",c2[i][2]);
              printf("Publisher: %.50s\n",c2[i][3]);
              break;
            }
            else printf("No matches found.");
            
         }     
    }
    
    ...
    When I run the program now the initial menu displays, but when I press any key the console still prints endless garbage characters.

    Also is it true that accessing arrays using pointer arithmetic is faster than indexing?

  6. #6
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Garbage characters? Or "invalid choice try again"? Since that conditional in the while loop will always be true, I don't know how you get past that part. Also, you can probably not type the character with ASCII code 1 at the keyboard -- you should be checking against '1', '2', '3', or '4'.

  7. #7
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Code:
         for(i=0; *c2; i++){
            if(!strcmp(author,c2[i][1])) {
              printf("Title: %.50s\n",c2[i][2]);
              printf("Publisher: %.50s\n",c2[i][3]);
              break;
            }
            else printf("No matches found.");
            
         }
    I don't see you changing c2 anywhere in that loop, which means it will probably execute infinitely. Maybe you wanted the loop condition to be "*c2[i]" or "c2[i][0]"?

    Your compiler was warning you about gets() because it's a very dangerous function. Because you don't pass it the size of your buffer, the user can enter as much data as they like. It's like a built-in buffer overrun. Also see: SourceForge.net: Gets - cpwiki

    And void main() is non-standard, one should use int main(): SourceForge.net: Void main - cpwiki

    Also is it true that accessing arrays using pointer arithmetic is faster than indexing?
    It's rather unlikely. Nearly all compilers these days do significant optimizations to your code; they'll change one version into the other if there's an efficiency difference. Note also that even if there was a difference in speed, it would be unnoticeable compared to the other things your code does. For example, an inefficient array operation might waste three or eight clock cycles. Waiting for data from the hard drive will take millions of cycles, and waiting for user input potentially way more than that. So don't worry about that sort of thing unless you're running calculations that take an hour to complete . . . .

    Also, may I suggest using better names than "c2"? You should also know that you can use the same name for parameters in different functions; the parameter only exists (is "in scope") for the duration of the function.

    Finally:
    Code:
             printf("Card Catalog:\n");
             printf("1. Enter\n2. Search by Author\n3. Search by Title\n4. Quit\n");
             printf("Enter your choice here: ");
             choice = getchar();
         
             while(choice!=1||choice!=2||choice!=3||choice!=4)
             printf("Invalid choice. Try again.");
    Maybe you want something like this:
    Code:
             printf("Card Catalog:\n");
             printf("1. Enter\n2. Search by Author\n3. Search by Title\n4. Quit\n");
             printf("Enter your choice here: ");
             while(choice != '1' && choice != '2' && choice != '3' && choice != '4') {
                 choice = getchar();         
                 printf("Invalid choice. Try again.");
            }
    You need AND, not OR. Think about it: will "choice != 1 OR choice != 2" ever be false? And you need to get a new character within the loop, or once you start it you'll never stop. You also need to use '1' instead of 1 (same goes for your switch statement), since getchar() returns characters, not nicely converted numbers. Finally, you'll have to initialize choice or else use a do-while loop; otherwise, the value of choice is undefined the first time your loop executes (it might be 'a', or '1', or something strange).
    Last edited by dwks; 08-31-2009 at 04:55 PM.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  8. #8
    Registered User
    Join Date
    Jan 2009
    Posts
    22
    Thanks for all that information, dwks. My program now acts better than it did previously, but the program just prints all the options ("Enter the title: " etc.) after I select a menu choice without giving the user a chance to type anything. I'm gonna try and use scanf instead of fgets and see what happens.

  9. #9
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Oh, yes. I missed that. If your program is still similar to what you have above (post your latest code!) then you're using getchar() in main() followed by a line-based input function like gets() or fgets() in the rest of the code.

    The problem with this is . . . consider typing "1\n", to pick a menu choice. getchar() will read the '1', and it will all work out. But when fgets() comes to read its data, it sees "\n" in the input buffer, and so returns immediately with an empty string.

    The solution is, when you use getchar(), to remove the other characters (up until a newline) from the input buffer. Something like this should do the trick.
    Code:
    while(getchar() != '\n') {}
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  10. #10
    Registered User
    Join Date
    Jan 2009
    Posts
    22
    I replaced the gets() with scanf and this is my new program:

    Code:
    #include "stdio.h"
    #include "conio.h"
    #include "string.h"
    
    void enter(char lib[100][3][50]);
    void findAuthor(char lib[100][3][50]);
    void findTitle(char lib[100][3][50]);
    
    int main(void)
    {
         char choice = '1';
         char catalog[100][3][50];        
              
         do {
             printf("Card Catalog:\n");
             printf("1. Enter\n2. Search by Author\n3. Search by Title\n4. Quit\n");
             printf("Enter your choice here: ");
             choice = getchar();
         
             while(choice!='1'&&choice!='2'&&choice!='3'&&choice!='4'){
             printf("\nInvalid choice. Try again.");
             choice = getchar();
             }
             
             switch(choice) {
               case('1'):
                 enter(catalog);
                 break;
            
               case('2'):
                 findAuthor(catalog);
                 break;
               
               case('3'):
                 findTitle(catalog);
                 break;
              }
            } while(choice!='4');
            
            printf("Thank you for using the Library Catalog. Press any key to exit.");
            getch();  
            return 0;      
    }
            
    void enter(char lib[100][3][50])
    {
         int i;     
         char author[50];
         char title[50];
         char publisher[50];
         
         for(i=0;i<101;i++){
             printf("\nEnter the title: ");      
             scanf("%50s",author);          
             if(!strcmp(author,"\r")) break;            
             printf("\nEnter the author: ");
             scanf("%50s",title);
             printf("\nEnter the publisher: ");
             scanf("%50s",publisher);       
         }
    }
    
    void findAuthor(char lib[100][3][50])
    {
         char author[50];
         int i;
         
         printf("Enter the author: ");
         scanf("%50s",author); 
         
         for(i=0;*lib[i][1];i++){
            if(!strcmp(author,lib[i][1])) {
              printf("Title: %.50s\n",lib[i][2]);
              printf("Publisher: %.50s\n",lib[i][3]);
              break;
            }    
            else printf("No matches found.");     
         }     
         
    }
    
    void findTitle(char lib[100][3][50])
    {
         char title[50];
         int i;
         
         printf("Enter the title: ");
         scanf("%50s",title); 
         
         for(i=0;*lib[i][1];i++){
            if(!strcmp(title,lib[i][2])){
              printf("Author: %.50s\n",lib[i][1]);
              printf("Publisher: %.50s\n",lib[i][3]);
              break;
              }
            else printf("No matches found.");        
         }     
    }
    This program still suffers from the newline character being in the input stream when it isn't supposed to be like you mentioned, but I am not sure where to place the while loop fragment you posted.

    There are two other problems. First, when the findAuthor and findTitle functions fail to find a match, the initial menu is printed out without "No matches found." being printed.

    The second problem is the line

    Code:
    if(!strcmp(author,"\r")) break;
    in the enter function. I want the loop to break when the user enters in a blank line (i.e. just presses enter). I have tried strcmp with \r and \n but neither work, so I can never exit the loop. I'm not sure what to compare it with to exit the loop, or whether using strcmp is even the right way to do it.

  11. #11
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    %s does not read whitespaces - so no chance to enter the \r or \n or \t or space into the buffer using this format specifier
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  12. #12
    Registered User
    Join Date
    Jan 2009
    Posts
    22
    Alright I went back to fgets() again, it seems to be in working order except for the getchar() problem, I still don't know where to place the while loop fragment.
    Last edited by Bakster; 09-03-2009 at 05:11 PM.

  13. #13
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by Bakster View Post
    Alright I went back to fgets() again, it seems to be in working order except for the getchar() problem, I still don't know where to place the while loop fragment.
    Why would you want to use getchar with fgets?

  14. #14
    Registered User
    Join Date
    Jan 2009
    Posts
    22
    Quote Originally Posted by tabstop View Post
    Why would you want to use getchar with fgets?
    Well I don't really know any alternatives to read a character. The only other input function I am aware of is scanf.

  15. #15
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Why not use fgets? (a) You should anyway and (b) it's the right thing to do. You can then either compare the first character of the input string to your menu options, or you can check to see if they typed in a bunch of stuff and throw an error message.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. loading a 32-bit library into 64-bit linux program
    By Elkvis in forum Linux Programming
    Replies: 11
    Last Post: 03-26-2009, 10:58 AM
  2. Client-server system with input from separate program
    By robot-ic in forum Networking/Device Communication
    Replies: 3
    Last Post: 01-16-2009, 03:30 PM
  3. Replies: 4
    Last Post: 03-26-2008, 08:48 AM
  4. Compiling Library Into Program.
    By Shogun in forum Linux Programming
    Replies: 10
    Last Post: 11-30-2004, 01:29 PM
  5. character occurrence program not working
    By Nutshell in forum C Programming
    Replies: 6
    Last Post: 01-21-2002, 10:31 PM