我正在尝试创建一个函数,在其中读取时间和 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限制循环,并且由于您使用索引i和i+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 $