Structures, external files, and functions

Reply

Join Date: May 2006
Posts: 3,114
Reputation: WaltP has much to be proud of WaltP has much to be proud of WaltP has much to be proud of WaltP has much to be proud of WaltP has much to be proud of WaltP has much to be proud of WaltP has much to be proud of WaltP has much to be proud of WaltP has much to be proud of 
Solved Threads: 281
Moderator
WaltP's Avatar
WaltP WaltP is offline Offline
Posting Sensei

Re: Structures, external files, and functions

 
0
  #11
Nov 9th, 2007
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
Reply With Quote Quick reply to this message  
Join Date: Nov 2007
Posts: 6
Reputation: deadswitch is an unknown quantity at this point 
Solved Threads: 0
deadswitch deadswitch is offline Offline
Newbie Poster

Re: Structures, external files, and functions

 
0
  #12
Nov 9th, 2007
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

  1. fgets(rooms[i].room_num, fin);
  2. fgets(rooms[i].room_name, fin);
  3. fgets(rooms[i].desc, fin);
  4. 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!
Reply With Quote Quick reply to this message  
Join Date: Oct 2007
Posts: 1,951
Reputation: Duoas has much to be proud of Duoas has much to be proud of Duoas has much to be proud of Duoas has much to be proud of Duoas has much to be proud of Duoas has much to be proud of Duoas has much to be proud of Duoas has much to be proud of 
Solved Threads: 214
Featured Poster
Duoas's Avatar
Duoas Duoas is offline Offline
Posting Virtuoso

Re: Structures, external files, and functions

 
0
  #13
Nov 9th, 2007
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.)

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5.  
  6. typedef enum {
  7. d_none, d_north, d_south, d_east, d_west, d_error = -1
  8. } direction_t;
  9.  
  10. const char *directions[] = {
  11. "none", "north", "south", "east", "west"
  12. };
  13.  
  14. typedef struct {
  15. int room_num;
  16. char room_name[ 80 ];
  17. char desc[ 1000 ];
  18. int num_links;
  19. direction_t direction1;
  20. int dest1;
  21. direction_t direction2;
  22. int dest2;
  23. } roomStruct;
  24.  
  25. direction_t str_to_direction( const char *d );
  26. int readRooms( const char *filename, roomStruct rooms[], int max_rooms );
  27.  
  28. /* -----------------------------------------------------------------
  29.   main
  30. ----------------------------------------------------------------- */
  31. int main () {
  32. int num_rooms;
  33. roomStruct rooms[ 100 ];
  34.  
  35. num_rooms = readRooms( "maps.txt", rooms, 100 );
  36.  
  37. printf( "number of rooms = %d", num_rooms );
  38.  
  39. return 0;
  40. }
  41.  
  42. /* -----------------------------------------------------------------
  43.   fgetline
  44. --------------------------------------------------------------------
  45.   Get an entire line from file, filling 'max' characters with
  46.   the result and tossing any extra, stripping the newline,
  47.   guaranteeing the string is nul-terminated,
  48.   and returning success or failure.
  49. */
  50. int fgetline( FILE *f, char *s, int max ) {
  51. char c;
  52. int i;
  53.  
  54. /* Get the line from file */
  55. if (fgets( s, max, f ) == NULL) return 0;
  56.  
  57. /* Make sure the entire line was read */
  58. i = strlen( s ) -1;
  59. if (s[ i ] != '\n') {
  60. while ((c = fgetc( f )) != '\n')
  61. if (c == EOF) break;
  62. }
  63. /* Strip the trailing newline */
  64. else s[ i ] = '\0';
  65.  
  66. return 1;
  67. }
  68.  
  69. /* -----------------------------------------------------------------
  70.   mstricmp
  71. --------------------------------------------------------------------
  72.   The POSIX stricmp function is deprecated and not always
  73.   available anyway... so we roll our own here.
  74. */
  75. int mstricmp( const char *s, const char *t ) {
  76. int i;
  77. char *ss, *tt;
  78. for (
  79. ss = (char *)s, tt = (char *)t;
  80. *ss || *tt;
  81. ss++, tt++
  82. ) {
  83. i = tolower( *ss ) - tolower( *tt );
  84. if (i != 0) return i;
  85. }
  86. return 0;
  87. }
  88.  
  89. /* -----------------------------------------------------------------
  90.   str_to_direction
  91. --------------------------------------------------------------------
  92.   Convert a character string into a direction_t.
  93.   Takes any string that is <= a direction name without
  94.   case-sensitivity.
  95.   Hence, "n" == "north", as do "no", "NOR", etc.
  96. */
  97. direction_t str_to_direction( const char *d ) {
  98. direction_t i;
  99.  
  100. for (i = d_none; i <= d_west; i++)
  101. if (mstricmp( d, directions[ i ] ) <= 0) return i;
  102.  
  103. return d_error;
  104. }
  105.  
  106. /* -----------------------------------------------------------------
  107.   readRooms
  108. --------------------------------------------------------------------
  109.   Read records from file. Returns the number of complete records read.
  110. */
  111. int readRooms( const char *filename, roomStruct rooms[], int max_rooms ) {
  112. char s[ 20 ];
  113. char *p;
  114. FILE *f;
  115. int i = 0;
  116.  
  117. if ((f = fopen( filename, "r" )) == NULL) return 0;
  118.  
  119. do {
  120. /* get the room number */
  121. if (!fgetline( f, s, 20 )) break;
  122. rooms[ i ].room_num = strtol( s, &p, 10 );
  123. if (*p != '\0') break;
  124.  
  125. /* get the room name */
  126. if (!fgetline( f, rooms[ i ].room_name, sizeof( rooms[ i ].room_name ) )) break;
  127.  
  128. /* get the room description */
  129. if (!fgetline( f, rooms[ i ].desc, sizeof( rooms[ i ].desc ) )) break;
  130.  
  131. /* get the number of links */
  132. if (!fgetline( f, s, 20 )) break;
  133. rooms[ i ].num_links = strtol( s, &p, 10 );
  134. if (*p != '\0') break;
  135.  
  136. /* get direction 1 */
  137. if (!fgetline( f, s, 20 )) break;
  138. if ((rooms[ i ].direction1 = str_to_direction( s )) == d_error) break;
  139.  
  140. /* get destination 1 */
  141. if (!fgetline( f, s, 20 )) break;
  142. rooms[ i ].dest1 = strtol( s, &p, 10 );
  143. if (*p != '\0') break;
  144.  
  145. /* get direction 2 */
  146. if (!fgetline( f, s, 20 )) break;
  147. if ((rooms[ i ].direction2 = str_to_direction( s )) == d_error) break;
  148.  
  149. /* get destination 2 */
  150. if (!fgetline( f, s, 20 )) break;
  151. rooms[ i ].dest2 = strtol( s, &p, 10 );
  152. if (*p != '\0') break;
  153.  
  154. if (++i >= max_rooms) break;
  155. } while (!feof( f ));
  156.  
  157. fclose( f );
  158. return i;
  159. }
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: 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.
Reply With Quote Quick reply to this message  
Join Date: Oct 2007
Posts: 1,951
Reputation: Duoas has much to be proud of Duoas has much to be proud of Duoas has much to be proud of Duoas has much to be proud of Duoas has much to be proud of Duoas has much to be proud of Duoas has much to be proud of Duoas has much to be proud of 
Solved Threads: 214
Featured Poster
Duoas's Avatar
Duoas Duoas is offline Offline
Posting Virtuoso

