Array Of Structures Issues

Discussion in 'Mac Programming' started by SkippyThorson, Apr 30, 2010.

  1. SkippyThorson macrumors 65816

    SkippyThorson

    Joined:
    Jul 22, 2007
    Location:
    Utica, NY
    #1
    Oh, the problems run vast and numerous on this one. The idea for this one is to take a text file, with information of 3 cars on 3 lines, and put it into 3 like structures. (I have also included that text file - and no, information doesn't make sense, but that's what the instructor wrote and wants us to use.)

    This program doesn't run - it's not complete - it's what I have this far. I know what I want to have done: I want to take said text file, and read in, one line at a time, the information for the 3 structures, and then print the 3 of them out to the screen. The problem here is we've gone beyond the book, to take a look at the next class' material since we're just about done, and we don't have much information to build off of.

    Any reading material that may be beneficial to me? Any words of wisdom or slaps to the head?

    (Like I said, I only posted what I've come up with so far. It's more like random notes to show you at least what I have vs what I don't.)

    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <ctype.h>
    
    typedef struct auto_t{
    	char make[15]; char model[30];
    	int mmon; int mday; int myear;
    	int pmon; int pday; int pyear;
    	float fuelcap; float fuellevel;
    	float odometer;
    } vehicles[3];
    
    //xxxxxxxxxxxxxxxxxxxxxxxxxMAINxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    int main(void)
    {	
    	//int readCar(vehicles*, FILE*);
    	//vehicles V;
    	//int i = 0;
    	//int itemsread;
    	//FILE *cfPtr;
    	void getinfo(auto_t*);
    	void printit(auto_t);
    	auto_t a1, a2, a3;
    	
    	}
    	return 0;
    }
    
    //xxxxxxxxxxxxxxxxxxxxxxFUNCTIONxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    
    void getinfo (auto_t *Pup)
    {
    	int n;
    	int i = 0;
    	char c;
    	int size;
    	
    	if((cfPtr = fopen("cars.txt", "r")) == NULL)
    		printf ("ERROR: NOT FOUND.\n");
    	else
    	{
    		while(!feof(cfPtr))
    		{
    			itemsread = readCar (&V, cfPtr);
    			printf ("%s %s\n", V[i].make, V[i].model);
    			printf ("%i %i %i\n", V[i].mmon, V[i].mday, V[i].myear);
    			printf ("%i %i %i\n", V[i].pmon, V[i].pday, V[i].pyear);
    			printf ("%f %f\n", V[i].fuelcap, V[i].fuellevel);
    			printf ("%f\n", V[i].odometer);
    		}
    		fclose(cfPtr);
    	}
    }
    
    In the cars.txt file:
     

    Attached Files:

    • cars.txt
      File size:
      143 bytes
      Views:
      103
  2. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #2
    I would have a routine that either takes a pointer to a single struct, or that returns a single struct. This should also take the line of input to be parsed. Then in another function you can loop, reading from the file and calling this function for each line. This could take an array of the structs. Then there can be a function that takes the array and element count to display the values.

    -Lee
     
  3. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #3
    A typedef for an array is asking for trouble. There are some special rules for arrays, especially for parameters, that tend to hurt anyone's brain. I'd use

    typedef struct { ... } auto_t;

    and go with that.
     
  4. jared_kipe macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #4
    Agreed, for instance, it makes it harder to "grow" the program. Like for example if you didn't know in advance how big the file you were parsing is going to be. Just typedef the struct, and then have a variable be an array of the structs.
     
  5. lloyddean macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #5
    SkippyThorson, I hate to sound like a broken record but, could you post the exact wording of your assignment?
     
  6. pilotError macrumors 68020

    pilotError

    Joined:
    Apr 12, 2006
    Location:
    Long Island
    #6
    Your basically on the right track.

    You've already defined the array of cars, you just need to be careful of what your passing to the various functions.

    So if your function is an auto_t *, when you pass &vehicles to the function, you should realize the entire array is passed, not just the first element.

    For instance, when you call getInfo(&vehicles), you are sending the address of the first struct in the array.

    you can create a second pointer

    auto_t * vPtr = Pup;

    then in the loop, use the pointer. Your still trying to use the array even though you've defined the functions to pass just a pointer to the array.

    So printing an element would pretty much be

    printf ("%s %s\n", vPtr->make, vPtr->model);

    to get to the next struct, its simply

    vPtr++

    I would do the following, create a readCar function that fills the array, then call the getInfo function that loops through the array. The reason being, you don't have to pass a pointer to a pointer to the ReadCar function.

    So your main would look more like this

    Code:
    int main(void)
    {	
    	readCar(&vehicles);
    	printit(&vehicles);
    
    	return 0;
    }
    
    int readCar(auto_t * Pup)
    {
    	File * carFile;
    
    	...
    }
    
    int printit(auto_t * Pup)
    {
    	auto_t *vPtr = Pup;
    
    	while (NULL != *vPtr++) {
    		printf ("%s %s\n", vPtr->make, vPtr->model);
    		...
    	}
    }
    

    Just add the appropriate error checking (if the file doesn't open, return say a 1 from readCar and check the return value in main.

    There's some blaring unspoken stuff in the code I posted, but your getting there. By splitting the functions, your focusing on one thing at a time.

    readCar will open the file and populate the array.

    1. Get the fopen to work. Wrap it with error checking and returning the error.
    2. Do the scanf or however you want to parse each of the lines in the file.
    3. Figure out how to populate the structure pointer (do one variable at a time)

    Just break it down into manageable tasks and you'll be fine.

    Post your questions in the thread for anyone in the future and we'll try and guide you without doing it for you.
     
  7. SkippyThorson thread starter macrumors 65816

    SkippyThorson

    Joined:
    Jul 22, 2007
    Location:
    Utica, NY
    #7
    :p No problem. You're the ones offering to help me. Whatever you'd like.

    The data on the cars from the first post is the external file we were told to use:
     
  8. lloyddean macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #8
    I see no requirement, nor even mention, of an array of the user defined data-type 'auto_t'.

    And the driver code must open the file and call 'scan_auto' to read (from the opened file) data filling in an 'auto_t'.

    If the read of a single record does not return an EOF call 'print_auto' passing in the 'auto_t' filled in by the call to 'scan_auto'.

    Repeat.
     
  9. SkippyThorson thread starter macrumors 65816

    SkippyThorson

    Joined:
    Jul 22, 2007
    Location:
    Utica, NY
    #9
    Another case of we only learned her way; when multiples of same structure are to be used, just make the one there an array of whatever number needed.

    Decided to go with the wisdom here, and I eliminated the array. This is still not done, and I would treat it as progress. It does not compile still.

    This is something along the lines of what you were referring to, I believe:

    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <ctype.h>
    
    typedef struct {
    	char make[15]; char model[30];
    	int mmon; int mday; int myear;
    	int pmon; int pday; int pyear;
    	float fuelcap; float fuellevel;
    	float odometer;
    } auto_t;
    
    FILE *cfPtr;
    int i = 0;
    
    //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxMAINxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    int main(void)
    {
    	
    	printf ("Welcome.\n");
    	void scan_auto(auto_t*);
    	void printit(auto_t);
    	printf ("Thank you.\n");
    	
    	return 0;
    }
    
    //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxSCAN_AUTOxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    scan_auto (*auto_t);
    {
    	for(i = 0; i < 3; i++)
    	{
    		if((cfPtr = fopen("cars.txt", "r")) == NULL)
    			printf ("ERROR: NOT FOUND.\n");
    			else
    			{
    				while(!feof(cfPtr))
    				{
    					scanf ("%s %s\n", (*auto_t[i]).make, (*auto_t[i]).model);
    					scanf ("%i %i %i\n", (*auto_t[i]).mmon, (*auto_t[i]).mday, (*auto_t[i]).myear);
    					scanf ("%i %i %i\n", (*auto_t[i]).pmon, (*auto_t[i]).pday, (*auto_t[i]).pyear);
    					scanf ("%f %f\n", (*auto_t[i]).fuelcap, (*auto_t[i]).fuellevel);
    					scanf ("%f\n", (*auto_t[i]).odometer);
    					void print_auto (auto_t)
    				}
    				fclose(cfPtr);
    			}
    	}
    }
    
    //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxPRINT_AUTOxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    void print_auto (auto_t);
    {
    	if((cfPtr = fopen("cars.txt", "r")) == NULL)
    		printf ("ERROR: NOT FOUND.\n");
    		else
    		{
    			while(!feof(cfPtr))
    			{
    				printf ("%s %s\n", auto_t[i].make, auto_t[i].model);
    				printf ("%i %i %i\n", auto_t[i].mmon, auto_t[i].mday, auto_t[i].myear);
    				printf ("%i %i %i\n", auto_t[i].pmon, auto_t[i].pday, auto_t[i].pyear);
    				printf ("%f %f\n", auto_t[i].fuelcap, auto_t[i].fuellevel);
    				printf ("%f\n", auto_t[i].odometer);
    			}
    			fclose(cfPtr);		
    		}
    }
    
     
  10. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #10
    I am concerned about the text your using and your instructor. auto_t is a type, so you need to declare a variable (or maybe an array?) of that type. If you DID want to pass the address of a variable, you'd use & in front of the variable you were getting the address of. This is just like every unary operator.

    Once you've declared a thing that includes auto_t, then you can pass it to your functions as-is. When a function takes type* as it's parameter it could be accepting a single one of this type via pointer OR it could be taking an array to that type.

    I would still break down your input function into a function that reads your file, which passes each line to another function that parses the line and either accepts a structure pointer and fills it in, or returns a structure.

    -Lee
     
  11. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #11
    It doesn't compile because you have lots of simple syntax errors. You also have much more serious logic errors, such as the print_auto() function.

    Frankly, this looks like you're trying to design the program by coding it. That approach almost never works, except for trivial problems.

    You need to design the program first, then flesh out the design with code.

    Design involves thinking things through, writing them down, and confirming that they match the specification. I suggest pseudocode in the "structured English" mold.
    http://en.wikipedia.org/wiki/Structured_English
    http://en.wikipedia.org/wiki/Pseudocode

    Example of one possible design:
    Code:
    Driver function
    main()
    - takes no command-line args
    - reads a file from a hard-wired pathname
    - open file
    - loop: 
    -- pass file to scan_auto() to get an auto_t
    -- check for EOF (how is EOF signalled here??)
    -- pass auto_t to print_auto() to print it
    - close file
    - exit
    - Unresolved decisions:
    -- how is EOF signalled?
    -- how is parse error signalled?
    -- is auto_t passed by pointer, or is struct itself passed?
    
    Functions of interest:
    scan_auto()
    - takes a file (pointer? stdio's FILE*?).
    - read one line
    - if EOF, return a unique indicator to caller
    - parse line into a single auto_t  (which scanf function?)
    - if parse fails (e.g. too little data), return failure
    - return single auto_t
    - Unresolved decisions:
    -- how is EOF signalled?
    -- how is parse error signalled?
    -- what parse errors?  e.g.: insufficient data, not a number, negative number
    
    print_auto()
    - takes one auto_t (pointer? or struct passing?).
    - print values to stdout
    - Unresolved decisions:
    -- precision of numbers?
    -- columnar alignment by spaces, or tab-separated?
    
    This example is more of an outline than structured English. However, it's accurate and detailed enough that a programmer could write code, and every one of the design statements could be a comment in the resulting code. In fact, one could paste the outline text into a .c file, add // and {} in appropriate places, and have the first compilable code. It would do nothing, but it would compile.

    Only after a design is written down should one start coding. The design must be accurate and reasonably detailed.

    The first code written should do nothing, but must accurately reflect the functions. It must compile perfectly, but when run it need do nothing at all. It may call printf() to show it ran.

    Next, the parameters to all functions must be defined correctly, both in type and position (stub functions). Again, it must compile, but do nothing when run.

    Next, fill in the main driver loop's code, and have it correctly call all functions. The functions should still do nothing, but can return hard-wired data (e.g. unvarying values assigned to the members of an auto_t struct) appropriate to their return type. All signalling of EOF conditions must work.

    You will probably have to write a stub scan function that returns a random number of auto_t's, then returns the EOF signal. DO NOT assume that there is exactly 3 lines of data. The spec calls for reading to EOF, not reading exactly 3 items.

    The reason for writing the driver loop first, and running it, is that you will need it to test the other functions. If your other functions are perfect, but there's no way to test them, then you haven't tested them, so how do you know they're perfect? I

    Next, make the print function work. It should correctly output the hard-wired data being returned by the scan function.

    Finally, make the scan function work.


    Note that I have outlined both a design for the program, and a process for turning that design into a working program. Also notice that your current approach is almost exactly backwards from this process. You're writing code without a clear design. As a result, your print function is hopelessly wrong (why is it re-reading the file?), and none of your code compiles. Your scan function is also wrong, because it's assuming 3 items, it's using the wrong scanf function, and other problems.
     
  12. lloyddean macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #12
    Let's break your assignment quote into several sections.

    1 Define a structure type auto_t to represent an automobile.

    Code:
    	struct auto_tag
    	{
    		... remember to fill in required fields
    	};
    	
    	typedef struct auto_tag		auto_t;
    	typedef auto_t*				auto_ptr;
    
    2 Include components for the make and model (strings), the odometer reading, the manufacturer and purchase dates, a component for tank capacity and current fuel level, giving both in gallons.

    Code:
    	struct auto_tag
    	{
    		char    make[15];
    		char    model[30];
    		
    		int     mmon;			// manufactor date - month
    		int     mday;			// manufactor date - day
    		int     myear;			// manufactor date - year
    		
    		int     pmon;			// purchase date - month
    		int     pday;			// purchase date - day
    		int     pyear;			// purchase date - year
    		
    		// could also be done using 'unsigned long int', should never be negative
    		float   fuelcap;		// fuel tank capacity (tank capacity in US gallons)
    		float   fuellevel;		// fuel tank level (tank level in US gallons)
    		
    		float   odometer;		// current milage (since we're using US gallons why not!)
    	};
    	
    	typedef struct auto_tag		auto_t;
    	typedef auto_t*				auto_ptr;
    
    3 Write I/O functions scan_auto and print_auto, and also write a driver function that repeatedly fills and displays an auto_t structure variable until EOF is encountered in the external input file. Be sure to use an external file.

    Code:
    	scan_auto()
    	print_auto()
    	int main()
    
    We can further refine these function based on the description given in item 3.

    'main' is our "driver".

    We're to REPEATEDLY fill in an 'auto_t' data type, from the contents of an external file, and print the contents of the retrieved data located in our 'auto_t' variable.

    Repeatedly implies a loop along the likes of:

    Code:
    	open file
    	if file is open
    		auto_t	vechicle;
    		loop top
    			scan_auto()
    			print_auto()
    		loop bottom
    	endif
    
    So it looks like 'scan_auto' will need both a reference to the open file and, becuase it need to modify the local instance of "vechicle", a pointer to the 'auto_t' vairable "vechicle".

    And it looks like 'print_auto' will need to be passed the a COPY of "vechicle".

    We'll need to wrap them both in a loop. It looks convient to have 'scan_auto' return the results of its reading from the passed file reference.

    I could further define the outline but I think I'd get flack from some of the others here if I did AT THIS TIME.

    Lets see where you take it from here!

    EDIT - May 3:

    OK, nowhere - so here's a minimal implementation:

    Code:
    // <http://forums.macrumors.com/showthread.php?t=907772>
    
    #include <ctype.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    struct auto_struct
    {
        char    make[15];
        char    model[30];
        
        int     mmon;
        int     mday;
        int     myear;
        
        int     pmon;
        int     pday;
        int     pyear;
        
        float   fuelcap;
        float   fuellevel;
        
        float   odometer;
    };
    
    typedef struct auto_struct  auto_t, * auto_ptr;
    
    void print_auto(FILE* pf, auto_t vehicle)
    {
        fprintf(pf, "%s %s %d %d %d %d %d %d %f %f %f\n"
                  , vehicle.make
                  , vehicle.model
                  , vehicle.mmon
                  , vehicle.mday
                  , vehicle.myear
                  , vehicle.pmon
                  , vehicle.pday
                  , vehicle.pyear
                  , vehicle.fuelcap
                  , vehicle.fuellevel
                  , vehicle.odometer);
    }
    
    int scan_auto(FILE* pf, auto_ptr p)
    {
        return fscanf(pf, "%s %s %d %d %d %d %d %d %f %f %f"
                        , p->make
                        , p->model
                        , &p->mmon
                        , &p->mday
                        , &p->myear
                        , &p->pmon
                        , &p->pday
                        , &p->pyear
                        , &p->fuelcap
                        , &p->fuellevel
                        , &p->odometer);
    }
    
    int main(void)
    {
        FILE*   pfSrc = fopen("cars.txt", "r");
        if ( pfSrc )
        {
            FILE*   pfDst = fopen("output.txt", "w");
            if ( pfDst )
            {
                auto_t  vehicle;
    
                while ( EOF != scan_auto(pfSrc, &vehicle) )
                {
                    print_auto(pfDst, vehicle);
                }
                
                return EXIT_SUCCESS;
            }
        }
        
        return EXIT_FAILURE;
    }
    
     
  13. Rat143 macrumors newbie

    Rat143

    Joined:
    Apr 2, 2016
    #13
    --- Post Merged, Apr 2, 2016 ---
    is this problem solved?
    can I have the final ans?
     

Share This Page