Thread: Passing Structures as Function Arguments

  1. #1
    Registered User
    Join Date
    Mar 2012
    Posts
    26

    Question Passing Structures as Function Arguments

    Hi. I'm having a problem with passing structures as function arguments. Pay particular attention to the definitions of the functions (lines 29 and 56). Upon compilation I always get these kinds of errors:

    error: expected ‘)’ before ‘STRUCT_Users’

    Where am I going wrong?

    Code:
    main() {
    
    
        typedef struct {
            char OrigCurr[4];
            char WantCurr[4];
            float ExRate;
        } DATATYPE_Rates;
        
        typedef struct {
            char User[31];
            char Pass[31];
            char Role[14];
        } DATATYPE_Users;
        
        DATATYPE_Rates STRUCT_Rates[100];
        DATATYPE_Users STRUCT_Users[100];
           
        int TXTDATA_Read_Rates();
        int TXTDATA_Read_Users();
    
        FILE *STREAM_Rates, *STREAM_Users;
    
        TXTDATA_Read_Rates(&STRUCT_Rates, &STREAM_Rates, &COUNT_Struct_Rates);
        TXTDATA_Read_Users(&STRUCT_Users, &STREAM_Users, &COUNT_Struct_Users);
    
    }
    
    int TXTDATA_Read_Rates(DATATYPE_Rates *a, FILE **STREAM_Rates, int *COUNT_Struct_Rates) {
        
        char FloatVal[99];
        int i;
        
        *STREAM_Rates = fopen("rates.txt", "rt");
        
        if (*STREAM_Rates == NULL)
            printf("  [Error!] \"rates.txt\" does not exist.");
        
        for (i = 0; !feof(*STREAM_Rates); i++) {
            
            fscanf(*STREAM_Rates, "%[^\t\n]\n", a[i].OrigCurr);        
            fscanf(*STREAM_Rates, "%[^\t\n]\n", a[i].WantCurr);        
            fscanf(*STREAM_Rates, "%[^\t\n]\n", FloatVal);
            a[i].ExRate = atof(FloatVal);
            
        }
        
        *COUNT_Struct_Rates = i;
    
    
        return *COUNT_Struct_Rates;
        
    }
    
    
    int TXTDATA_Read_Users(DATATYPE_Rates STRUCT_Users, FILE **STREAM_Users, int *COUNT_Struct_Users) {
        
        int i;
        
        *STREAM_Users = fopen("CA_users.txt", "rt");
        
        if (*STREAM_Users == NULL)
            printf("  [Error!] \"CA_users.txt\" does not exist.");
        
        for (i = 0; !feof(*STREAM_Users); i++) {
            
            fscanf(*STREAM_Users, "%[^\t\n]\n", STRUCT_Users[i].User);
            fscanf(*STREAM_Users, "%[^\t\n]\n", STRUCT_Users[i].Pass);
            fscanf(*STREAM_Users, "%[^\t\n]\n", STRUCT_Users[i].Role);
            
        }
        
        *COUNT_Struct_Users = i;
        
        return *COUNT_Struct_Users;
    
    
    }

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    1. Move your typedef's outside main. As written, you've limited the scope of the typedef's to main().

    2. Make your function prototypes the same as the function definition.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Mar 2012
    Posts
    26
    1. But I thought creating objects on a global scale is usually a bad idea? Or does that not apply to structures? Is there a way to still have the structures exclusively inside main() and still be able to pass them into functions?

    2. Right, my function prototypes need work.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Lines 4 to 14 are types.
    You don't create any data storage at this point.

    Lines 16 and 17 are instances of those types.
    These allocate some actual space. It's generally a good idea to restrict the scope of data to the narrowest scope which makes sense.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    You should move the typedefs and function prototypes outside of main. These are not global "objects" but declarations of types.

    For function TXTDATA_Read_Users:
    The first formal parameter should be a pointer (you're missing the asterisk). Also, if you want to access members User, Pass, Role, then presumably it should be DATATYPE_Users not DATATYPE_Rates.

    And you're missing two variables: COUNT_Struct_Rates and COUNT_Struct_Users.

    Also, when you call your two functions, don't use the ampersand in front of the first parameters. They are already pointers.
    Last edited by oogabooga; 03-23-2012 at 10:19 AM.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  6. #6
    Registered User
    Join Date
    Mar 2012
    Posts
    26
    Alright, so I have to put the following outside of main: typedef structs, and function prototypes. What about lines 16-17?

  7. #7
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    These
    Code:
        DATATYPE_Rates STRUCT_Rates[100];
        DATATYPE_Users STRUCT_Users[100];
    can stay in main. They will be allocated on main's stack and passed (as pointers) to their respective functions.

    Other points:
    There's (apparently) no reason for you to be passing in the FILE*'s. Declare them locally in the functions.
    You should close your files at the end of those functions.
    main should be declared as int main(void) and should have a return 0; as it's last line.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  8. #8
    Registered User
    Join Date
    Mar 2012
    Posts
    26
    @oogabooga: Regarding the files. I plan on closing them in another function (which I've not yet written). So that's why I want to have them in int main();, so I can pass the FILE*s and close them.

  9. #9
    Registered User claudiu's Avatar
    Join Date
    Feb 2010
    Location
    London, United Kingdom
    Posts
    2,094
    Quote Originally Posted by Jyqft View Post
    @oogabooga: Regarding the files. I plan on closing them in another function (which I've not yet written). So that's why I want to have them in int main();, so I can pass the FILE*s and close them.
    Well yeah but it's not a bad idea to close them in the meantime as well. That's like saying, I will leave this stove on and will come back to it and turn it off after I have cooked my main meal on this other stove.
    1. Get rid of gets(). Never ever ever use it again. Replace it with fgets() and use that instead.
    2. Get rid of void main and replace it with int main(void) and return 0 at the end of the function.
    3. Get rid of conio.h and other antiquated DOS crap headers.
    4. Don't cast the return value of malloc, even if you always always always make sure that stdlib.h is included.

  10. #10
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Quote Originally Posted by Jyqft View Post
    Regarding the files. I plan on closing them in another function
    Why?

    The more one looks, the more errors one finds:
    • If the file does not exist, don't print an error message AND THEN continue with normal processing.
    • You're not checking for end-of-file properly.
    • You are both setting a passed in value (through a pointer) AND returning the value. Just return it, since it looks like there's no reason to pass it in.
    • You're not setting COUNT_Struct_Rates and COUNT_Struct_Users.
    • And if you tell us what your data looks like there might be a better way to read it.

    To sum up:
    You've written more than you should have without stopping to test it.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  11. #11
    Registered User
    Join Date
    Mar 2012
    Posts
    26
    @claudiu: Fair enough.

    @oogabooga:
    1. Regarding handling of the file's existence: I'm not sure how to interrupt normal processing. What do you think should I do?
    2. Regarding EOF checking: How so?
    3. Regarding passing AND returning: Point. I was actually wondering how come no one pointed that out (until now). But if I choose to return only, should I simply equate the COUNT variables to the function in int main();?
    4. Regarding Setting the COUNT variables: But if you check the TXTDATA functions, I set them to i. Would it matter if I didn't set them to 0 at first?
    5. Umm I'm not sure what you mean. But this is, after all, a fragment of my source code. The objective of the program I'm writing is to deal with currencies, if that helps.

    By the way, I have stopped to test my code. It just so happens that my organization is pretty lousy...
    Last edited by Jyqft; 03-23-2012 at 11:05 AM.

  12. #12
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    1.
    Code:
    FILE *fp = fopen("file.dat", "r");
    if (!fp) {
        fprintf(stderr, "Can't open file.dat\n");
        exit(1);  // exit the program (returning 1 to the OS)
    }
    // ...
    fclose(fp);
    2.
    Code:
    int rv; // fscanf returns the number of values it reads
    while (1) {
        rv = fscanf(fp, "%d", &n[i].x);
        if (rv != 1) break;
        rv = fscanf(fp, "%d", &n[i].y);
        if (rv != 1) break;
        i++;
    }
    3. Yes.
    4. Just return i from the functions and define and equate the COUNT vars to them in main.
    5. You don't understand what it means to describe the format of your data? Never mind then.

    So your function prototypes should just be
    Code:
    int TXTDATA_Read_Rates(DATATYPE_Rates *a);
    int TXTDATA_Read_Users(DATATYPE_Users *STRUCT_Users);
    (although a is not a very good name).
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  13. #13
    Registered User
    Join Date
    Mar 2012
    Posts
    26
    I'm down with this:

    Code:
    int TXTDATA_Read_Rates(DATATYPE_Rates *STRUCT_Rates) {
        
        char FloatVal[99];
        int i;
        
        FILE *STREAM_Rates;
        
        STREAM_Rates = fopen("rates.txt", "rt");
        
        if (STREAM_Rates == NULL) {
            printf("[Error!] \"rates.txt\" does not exist.\n");
            exit(1);
        }
        
        for (i = 0; !feof(STREAM_Rates); i++) {
            
            fscanf(STREAM_Rates, "%[^\t\n]\n", STRUCT_Rates[i].OrigCurr);        
            fscanf(STREAM_Rates, "%[^\t\n]\n", STRUCT_Rates[i].WantCurr);        
            fscanf(STREAM_Rates, "%[^\t\n]\n", FloatVal);
            STRUCT_Rates[i].ExRate = atof(FloatVal);
            
        }
        
        fclose(STREAM_Rates);
        return i;
        
    }
    
    
    int TXTDATA_Read_Users(DATATYPE_Users *STRUCT_Users) {
        
        int i;
        
        FILE *STREAM_Users;
                
        STREAM_Users = fopen("CA_users.txt", "rt");
            
        if (STREAM_Users == NULL) {
            printf("[Error!] \"CA_users.txt\" does not exist.\n");
            exit(1);
            
        }    
        
        for (i = 0; !feof(STREAM_Users); i++) {
            
            fscanf(STREAM_Users, "%[^\t\n]\n", STRUCT_Users[i].User);
            fscanf(STREAM_Users, "%[^\t\n]\n", STRUCT_Users[i].Pass);
            fscanf(STREAM_Users, "%[^\t\n]\n", STRUCT_Users[i].Role);
            
        }
        
        fclose(STREAM_Users);
        return i;
        
    }
    But it gives me Segmentation fault 11. What am I doing wrong now?

    EDIT: Never mind, another part of the code was causing the problem.
    Last edited by Jyqft; 03-23-2012 at 10:12 PM.

  14. #14
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    This is probably what oogabooga was referencing:
    Code:
    int TXTDATA_Read_Rates(DATATYPE_Rates *STRUCT_Rates) {
         
        char FloatVal[99];
        int i;
         
        FILE *STREAM_Rates;
    
        ...
    
        for (i = 0; !feof(STREAM_Rates); i++) {
             
            fscanf(STREAM_Rates, "%[^\t\n]\n", STRUCT_Rates[i].OrigCurr);       
            fscanf(STREAM_Rates, "%[^\t\n]\n", STRUCT_Rates[i].WantCurr);       
            fscanf(STREAM_Rates, "%[^\t\n]\n", FloatVal);
            STRUCT_Rates[i].ExRate = atof(FloatVal);
             
        }
         
        ...
         
    }
     
     
    int TXTDATA_Read_Users(DATATYPE_Users *STRUCT_Users) {
         
        int i;
         
        FILE *STREAM_Users;
    
        ...
         
        for (i = 0; !feof(STREAM_Users); i++) {
             
            fscanf(STREAM_Users, "%[^\t\n]\n", STRUCT_Users[i].User);
            fscanf(STREAM_Users, "%[^\t\n]\n", STRUCT_Users[i].Pass);
            fscanf(STREAM_Users, "%[^\t\n]\n", STRUCT_Users[i].Role);
             
        }
      
        ...
    
    }
    You should not use an EOF test to control your loops.

    Read: FAQ > Why it's bad to use feof() to control a loop

    The link uses a while(!feof(stream)) loop to demonstrate what's wrong however your for loop is basically doing the same thing.

    There are different ways of handling this, you've been shown one way. Another way would be to consider that you are reading three values in the body of the loop with three individual fscanf calls. Your for loop should be making a single fscanf call reading in three values and testing that 3 values were scanned. Your loop should also make sure that i is less than 100 before you attempt to read data into an array index that might not be valid.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Help passing arguments to function
    By HAssan in forum C Programming
    Replies: 2
    Last Post: 11-26-2007, 02:15 PM
  2. Passing arguments to another function
    By Wiretron in forum C Programming
    Replies: 2
    Last Post: 12-24-2006, 05:57 AM
  3. need function help, passing arguments
    By infernosnow in forum Game Programming
    Replies: 18
    Last Post: 07-18-2006, 02:45 AM
  4. Structures, passing array of structures to function
    By saahmed in forum C Programming
    Replies: 10
    Last Post: 04-05-2006, 11:06 PM
  5. Passing arguments to function...
    By alvifarooq in forum C++ Programming
    Replies: 8
    Last Post: 09-24-2004, 12:50 PM

Tags for this Thread