Thread: Troubleshooting Input Function

  1. #1
    Registered User
    Join Date
    Nov 2007
    Posts
    26

    Question Troubleshooting Input Function

    Hey Folks,

    Anyone know why I'm getting an "incompatible types in return" error for :
    Code:
     if (fgets_ptr == NULL) return -1;
    in Dev C++ 4.9.9.2?

    Even when I remove the line, the function still does not behave as intended. I'm trying to take an entry, clear the buffer, and keep taking entries until the user gets it right (string neither to long nor empty), and finally remove the newline if there is one. Can anyone see what's going on here? Thanks.

    -SH

    Code:
    contact input ()                                                /* gets an entry from the user */
    {
         contact entry = {'\0','\0','\0','\0','\0','\0','\0','\0'}; /* initializes the structure   */
         char *fgets_ptr;
         int length;
         
         do{
         printf ("\nEnter a new name.\n\n>");
         fgets(entry.name, sizeof(entry.name), stdin);
         fgets_ptr = fgets(entry.name , sizeof(entry.name), stdin);
         if (fgets_ptr == NULL) return -1;  
         while((junk = getchar()) != '\n' && junk != EOF);
                        if ( strchr(entry.name, '\n') == NULL ){     /* if overflow */
                        printf ("\nYour entry is too long, please try again.");
                        entry.name[0] = '\0';
                        }
                        } while (entry.name[0] == '\0' || entry.name[0] == '\n');
         length = strlen (entry.name);             
         if (entry.name[length - 1] == '\n'){
             entry.name[length - 1] == '\0';}                        /* replace \n */
         return entry;
    }

  2. #2
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    That's because your return type is a struct of type contact, but -1 isn't of type contact, is it?

  3. #3
    Registered User
    Join Date
    Nov 2007
    Posts
    26
    Hmmm, so what do I return if I want this to compile and run without crashing if fgets returns NULL?

    Also, when I remove this line the code compiles but I get prompted for a name and must hit enter 3 times before I get prompted for a name again, regardless of whether my entry was empty or too long. It seems to be an infinite loop. Is there something wrong with my do-while syntax? Thanks for reading.
    Last edited by SiliconHobo; 11-29-2007 at 08:53 AM.

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    The solution depends on what how you use your function elsewhere.

    One solution is that you pass in a pointer to a contact, and fill it in (unless it fails), then return a "success/fail" value.

    Or you could allocate some memory with malloc for a contact, and if you then fail to read in the data, free the memory and return NULL.

    By the way:
    Code:
         fgets(entry.name, sizeof(entry.name), stdin);
         fgets_ptr = fgets(entry.name , sizeof(entry.name), stdin);
    I guess you only want to read the name once, right?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    Registered User
    Join Date
    Nov 2007
    Posts
    26
    Yes, only once in each run through the do-while. Thanks. Now I only have to hit enter twice instead of 3 times :P Could it be something to do with :

    Code:
    while((junk = getchar()) != '\n' && junk != EOF);
    ?
    Last edited by SiliconHobo; 11-29-2007 at 09:01 AM.

  6. #6
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Most certainly - you only need that if you don't have a newline at the end of the entry.name, so you need to swap place between the if-statement checking for newline and the while-loop reading any leftover data.

    Also, perhaps you may want to indent your code so that your loops are visible [one advantage of learning to program in Python is that indentation is enforced - your code don't work right if you sloppily just put things wherever you feel like.]

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  7. #7
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Chappell Hill, Texas
    Posts
    2,332
    It was working just fine when it looked like this: http://cboard.cprogramming.com/showp...08&postcount=6

    Compare any differences.

    Todd

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    The usual way for functions to return success/fail is typically that they take an argument (in this case, a pointer) to a "buffer" where it can store the information and returns bool, int, whatever to indicate success or failure.

  9. #9
    Registered User
    Join Date
    Nov 2007
    Posts
    26
    Thanks for the replies. Todd: I know you gave the exact working code but I wanted to write my own based on what I learned from your example rather than simply copy/paste. I have now got the get_input function working fine on its own. However, when I try to write another function that calls get_input repeatedlly with different prompt and pointer parameters for each field in the contact structure:

    Code:
    int get_input (char, contact);
    Code:
    contact input ()                                                /* gets an entry from the user */
    {
         contact entry = {'\0','\0','\0','\0','\0','\0','\0','\0'}; /* initializes the structure   */
         contact *input_ptr;
         input_ptr = &entry;
         char prompt1[25] = "Please enter a new name.";
    
         get_input (prompt1, &input_ptr->name);
         
         return (entry);
    }
         
    int get_input (prompt, *input_ptr)
    {
         char *fgets_ptr;
         char junk = 0;
         int length;
         
                    do{
                    printf ("\n%s\n\n>", prompt);
                     *fgets_ptr = fgets(*input_ptr, sizeof(*input_ptr), stdin); 
                     if (fgets_ptr == NULL) return -1;   
                        if ( strchr(*input_ptr, '\n') == NULL ){         /* if overflow */
                        printf ("\nYour entry is too long, please try again.\a");
                        while((junk = getchar()) != '\n' && junk != EOF);
                        *input_ptr[0] = '\0';
                        }
                    } while (*input_ptr[0] == '\0' || *input_ptr[0] == '\n');
         length = strlen (*input_ptr);             
         if (*input_ptr[length - 1] == '\n'){
             *input_ptr[length - 1] == '\0';}                            /* replace \n */
    }
    I get a host of errors:

    Code:
    Compiler: Default compiler
    Executing  gcc.exe... 
    In function `input':
    106: warning: passing arg 1 of `get_input' makes integer from pointer without a cast
    106: error: incompatible type for argument 2 of `get_input'
    At top level:
    111: error: syntax error before '*' token
    In function `get_input':
    112: error: number of arguments doesn't match prototype
    30: error: prototype declaration
    118: error: `prompt' undeclared (first use in this function)
    118: error: (Each undeclared identifier is reported only once
    118: error: for each function it appears in.)
    119: error: `input_ptr' undeclared (first use in this function)
    119: warning: assignment makes integer from pointer without a cast
    
    Execution terminated
    I've been fiddling with this for a while and I really need a little bit of interpretation to understand what's causing these warnings/errors. I'm new to pointers so please go easy on me. Thank you again for the good advice.

    -SH
    Last edited by SiliconHobo; 12-02-2007 at 05:50 AM.

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    No wonder. You're not getting the hang of the syntax. A couple of tutorials might be in place. Especially functions and pointers:
    Functions: http://www.cprogramming.com/tutorial/c/lesson4.html
    Pointers: http://www.cprogramming.com/tutorial/c/lesson6.html

  11. #11
    Registered User
    Join Date
    Nov 2007
    Posts
    26
    Okay. I read them but no light bulbs are coming on atm. If I could understand the errors that would probably help. The only one I'm familiar with is the undeclared variables error but I don't see why I'm getting it since the stated variables are declared as parameters in get_input.
    Last edited by SiliconHobo; 12-02-2007 at 06:04 AM.

  12. #12
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Chappell Hill, Texas
    Posts
    2,332
    OK, let's go over function declarations, function calls and function definitions. The summary of all this will be that they have to match.

    Your declaration is this:
    Code:
    int get_input (char, contact);
    This says you are passing, by value, a single one byte characters, and a contact datatype (whatever that is - it doesn't really matter).

    For function call is this:
    Code:
    get_input (prompt1, &input_ptr->name);
    So, at run time, you will pass a copy of prompt1, which is the address of a char[25] array, and the address of the name field of the structure pointed to by input_ptr.

    You've scored 0 for 2 so far.

    Now, your function definition says this:
    Code:
    int get_input (prompt, *input_ptr)
    Not even close. You have to supply a data type for both parms, and you haven't specified a data type for either.

    3 strikes - you are out. (Actually, more bugs than that - but I won't dwell on something you don't understand with too critical an eye.)

    Now, Going back to my first point that the function declaration, function call and function definition have to match. You need to decide if you want pass parms by value or by reference. Here's an example of the differences between the two.

    Call by value: You tell the compiler to make a copy (essentially) of whatever variable you want to pass to a function. The compiler (well, it's not actually the "compiler", but the code generated BY the compiler - but I'll call it the compiler for discussion purposes) will make a copy of the "value" and place it on the stack. When the function gets control, it uses the copy of the value and cannot touch the original value. Here's a commented example:

    Code:
    #include <stdio.h>
    
    int myfunc(char) ;  // function declaration 
    
    int main() { 
    
    	char mychar = 'Z' ; 
    	int rc  ; // return code 
    	
    	// mychar will be Z 
    	printf("main: before myfunc() call, mychar = &#37;c\n", mychar) ; 
    
    	// Call myfunc(), using a call be value syntax.  A copy of the 
    	// actual value of mychar will be placed on the stack.  myfunc() will
    	// never have access to the original mychar variable.  
    	rc = myfunc(mychar) ;   // function call 
    	
    	// Print out the value of mychar.  It will still be Z, because 
    	// function myfunc() changed the copy of mychar that was placed 
    	// on the stack.   This now proves that function myfunc() did not 
    	// use the original value of mychar - it only changed a temporary 
    	// copy of it that was on the stack. 
    	printf("main: after myfunc() call, mychar = %c\n", mychar) ; 
    
    	return 0 ; 
    } 
    
    int myfunc(char xxx) {   // function definition 
    	// report the incoming value. 
    	printf("xxx should be Z, and it is: %c \n", xxx ) ; 
    
    	// Change variable xxx to a new value.
    	xxx = 'H' ; 
    
    	// This shows that the value was changed. 
    	printf("xxx should be H, and it is: %c \n", xxx) ; 
    	return 0 ; 
    }
    Maybe the most important thing to point out from the above example is that the function myfunc() cannot change the calling routine's variable in a call-by-value scenario.

    Call by reference: Let's change our example just a little now to a call-by-reference call. We need to use a pointer variable and change our function declaration, call and definition. The primary differences are in red.

    Code:
    #include <stdio.h>
    
    int myfunc(char *) ;  // function declaration 
    
    int main() { 
    	char mychar = 'Z' ; 
    	char * myptr ; 
    	int rc  ; // return code 
    
    	myptr = &mychar ;   // Initialize myptr pointer to the address of mychar.
    
    	// mychar will be Z 
    	printf("main: before myfunc() call, mychar = %c\n", mychar) ; 
    	printf("main: before myfunc() call, myptr  = %p\n", myptr) ; 
    
    	// Call myfunc(), using a call be reference scheme.  The pointer to the 
    	// actual value of mychar will be placed on the stack.  myfunc() can 
    	// now access the original mychar variable.  
    	rc = myfunc(myptr) ;  // function call  
    	
    	// Print out the value of mychar.  We passed a pointer to mychar, 
    	// and function myfunc() changed the value of it through indirection. 
    	printf("main: after myfunc() call, mychar = %c\n", mychar) ; 
    	printf("main: after myfunc() call, myptr  = %p\n", myptr) ; 
    
    	return 0 ; 
    } 
    
    int myfunc(char * xxx) { // function definition 
    	// report the incoming value. 
    	printf("xxx value should be Z, and it is: %c \n", *xxx ) ; 
    	printf("xxx pointer is is: %p \n", xxx ) ; 
    
    	// Through pointer xxx, variable the value to a new value.
    	*xxx = 'H' ; 
    
    	// This shows that the value was changed. 
    	printf("xxx value should be H, and it is: %c \n", *xxx) ; 
    	return 0 ; 
    }
    Now, let's focus on another aspect of getting all three (function declaration, call and definition) to match - the return value.

    Here's the first example repeated to focus on the the return type.
    Code:
    #include <stdio.h>
    
    int myfunc(char) ;  // function declaration 
    
    int main() { 
    
    	char mychar = 'Z' ; 
    	int rc  ; // return code  
    	
    	// mychar will be Z 
    	printf("main: before myfunc() call, mychar = %c\n", mychar) ; 
    
    	// Call myfunc(), using a call be value syntax.  A copy of the 
    	// actual value of mychar will be placed on the stack.  myfunc() will
    	// never have access to the original mychar variable.  
    	rc = myfunc(mychar) ;   // function call 
    	
    	// Print out the value of mychar.  It will still be Z, because 
    	// function myfunc() changed the copy of mychar that was placed 
    	// on the stack.   This now proves that function myfunc() did not 
    	// use the original value of mychar - it only changed a temporary 
    	// copy of it that was on the stack. 
    	printf("main: after myfunc() call, mychar = %c\n", mychar) ; 
    
    	return 0 ; 
    } 
    
    int myfunc(char xxx) {   // function definition 
    	// report the incoming value. 
    	printf("xxx should be Z, and it is: %c \n", xxx ) ; 
    
    	// Change variable xxx to a new value.
    	xxx = 'H' ; 
    
    	// This shows that the value was changed. 
    	printf("xxx should be H, and it is: %c \n", xxx) ; 
    	return 0 ; 
    }
    Declaration: For myfunc(), the return type of int is declared in the function declaration.
    Definition: myfunc() repeats the same "declaration" again in the definition, stating it will return an int value. And, indeed, it issues a return 0 ; before it exits.
    Call: When called, the call needs to do something with int that is returned from the call to myfunc(). It does this by assigning the value to the variable rc. Again, all threes match.

    Also, note the green code above. The exact same thing is being done for main() - we just don't have a function declaration for main().

    Hope this helps.

    Todd
    Last edited by Dino; 12-02-2007 at 04:08 PM.

  13. #13
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Syntax for function are as following (see Todd's example too of course):
    Declarations:

    Code:
    ReturnType FunctionName(ArgumentType ArgumentName, ArgumentType2 ArgumentName2);
    ReturnType is what type you want the function to return, FunctionName is the name of your function that you'll use to call it, ArgumentType is the type of argument you want the function to accept and ArgumentName is the name by which you'll access that varaible.
    Function definition is the same:

    Code:
    ReturnType FunctionName(ArgumentType ArgumentName, ArgumentType2 ArgumentName2)
    {
    /* Your code here */
    }
    Your delcaration and definition MUST match. The declarations tell the compiler that your function exists. If your declaration and definition mismatch, you'll get a compiler error or linker error.

    This should also help.

  14. #14
    Registered User
    Join Date
    Nov 2007
    Posts
    26
    Okay, thanks Todd and Elysia for the detailed explanation. I've simplified the program and I believe my declaration, call and function now match.

    Code:
    char get_input (char[26]);
    Code:
    get_input (prompt1);
    Code:
    char get_input (char prompt[26])
    I have changed the return type to char so I can get the string in get_input and then return it to the calling function which can assign it to the appropriate place in the structure. This is what I've written:

    Code:
    contact input ()                                                /* gets an entry from the user */
    {
         contact entry = {'\0','\0','\0','\0','\0','\0','\0','\0'}; /* initializes the structure   */
         char prompt1[26] = "Please enter a new name.";
         char prompt2[26] = "Enter a street address.";
         char prompt3[26] = "Enter a city.";
         char prompt4[26] = "Enter a province.";
         char prompt5[26] = "Enter a post code.";
         char prompt6[26] = "Enter a country.";
         char prompt7[26] = "Enter a date of birth.";
         char prompt8[26] = "Enter a phone number.";
         char prompt9[26] = "Enter an email address.";
    
         entry.name = get_input (prompt1);
         entry.add.street = get_input (prompt2);
         entry.add.city = get_input (prompt3);
         entry.add.state = get_input (prompt4);
         entry.add.post = get_input (prompt5);
         entry.add.country = get_input (prompt6);
         entry.birth = get_input (prompt7);
         entry.phone = get_input (prompt8);
         entry.email = get_input (prompt9);
         
         return (entry);
    }
    
    char get_input (char prompt[26])
    {
         char string [50] = {0};
         char junk = 0;
         int length;
         
                    do{
                    printf ("\n%s\n\n>", prompt);
                    fgets(string, sizeof(string), stdin);   
                        if ( strchr(string, '\n') == NULL ){         /* if overflow */
                        printf ("\nYour entry is too long, please try again.\a");
                        while((junk = getchar()) != '\n' && junk != EOF);
                        string[0] = '\0';
                        }
                    } while (string[0] == '\0' || string[0] == '\n');
         length = strlen (string);             
         if (string[length - 1] == '\n'){
             string[length - 1] == '\0';}                            /* replace \n  */
         return (string);
    }
    I'm getting "incompatible types in assignment" error on the lines that call get_input. What is the correct way to plug the returned string into the contact structure?

    Code:
    typedef struct address_tree             /* address sub-strcuture */
    {
           char street[50];
           char city[50];
           char post[50];
           char state[50];
           char country[50];
    }address;   
    
    typedef struct top_tree                 /* top-level database structure */
    {
           char name[50];
           char email[50];
           char birth[50];
           char phone[50];
           address add;
    }contact;
    Also, is there any practical advantage to using a nested structure here? I just just did it to learn how they work. Thanks for reading.

  15. #15
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    There is definetly an advantage - to your program's layout. It would make sense to have your address with all the other information. And making a struct out of that can also be helpful.
    For your error, you declare return type as char but you return char* (just for reference, returning an array for sort automatically casts it to a pointer, so a char array becomes char*).
    What is the solution? There are several, but the one that's most recommended is that get_input takes a char* argument to a buffer to fill. And it should take a size argument too, to make sure that it doesn't input more data than space available in the buffer.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Undefined Reference Compiling Error
    By AlakaAlaki in forum C++ Programming
    Replies: 1
    Last Post: 06-27-2008, 11:45 AM
  2. dllimport function not allowed
    By steve1_rm in forum C++ Programming
    Replies: 5
    Last Post: 03-11-2008, 03:33 AM
  3. Replies: 3
    Last Post: 03-04-2005, 02:46 PM
  4. c++ linking problem for x11
    By kron in forum Linux Programming
    Replies: 1
    Last Post: 11-19-2004, 10:18 AM
  5. Contest Results - May 27, 2002
    By ygfperson in forum A Brief History of Cprogramming.com
    Replies: 18
    Last Post: 06-18-2002, 01:27 PM