C - 将数据读入struct,memcpy数组?

时间:2015-03-04 14:49:34

标签: c arrays struct

为了清晰起见,编辑

fscanf正在按照它在这里编写的方式工作......它将数据放入已损坏的数组中。

为清晰起见,另一个编辑:

唯一的失败点是第二次迭代中的memcpy行,其中fileindex为0且i为1. memcpy行正常工作时i为0。


我正在使用fread将用于从二进制文件直接读取数据的程序转换为从ascii文本读取的数据。这是设置:

#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];

以前的工作方式是,在一个循环中,数组将通过以下方式填充:

fread (&FlightEntries[fileIndex][i], sizeof (FLIGHT_ENTRY_TYPE), 1, pFile);

我相信这实际上会通过将数据直接放入内存来实例化数组中的每个条目。现在我正在阅读一个文本文件,我已尽力将所有值都放入数组中,但它只写入第一个条目FlightEntries [0] [0]。任何读取或写入FlightEntries [0] [1]的尝试都会崩溃。这是我目前最好的尝试。

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);
        }
}

我认为数组条目没有正确分配。我已经尝试通过FlightEntries[fileIndex][i].local_x = (double)plocalx;直接访问各个结构成员了,我也尝试使用memcpy为每个成员做同样的事情......我的指针是错误的还是什么?我不知道该去哪里。每次我遇到一个绊脚石,其他东西出现了,我认为这些都与数组有关,而不是从文件中读取。我是否必须做一些事情来分配空间?

最大的问题是:

freadmemcpy没有做的FlightEntries [0] [1]中的二进制数据做了什么?我的memcpy行是否正确?我需要做某种malloc吗?

2 个答案:

答案 0 :(得分:3)

...用于使用fread将二进制文件中的数据直接读入数组。 ...
修改
现在我正在阅读文本文件,并且我已尽力将所有值都放入数组中。

除非您的文件内容与FLIGHT_ENTRY_TYPE结构的当前定义匹配,否则可能是这些定义:

#define MAX_FLIGHT_ENTRIES    27000
#define MAX_PLANES_IN_A_FLIGHT 10

无论您尝试什么, 都会导致您的阅读尝试出现问题。 (文件内容和结构定义必须对齐以执行您要执行的操作。因为您使用的是文本文件,所以应该可以轻松验证。)

feof(pFile) 很少是阅读文件的好选择

考虑将其更改为:(伪代码)

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);   
}

结构的前三个成员是double值,因此应该读入双精度值。如果您决定进行更改:

float plocalx, plocaly, plocalz; 

TO:

double plocalx, plocaly, plocalz;

请务必同时更改

fresult = fscanf(pFile, "%f %f %f %f %f %f %f %f %f %f %f %f %f\n", 

<强>

fresult = fscanf(pFile, "%lf %lf %lf %f %f %f %f %f %f %f %f %f %f\n",  

您还应该检查sscanf()的返回值 返回值: 根据formatString中的说明符,将指定源字符串的输入转换为一系列值。如果在 第一次 转换之前发生输入失败,则该函数返回EOF(-1);否则,该函数返回分配的输入项数。如果在重叠的对象之间进行复制,则行为未定义。

编辑2
如果确实需要创建一个字符串数组(对于文件的每一行),这些函数将有所帮助:

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;
}   

这里的概念是假定文件的每一行代表填充FLIGHT_ENTRY_TYPE结构的一个结构实例的数据。换句话说,对于结构数组中的每个结构,都会读取文件中的一行。

答案 1 :(得分:0)

减弱未上市的情况。

事实证明,由于我无法调试,我在循环迭代结束时放置了一个日志文件片段。我相信实例化日志文件会破坏数组并阻止数组被写入。可能是堆问题,但我不确定。我从这个练习中学到了很多关于内存指针的处理以及从文件读取和写入数据的更好方法。谢谢大家的帮助。