C - 在编辑结构数组的成员时遇到问题



我正在尝试创建一个函数,在其中读取时间和 x、y、z 坐标数据的文件。我正在使用 for 循环,如果对于任何 i 和 i+1 的时间相同,我将平均它们的坐标位置,用这些平均值覆盖 i,然后用 NAN 覆盖 i+1。

struct  Data {
double Time_Data;
double X_Data;
double Y_Data;
double Z_Data;
};
int main(int argc, char *argv[]){
const int SIZE = 3694;
char Input[80] = "output.csv";
const char Deliminator[2] = ",";
char* field;
char line[50];
struct Data dataPoints[SIZE];
FILE * pointer;
fpointer = fopen(Input, "r");
if(fpointer == NULL){
printf("Unable to open file n");
return 0;
}   
int LineCount = 0;
while(fgets(line, sizeof line, fpointer) != NULL){
field = strtok(line, Deliminator);
dataPoints[LineCount].Time_Data = atof(field);
field = strtok(NULL, Deliminator);
dataPoints[LineCount].X_Data = atof(field);
field = strtok(NULL, Deliminator);
dataPoints[LineCount].Y_Data = atof(field);
field = strtok(NULL, Deliminator);
dataPoints[LineCount].Z_Data = atof(field);
LineCount++;
}
fclose(pointer);
struct Data* structPointer[] = &dataPoints[];
double average_X;
double average_Y;
double average_Z;
for(int i=0; i<SIZE; i++){
average_X = 0;
average_Y = 0;
average_Z = 0;
if(dataPoints[i].Time_Data = dataPoints[i+1].Time_Data){
average_X = (structPointer[i]->X_Data + structPointer[i+1]->X_Data)/2;
average_Y = (structPointer[i]->Y_Data + structPointer[i+1]->Y_Data)/2;
average_Z = (structPointer[i]->Z_Data + structPointer[i+1]->Z_Data)/2;
structPointer[i]->X_Data = average_X;
structPointer[i]->Y_Data = average_Y;
structPointer[i]->Z_Data = average_Z;
structPointer[i+1]->Time_Data = NAN;
structPointer[i+1]->X_Data = NAN;
structPointer[i+1]->Y_Data = NAN;
structPointer[i+1]->Z_Data = NAN;
}
}
for(int i=0; i < SIZE; i++){
printf("%d    %lf    %lf    %lf    %lfn", i, 
structPointer[i]->Time_Data,
structPointer[i]->X_Data,
structPointer[i]->Y_Data,
structPointer[i]->Z_Data);
}
return 0;
}

我正在尝试使用结构指针来访问和覆盖数据。我已经在指针上做了很多阅读,但我没有任何运气让它工作。

in

