Reputation: 161
fscanf
is working the way it is written here...it's getting the data into the array that's broken.
The only point of failure is the memcpy
line on the second iteration through the loop where fileindex
is 0 and i
is 1. the memcpy
line works fine when i
is 0.
I'm converting a program that used to read data from a binary file directly into an array using fread
into reading from ascii text. Here's the setup:
#define MAX_FLIGHT_ENTRIES 27000
#define MAX_PLANES_IN_A_FLIGHT 10
typedef struct {
double local_x;
double local_y;
double local_z;
float pitch;
float roll;
float heading;
float gearpos;
float flappos;
float speedbrakepos;
float canopypos;
float afterburnerOn;
float kias;
float time; // record timestamp
} FLIGHT_ENTRY_TYPE;
static FLIGHT_ENTRY_TYPE FlightEntries [MAX_PLANES_IN_A_FLIGHT][MAX_FLIGHT_ENTRIES];
The way this used to work is, in a loop, the array would be filled via:
fread (&FlightEntries[fileIndex][i], sizeof (FLIGHT_ENTRY_TYPE), 1, pFile);
And I believe this would actually instantiate each entry in the array by putting the data directly into memory. Now I'm reading from a text file and I've tried everything I can to get the values into the array, but it only ever writes the first entry FlightEntries[0][0]. Any attempt to read or write to FlightEntries[0][1] crashes. Here's my current best attempt.
for ( i = 0; i < MAX_FLIGHT_ENTRIES; i++)
{
// If the file end is found before it should be, set values to defaults
// and save the file
if (feof(pFile))
{
FlightInfo[fileIndex].endFrameIndex = i - 1;
break;
}
else
{
float plocalx, plocaly, plocalz;
float ppitch, proll, pheading, pgearpos, pflappos, pbrakepos, pcanopypos, pafterburnon, pkias, ptime;
int fresult;
fresult = fscanf(pFile, "%f %f %f %f %f %f %f %f %f %f %f %f %f\n",
&plocalx,
&plocaly,
&plocalz,
&ppitch,
&proll,
&pheading,
&pgearpos,
&pflappos,
&pbrakepos,
&pcanopypos,
&pafterburnon,
&pkias,
&ptime);
FLIGHT_ENTRY_TYPE newEntry;
newEntry.local_x = (double)plocalx;
newEntry.local_y = (double)plocaly;
newEntry.local_z = (double)plocalz;
newEntry.pitch = ppitch;
newEntry.roll = proll;
newEntry.heading = pheading;
newEntry.gearpos = pgearpos;
newEntry.flappos = pflappos;
newEntry.speedbrakepos = pbrakepos;
newEntry.canopypos = pcanopypos;
newEntry.afterburnerOn = pafterburnon;
newEntry.kias = pkias;
newEntry.time = ptime;
memcpy (&FlightEntries[fileIndex][i], &newEntry, sizeof FLIGHT_ENTRY_TYPE);
}
}
I don't think the array entries are getting allocated properly. I've tried accessing the individual structure members directly via FlightEntries[fileIndex][i].local_x = (double)plocalx;
and I've also tried using memcpy
to do the same thing for each member...am I doing my pointers wrong or something? I have no idea where to go with this. Every time I get past one stumbling block, something else comes up and I think it's all related to the array as opposed to reading from file. Do I have to do something to allocate space?
What does fread
do with binary data in FlightEntries[0][1] that memcpy
isn't doing? And is my memcpy
line correct? Do I need to do some kind of malloc
?
Upvotes: 1
Views: 1133
Reputation: 23218
...used to read data from a binary file directly into an array using fread....
EDIT
Now I'm reading from a text file and I've tried everything I can to get the values into the array.
Unless the contents of your file match the current definition of the FLIGHT_ENTRY_TYPE struct, and perhaps these definitions:
#define MAX_FLIGHT_ENTRIES 27000
#define MAX_PLANES_IN_A_FLIGHT 10
There will be problems with your read attempt, no matter what you try. (The file contents, and the struct definition MUST be in alignment to do what you are trying to do. Because you are using a text file, this should be easily verifiable.)
Also, feof(pFile) is rarely a good choice for reading a file
Consider changing it to something like this:(pseudo code)
FLIGHT_ENTRY_TYPE newEntry;
int len = sizeof(FLIGHT_ENTRY_TYPE)*2;// *2 to account for comma delimiters, etc. Change as needed
char **stringArray = {0};
//see edits in answer below for defintion of allocArray()
stringArray = allocMemory(stringArray, MAX_PLANES_IN_A_FLIGHT, len);
FILE *fp = fopen(".\\filename.bin", "rb");
if(fp && stringArray)
{
while(fgets(stringArray[i], len, fp)
{
fresult = sscanf(stringArray[i], "%f %f %f %f %f %f %f %f %f %f %f %f %f\n",
&plocalx,
&plocaly,
&plocalz,
&ppitch,
&proll,
&pheading,
&pgearpos,
&pflappos,
&pbrakepos,
&pcanopypos,
&pafterburnon,
&pkias,
&ptime);
if(fresult > 0)
{ ...assign values to newEntry struct... }
}
fclose(fp);
freeMemory(stringArray,MAX_PLANES_IN_A_FLIGHT);
}
The first three members of your struct are double
values, and should therefore be read into double values. If you decide to make that change:
float plocalx, plocaly, plocalz;
TO:
double plocalx, plocaly, plocalz;
Be sure to also Change:
fresult = fscanf(pFile, "%f %f %f %f %f %f %f %f %f %f %f %f %f\n",
To:
fresult = fscanf(pFile, "%lf %lf %lf %f %f %f %f %f %f %f %f %f %f\n",
You should also check the return value of sscanf()
The return value: Converts input from the specified source string into a series of values according to the specifiers in formatString. If an input failure occurs before the first conversion, the function returns EOF (-1); otherwise, the function returns the number of input items assigned. If copying takes place between objects that overlap, the behavior is undefined.
EDIT 2
If you do need to create an array of strings (for each line of the file), these functions will help:
char ** allocMemory(char ** a, int numStrings, int maxStrLen)
{
int i;
a = calloc(sizeof(char*)*(numStrings+1), sizeof(char*));
for(i=0;i<numStrings; i++)
{
a[i] = calloc(sizeof(char)*maxStrLen + 1, sizeof(char));
}
return a;
}
void freeMemory(char ** a, int numStrings)
{
int i;
for(i=0;i<numStrings; i++)
if(a[i]) free(a[i]);
free(a);
}
//usage:
#define MAX_FLIGHT_ENTRIES 27000
#define MAX_PLANES_IN_A_FLIGHT 10
int main(void)
{
char **stringArray = {0};
stringArray = allocMemory(stringArray, MAX_PLANES_IN_A_FLIGHT, sizeof FLIGHT_ENTRY_TYPE);
...//read data into string array as shown in code above
return 0;
}
The concept here is that each line of the file is assumed to represent the data to populate one struct instance of the FLIGHT_ENTRY_TYPE struct. Stated differently, one line in the file is read for each struct in the array of structs.
Upvotes: 3
Reputation: 161
Extenuating unlisted circumstances.
Turns out, since I couldn't debug, I had placed a log file snippet at the end of the loop iteration. I believe that instantiating the logfile was corrupting the array and preventing the array from being written to. Possibly a heap issue, but I'm not sure. I've learned quite a bit from this exercise about dealign with memory pointers as well as better ways to read and write data from file. So Thank you all for the help.
Upvotes: 0