Any 'C' Afficiandos out there?

Anything that isn't directly related to Age Creation but that might be interesting to Age developers.

Any 'C' Afficiandos out there?

Postby teedyo » Tue Apr 29, 2008 4:38 pm

I've run into a bit of a wall using fscanf to read from a text file. Please, no diatribes about the limitations of fscanf. :) For a known, invariant file structure it should work fine... Anyway.....

Lets declare:

char *filelist[40], *listfile; --where listfile is a text file with one filename per line.
FILE *fp;

And:
filelist[0] = "filename1.ext";
filelist[1] = "filename2.ext";
.
.
.
filelist[5] = "filename5.ext";
Then:
for(i = 0; i < 5; i++) printf("%s\n", filelist[i]);

This does what is expected and outputs a list of the filenames. However; if I do:

fp = fopen(listfile, "r");
for(i = 0; i < 5; i++)
fscanf(fp, "%s", filelist[i]);

And then do:
for(i = 0; i < 5; i++) printf("%s\n", filelist[i]);

It does not. What it outputs is this:
filefilefilefilefilename5.ext
filefilefilefilename5.ext
.
.
filename5.ext

It's obvious that what is happening is that filelist[i] is being incremented by machine int/32 bits/4 bytes rather than by the length of the previous string. Manually incrementing filelist by the length of the previous string doesn't solve the problem because when I go back to filelist[0]; it outputs garbage.

Does anybody know why it increments properly when I explicitly assign the strings but not when reading with fscanf? I have verified that fscanf is returning the full string + the \0 line feed character. I really hate scanning one character at a time when I shouldn't need to.
teedyo
 
Posts: 212
Joined: Tue Oct 09, 2007 5:47 pm

Re: Any 'C' Afficiandos out there?

Postby Gbadji » Wed Apr 30, 2008 12:27 am

******************
* comme d'habitude, je décrits d'abord en français, c'est plus facile pour moi :)
**
* the english version is following
******************

lors de la déclaration char *filelist[40] tu réserves un espace de 40 pointeurs de caractères,
lors de l'affectation filelist[0] = "filename1.ext" tu utilises le premier pointeur pour lui donner comme valeur l'adresse de la chaîne "filename1.ext" qui est définie ailleurs.
Lorsque tu utilises fscanf, tu demandes à écrire les noms de fichiers dans l'espace réservé pour filelist. Le premier s'écrit au début de filelist, puis le second à la taille d'un pointeur de caractère plus loin (la taille des éléments de filelist) , écrasant une partie du précédant.

*****************
* now the english version
*****************
When you declare char *filelist[40] you allocate space for 40 char pointers,
when you initialize filelist[0] = "filename1.ext" you use the first char pointer and give it as the value the address of the string "filename1.ext" store in an other place.
When you use fscanf, you request to write the filenames in the space reserved for filelist. The first one is writing at the beginning of filelist, the next one is writing one char pointer size further (size of one filelist element), overwrinting a part of the first one.
The French's Mystpedia age Project - http://www.mystpedia.net
To find me in the Cavern: Gbadji KI #6911493 or Alatan KI#7869109
User avatar
Gbadji
 
Posts: 73
Joined: Sat Feb 02, 2008 5:59 am

Re: Any 'C' Afficiandos out there?

Postby Nadnerb » Wed Apr 30, 2008 11:54 am

As Gbadji said, you're only allocating space for pointers to character arrays, and not allocating any space for the actual characters, and then writing the characters into the space where the pointers would go. What you need to do to make this work is allocate space for the characters. One simple way to do this would be to use a two dimensional array. ie:
Code: Select all
   char filelist[40][256]; //256 will be our arbitrary max line length
   FILE* fp;
...
   fp = fopen(listfile, "r");
   for(int i = 0; i < 5; i++)
      fscanf(fp, "%s", filelist[i]);

   for(int i = 0; i < 5; i++)
      printf("%s\n", filelist[i]);

This allocates enough space for the characters that make up the filenames, rather than just pointers to unallocated memory for them. When you assign a static string to a variable as you do here:
Code: Select all
filelist[0] = "filename1.ext";

what actually happens is that the space for the characters is allocated for you by the compiler. When you are reading from a file, you have to make space for the input.
Image
Live KI: 34914 MOULa KI: 23247 Gehn KI: 11588 Available Ages: TunnelDemo3, BoxAge, Odema
Nadnerb
 
Posts: 1057
Joined: Fri Sep 28, 2007 8:01 pm
Location: US (Eastern Time)

Re: Any 'C' Afficiandos out there?

Postby teedyo » Wed Apr 30, 2008 6:51 pm

Thanks for the responses guys; I got it figured out last night. When I thought was doing it right(not like above); the program segfaulted. Doing it as above gave me erroneous information but the rest of the program continued to run so I could test other segments. What I was originally doing was like this:
char *inbuf, *filelist[];
FILE *fp;

for( 1 = 0; 1 < 5; i++) {
fscanf(fp, "%s", inbuf);
filelist[i] = malloc((strlen(inbuf) + 1)*sizeof(char)); <- Segmentation fault here
if(!flist[i] exit(1);
strcpy(flist[i], inbuf);
}

Turns out it didn't like the fact that I didn't allocate space for inbuf so a:
inbuf = malloc(257*sizeof(char));
solved the problem. One of those cases where 90% correct was more disasterous than 90% wrong. :)

At one point I did try a 2d array as in your example Nadnerb but, fscanf didn't seem to like it. I may have included both indices(filelist[i][0]) tho'.
teedyo
 
Posts: 212
Joined: Tue Oct 09, 2007 5:47 pm


Return to Off-Topic Discussion

Who is online

Users browsing this forum: No registered users and 0 guests