if(dataPoints[i].Time_Data = dataPoints[i+1].Time_Data){

您不检查时间是否相同,则需要:

if(dataPoints[i].Time_Data == dataPoints[i+1].Time_Data){

在第一个

for(int i=0; i<SIZE; i++){

您不考虑读取的元素数,因此您可以访问具有未定义行为的数组的非初始化元素。您必须根据LineCount限制循环,并且由于您使用索引ii+1,因此必须i<LineCount-1结束测试

在第二个

for(int i=0; i < SIZE; i++){

必须是

for(int i=0; i < LineCount; i++){

但请注意,您将打印设置为 NAN 的条目。

为什么是那条线:

你想要
struct Data* structPointer[] = &dataPoints[];

struct Data* structPointer = dataPoints;

并且该新变量是无用的,您可以继续使用dataPoint,因为您可以使用索引而不是通过您递增的指针访问元素。

出于那做

while(fgets(line, sizeof line, fpointer) != NULL){

不考虑可以读取比SIZE更多的元素是危险的,因为您可以使用未定义的行为写出数组,例如

while((LineCount != SIZE) && (fgets(line, sizeof line, fpointer) != NULL)){

您也永远不会检查strtok不返回NULL,如果文件无效,您将以未定义的行为调用atof(NULL),最好检查结果strtok以便在文件无效时中断循环。

此外,atof不会检测到错误,如果文件无效并且不包含有效的浮点数,您将在不知道的情况下处理 0,最好使用例如strtod来检测错误。

当您在这种情况下,在完成所有structPointer[i+1]->xx = NAN;后时间是相同的,最好递增i以跳过数组的该条目。

char Input[80] = "output.csv";
...
const char Deliminator[2] = ",";

可以替换为

const char * const input = "output.csv";
...
const char * const Deliminator = ",";

例如,简化代码并使用动态分配的数组不受虚拟内存大小的限制:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct  Data {
double Time_Data;
double X_Data;
double Y_Data;
double Z_Data;
};
int main(int argc, char *argv[])
{
const char * const input = "output.csv";
FILE * fpointer = fopen(input, "r");

if (fpointer == NULL){
perror("Unable to open file");
return 0;
} 

struct Data * dataPoints = NULL; /* or malloc(0) if you prefer */
int lineCount = 0;
double t,x,y,z;

while (fscanf(fpointer, "%lf,%lf,%lf,%lf", &t, &x, &y, &z) == 4) {
/* may be bypass rest of line */

dataPoints = realloc(dataPoints, sizeof(*dataPoints) * (lineCount + 1));
if (dataPoints == NULL) {
fputs("not enough memory", stderr);
return 0;
}
dataPoints[lineCount].Time_Data = t;
dataPoints[lineCount].X_Data = x;
dataPoints[lineCount].Y_Data = y;
dataPoints[lineCount].Z_Data = z;
lineCount++;
}

fclose(fpointer);

for (int i=0; i<lineCount-1; i++) {
if (dataPoints[i].Time_Data == dataPoints[i+1].Time_Data){
dataPoints[i].X_Data = (dataPoints[i].X_Data + dataPoints[i+1].X_Data)/2;
dataPoints[i].Y_Data = (dataPoints[i].Y_Data + dataPoints[i+1].Y_Data)/2;
dataPoints[i].Z_Data = (dataPoints[i].Z_Data + dataPoints[i+1].Z_Data)/2;

i += 1;
dataPoints[i].Time_Data = NAN;
dataPoints[i].X_Data = NAN;
dataPoints[i].Y_Data = NAN;
dataPoints[i].Z_Data = NAN;
}
}

for (int i=0; i < lineCount; i++) {
printf("%d    %f    %f    %f    %fn", i, 
dataPoints[i].Time_Data,
dataPoints[i].X_Data,
dataPoints[i].Y_Data,
dataPoints[i].Z_Data);
}

free(dataPoints);
return 0;
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -Wall c.c
pi@raspberrypi:/tmp $ cat output.csv 
1,2,3,4
11,22,33,44
11,10,30,40
11,11,31,41
2,20,30,40
3,2,3,4
3,23,33,43
pi@raspberrypi:/tmp $ ./a.out
0    1.000000    2.000000    3.000000    4.000000
1    11.000000    16.000000    31.500000    42.000000
2    nan    nan    nan    nan
3    11.000000    11.000000    31.000000    41.000000
4    2.000000    20.000000    30.000000    40.000000
5    3.000000    12.500000    18.000000    23.500000
6    nan    nan    nan    nan
pi@raspberrypi:/tmp $ 

但通常csv文件有一个标题行,在这种情况下,在读取值之前必须绕过它,例如:

#include <stdlib.h>
#include <math.h>
struct  Data {
double Time_Data;
double X_Data;
double Y_Data;
double Z_Data;
};
int main(int argc, char *argv[])
{
const char * const input = "output.csv";
FILE * fpointer = fopen(input, "r");

if (fpointer == NULL){
perror("Unable to open file");
return 0;
} 

/* bypass header line */
int i;

while (((i = fgetc(fpointer)) != 'n') && (i != EOF))
;

struct Data * dataPoints = NULL; /* or malloc(0) if you prefer */
int lineCount = 0;
double t,x,y,z;

while (fscanf(fpointer, "%lf,%lf,%lf,%lf", &t, &x, &y, &z) == 4) {
/* may be bypass rest of line */

dataPoints = realloc(dataPoints, sizeof(*dataPoints) * (lineCount + 1));
if (dataPoints == NULL) {
fputs("not enough memory", stderr);
return 0;
}
dataPoints[lineCount].Time_Data = t;
dataPoints[lineCount].X_Data = x;
dataPoints[lineCount].Y_Data = y;
dataPoints[lineCount].Z_Data = z;
lineCount++;
}

fclose(fpointer);

for (i=0; i<lineCount-1; i++) {
if (dataPoints[i].Time_Data == dataPoints[i+1].Time_Data){
dataPoints[i].X_Data = (dataPoints[i].X_Data + dataPoints[i+1].X_Data)/2;
dataPoints[i].Y_Data = (dataPoints[i].Y_Data + dataPoints[i+1].Y_Data)/2;
dataPoints[i].Z_Data = (dataPoints[i].Z_Data + dataPoints[i+1].Z_Data)/2;

i += 1;
dataPoints[i].Time_Data = NAN;
dataPoints[i].X_Data = NAN;
dataPoints[i].Y_Data = NAN;
dataPoints[i].Z_Data = NAN;
}
}

for (i=0; i < lineCount; i++) {
printf("%d    %f    %f    %f    %fn", i, 
dataPoints[i].Time_Data,
dataPoints[i].X_Data,
dataPoints[i].Y_Data,
dataPoints[i].Z_Data);
}

free(dataPoints);
return 0;
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -Wall c.c
pi@raspberrypi:/tmp $ cat output.csv 
time,x,y,z
1,2,3,4
11,22,33,44
11,10,30,40
11,11,31,41
2,20,30,40
3,2,3,4
3,23,33,43
pi@raspberrypi:/tmp $ ./a.out
0    1.000000    2.000000    3.000000    4.000000
1    11.000000    16.000000    31.500000    42.000000
2    nan    nan    nan    nan
3    11.000000    11.000000    31.000000    41.000000
4    2.000000    20.000000    30.000000    40.000000
5    3.000000    12.500000    18.000000    23.500000
6    nan    nan    nan    nan
pi@raspberrypi:/tmp $ 

最新更新