Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

SkippyThorson

macrumors 68000
Original poster
Jul 22, 2007
1,705
1,007
Utica, NY
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:
Mercury Sable 99942 1 18 2001 5 30 1991 16 12.5
Mazda Navajo 123961 2 20 1993 6 15 1993 19.3 16.7
Toyota Camry 8223 6 13 2009 4 12 2009 15 8.9
 

Attachments

  • cars.txt
    143 bytes · Views: 332
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
 
Any words of wisdom or slaps to the head?

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.
 
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.

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.
 
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.
 
SkippyThorson, I hate to sound like a broken record but, could you post the exact wording of your assignment?

:p No problem. You're the ones offering to help me. Whatever you'd like.

Define a structure type auto_t to represent an automobile. 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. Write I/O functions scan_auto and print_auto, and also write a driver function that repeatedly fills and displays an auto structure variable until EOF is encountered in the external input file. Be sure to use an external file.

The data on the cars from the first post is the external file we were told to use:
Mercury Sable 99942 1 18 2001 5 30 1991 16 12.5
Mazda Navajo 123961 2 20 1993 6 15 1993 19.3 16.7
Toyota Camry 8223 6 13 2009 4 12 2009 15 8.9
 
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.
 
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);		
		}
}
 
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
 
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.

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.
 
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:
// <https://forums.macrumors.com/threads/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;
}
 
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:
// <https://forums.macrumors.com/threads/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;
}
[doublepost=1459583585][/doublepost]is this problem solved?
can I have the final ans?
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.