Re: Structures, external files, and functions

 
0
  #14
Nov 9th, 2007
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.
Reply With Quote Quick reply to this message  
Join Date: May 2006
Posts: 3,114
Reputation: WaltP has much to be proud of WaltP has much to be proud of WaltP has much to be proud of WaltP has much to be proud of WaltP has much to be proud of WaltP has much to be proud of WaltP has much to be proud of WaltP has much to be proud of WaltP has much to be proud of 
Solved Threads: 281
Moderator
WaltP's Avatar
WaltP WaltP is offline Offline
Posting Sensei

Re: Structures, external files, and functions

 
0
  #15
Nov 10th, 2007
Originally Posted by deadswitch View Post
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

  1. fgets(rooms[i].room_num, fin);
  2. fgets(rooms[i].room_name, fin);
  3. fgets(rooms[i].desc, fin);
  4. fgets(rooms[i].num_links, fin);

etc...

and get just ONE room into ONE struct.
I assume the above did not work properly for some reason. So what happened? What didn't work?
The 3 Laws of the Procrastination Society:
1) Never do today that which can be put off until tomorrow
2) Tomorrow never comes
Reply With Quote Quick reply to this message  
Join Date: Dec 2006
Posts: 2,031
Reputation: Aia has much to be proud of Aia has much to be proud of Aia has much to be proud of Aia has much to be proud of Aia has much to be proud of Aia has much to be proud of Aia has much to be proud of Aia has much to be proud of Aia has much to be proud of Aia has much to be proud of 
Solved Threads: 177
Aia's Avatar
Aia Aia is offline Offline
Postaholic

Re: Structures, external files, and functions

 
0
  #16
Nov 10th, 2007
fgets() is prototyped:
  1. char *fgets(char *restrict s, int n, FILE *restrict stream);
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:
  1. fgets(rooms[i].room_num, fin);
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.

  1. fgets(rooms[i].room_name, fin);
rooms[i].room_name is the correct argument, however is missing the second one.
  1. fgets(rooms[i].desc, fin);
  2. fgets(rooms[i].num_links, fin);
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().
Reply With Quote Quick reply to this message  
Reply

This thread is more than three months old.
Perhaps start a new thread instead?
Message:


Thread Tools Search this Thread



About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC