| | |
Structures, external files, and functions
![]() |
Yes,
fscanf() is your problem. See this series to understand the complications. The 3 Laws of the Procrastination Society:
1) Never do today that which can be put off until tomorrow
2) Tomorrow never comes
1) Never do today that which can be put off until tomorrow
2) Tomorrow never comes
•
•
Join Date: Nov 2007
Posts: 6
Reputation:
Solved Threads: 0
Thanks so much for the help, everyone. Unfortunately, I'm still not understanding things.
I'm completely baffled as to how to read in each room from the map file and stick each room into its own struct and have each element of the room in its own little place in the struct.
I'd really like to just use the format
etc...
and get just ONE room into ONE struct. I don't even know where to begin with finding out how many rooms are in the maps.c. file and reading them all into the structures array. Or maybe I don't even have to do that.
Sorry, I probably sound really confused (which I am). I think I must be really off-base. Once I can get the basic structure of this thing down, the "game" should be infinitely expandable just by adding more rooms to the maps.c file, and never messing with the code itself.
Thanks again for your help. Any more you can offer would be greatly appreciated. I just want it to work!
I'm completely baffled as to how to read in each room from the map file and stick each room into its own struct and have each element of the room in its own little place in the struct.
I'd really like to just use the format
c Syntax (Toggle Plain Text)
fgets(rooms[i].room_num, fin); fgets(rooms[i].room_name, fin); fgets(rooms[i].desc, fin); fgets(rooms[i].num_links, fin);
etc...
and get just ONE room into ONE struct. I don't even know where to begin with finding out how many rooms are in the maps.c. file and reading them all into the structures array. Or maybe I don't even have to do that.
Sorry, I probably sound really confused (which I am). I think I must be really off-base. Once I can get the basic structure of this thing down, the "game" should be infinitely expandable just by adding more rooms to the maps.c file, and never messing with the code itself.
Thanks again for your help. Any more you can offer would be greatly appreciated. I just want it to work!
Yes, such abstraction is usually best. However, in C, you must build your own.
I've taken some liberties here.
1. First, I changed your direction type to an enumeration.
2. Second, I added a whole lot of error checking. (I am assuming this is not a school project. Please don't make me wrong.)
Some notes:
1. Don't name files other than C source code "anything.c". I renamed "maps.c" to "maps.txt".
2. Don't use C++ comments in a C program.
3. Don't forget to close files when you are done with them.
4. This code aborts on error, but does not inform you that an error actually occurred. Hence, if the nth record contains an error, you will only get n-1 records out of the file, and main() won't know any different. There are a number of ways to settle this error... the easiest being to check to see if any record has a dest1 or dest2 >= the number of records read. You'll have to do that.
5. Care is taken not to hardcode the length of any string in the readRooms() function. (Note the use of the sizeof operator.) Keep in mind this only works for char strings. (Unicode strings would need a bit more help.)
The purpose for posting all this wasn't to make your life thought-free. It was to give you a template upon which to work your program further. It provides examples of:
1. Good I/O.
2. Use of enums and conversion. (enum to string:
3. Use of a loop.
4. Care when handling maxima (i.e. you can't read more records than you have room for --currently at 100).
5. capacity for good error checking.
Well, that's enough. Enjoy.
I've taken some liberties here.
1. First, I changed your direction type to an enumeration.
2. Second, I added a whole lot of error checking. (I am assuming this is not a school project. Please don't make me wrong.)
Some notes:
1. Don't name files other than C source code "anything.c". I renamed "maps.c" to "maps.txt".
2. Don't use C++ comments in a C program.
3. Don't forget to close files when you are done with them.
4. This code aborts on error, but does not inform you that an error actually occurred. Hence, if the nth record contains an error, you will only get n-1 records out of the file, and main() won't know any different. There are a number of ways to settle this error... the easiest being to check to see if any record has a dest1 or dest2 >= the number of records read. You'll have to do that.
5. Care is taken not to hardcode the length of any string in the readRooms() function. (Note the use of the sizeof operator.) Keep in mind this only works for char strings. (Unicode strings would need a bit more help.)
C Syntax (Toggle Plain Text)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> typedef enum { d_none, d_north, d_south, d_east, d_west, d_error = -1 } direction_t; const char *directions[] = { "none", "north", "south", "east", "west" }; typedef struct { int room_num; char room_name[ 80 ]; char desc[ 1000 ]; int num_links; direction_t direction1; int dest1; direction_t direction2; int dest2; } roomStruct; direction_t str_to_direction( const char *d ); int readRooms( const char *filename, roomStruct rooms[], int max_rooms ); /* ----------------------------------------------------------------- main ----------------------------------------------------------------- */ int main () { int num_rooms; roomStruct rooms[ 100 ]; num_rooms = readRooms( "maps.txt", rooms, 100 ); printf( "number of rooms = %d", num_rooms ); return 0; } /* ----------------------------------------------------------------- fgetline -------------------------------------------------------------------- Get an entire line from file, filling 'max' characters with the result and tossing any extra, stripping the newline, guaranteeing the string is nul-terminated, and returning success or failure. */ int fgetline( FILE *f, char *s, int max ) { char c; int i; /* Get the line from file */ if (fgets( s, max, f ) == NULL) return 0; /* Make sure the entire line was read */ i = strlen( s ) -1; if (s[ i ] != '\n') { while ((c = fgetc( f )) != '\n') if (c == EOF) break; } /* Strip the trailing newline */ else s[ i ] = '\0'; return 1; } /* ----------------------------------------------------------------- mstricmp -------------------------------------------------------------------- The POSIX stricmp function is deprecated and not always available anyway... so we roll our own here. */ int mstricmp( const char *s, const char *t ) { int i; char *ss, *tt; for ( ss = (char *)s, tt = (char *)t; *ss || *tt; ss++, tt++ ) { i = tolower( *ss ) - tolower( *tt ); if (i != 0) return i; } return 0; } /* ----------------------------------------------------------------- str_to_direction -------------------------------------------------------------------- Convert a character string into a direction_t. Takes any string that is <= a direction name without case-sensitivity. Hence, "n" == "north", as do "no", "NOR", etc. */ direction_t str_to_direction( const char *d ) { direction_t i; for (i = d_none; i <= d_west; i++) if (mstricmp( d, directions[ i ] ) <= 0) return i; return d_error; } /* ----------------------------------------------------------------- readRooms -------------------------------------------------------------------- Read records from file. Returns the number of complete records read. */ int readRooms( const char *filename, roomStruct rooms[], int max_rooms ) { char s[ 20 ]; char *p; FILE *f; int i = 0; if ((f = fopen( filename, "r" )) == NULL) return 0; do { /* get the room number */ if (!fgetline( f, s, 20 )) break; rooms[ i ].room_num = strtol( s, &p, 10 ); if (*p != '\0') break; /* get the room name */ if (!fgetline( f, rooms[ i ].room_name, sizeof( rooms[ i ].room_name ) )) break; /* get the room description */ if (!fgetline( f, rooms[ i ].desc, sizeof( rooms[ i ].desc ) )) break; /* get the number of links */ if (!fgetline( f, s, 20 )) break; rooms[ i ].num_links = strtol( s, &p, 10 ); if (*p != '\0') break; /* get direction 1 */ if (!fgetline( f, s, 20 )) break; if ((rooms[ i ].direction1 = str_to_direction( s )) == d_error) break; /* get destination 1 */ if (!fgetline( f, s, 20 )) break; rooms[ i ].dest1 = strtol( s, &p, 10 ); if (*p != '\0') break; /* get direction 2 */ if (!fgetline( f, s, 20 )) break; if ((rooms[ i ].direction2 = str_to_direction( s )) == d_error) break; /* get destination 2 */ if (!fgetline( f, s, 20 )) break; rooms[ i ].dest2 = strtol( s, &p, 10 ); if (*p != '\0') break; if (++i >= max_rooms) break; } while (!feof( f )); fclose( f ); return i; }
1. Good I/O.
2. Use of enums and conversion. (enum to string:
directions[ d_north ])3. Use of a loop.
4. Care when handling maxima (i.e. you can't read more records than you have room for --currently at 100).
5. capacity for good error checking.
Well, that's enough. Enjoy.
Oh yeah... (sorry for the double-post)
the error checking in the example is fairly simplistic. It glosses over errors like lines that are too long in the file. So, for example, if your description is longer than 999 characters, the player will see only the first 999 and the rest are ignored.
It would be better to dynamically allocate the space for description. That way it can be as large or small as you want...
Hope this helps.
the error checking in the example is fairly simplistic. It glosses over errors like lines that are too long in the file. So, for example, if your description is longer than 999 characters, the player will see only the first 999 and the rest are ignored.
It would be better to dynamically allocate the space for description. That way it can be as large or small as you want...
Hope this helps.
•
•
•
•
I'm completely baffled as to how to read in each room from the map file and stick each room into its own struct and have each element of the room in its own little place in the struct.
I'd really like to just use the format
c Syntax (Toggle Plain Text)
fgets(rooms[i].room_num, fin); fgets(rooms[i].room_name, fin); fgets(rooms[i].desc, fin); fgets(rooms[i].num_links, fin);
etc...
and get just ONE room into ONE struct.
The 3 Laws of the Procrastination Society:
1) Never do today that which can be put off until tomorrow
2) Tomorrow never comes
1) Never do today that which can be put off until tomorrow
2) Tomorrow never comes
fgets() is prototyped: meaning it returns a pointer to a string and accepts three arguments. 1st, a string, 2nd, size of the storage available to it and 3rd, a stream or where it reads from.
Let's look at your calls to fgets:
rooms[i].room_num is an integer and not an array of characters as is needed, futhermore is missing the second argument which should be an int for the size of the space available.
rooms[i].room_name is the correct argument, however is missing the second one.
The last two I'll leave it to you to figure out where and why they are wrong.
The information in the file maps.c needs to be formatted in a neat and controlled way that
will allow a methodical reading by fgets or fscanf.
By the way, if you use fgets to obtain an integer, it is necessary to store the read string in an array of chars and then scan for the integer using sscanf().
C Syntax (Toggle Plain Text)
char *fgets(char *restrict s, int n, FILE *restrict stream);
Let's look at your calls to fgets:
C Syntax (Toggle Plain Text)
fgets(rooms[i].room_num, fin);
C Syntax (Toggle Plain Text)
fgets(rooms[i].room_name, fin);
C Syntax (Toggle Plain Text)
fgets(rooms[i].desc, fin); fgets(rooms[i].num_links, fin);
The information in the file maps.c needs to be formatted in a neat and controlled way that
will allow a methodical reading by fgets or fscanf.
By the way, if you use fgets to obtain an integer, it is necessary to store the read string in an array of chars and then scan for the integer using sscanf().
![]() |
Similar Threads
- Calling external files (C++)
- Problems Linking C++ Files (C++)
- Can't open any xml file (PHP)
- Help: need feedback on my Java assignment about thread sleep. It's already coded. (Java)
- reading external files into java (Java)
- Using data i read from *.* files (C++)
- unresolved external symbol when using a hashtable class (C++)
- Zend PHP Certification (PHP)
Other Threads in the C Forum
- Previous Thread: Controlling wheter postfix expression is valid
- Next Thread: quick sort
| Thread Tools | Search this Thread |
adobe api array arrays bash binarysearch calculate char cm convert copyanyfile copypdffile cprogramme createcopyoffile createprocess() csyntax directory dynamic feet fflush file floatingpointvalidation fork forloop frequency getlasterror givemetehcodez global graphics gtkgcurlcompiling hacking hardware highest homework i/o inches incrementoperators intmain() iso kernel kilometer km linked linkedlist linux linuxsegmentationfault list locate logical_drives loopinsideloop. match matrix microsoft motherboard mqqueue mysql oddnumber odf open opensource openwebfoundation owf pattern pdf performance pointer posix power probleminc program programming pyramidusingturboccodes read recursion recv recvblocked repetition research scanf scheduling scripting segmentationfault send shape socketprograming socketprogramming stack standard string suggestions systemcall test unix urboc user variable voidmain() wab win32api windows.h






