这是我在堆栈溢出时的第一篇文章,希望有人能指出我正确的方向。我正在写一个C函数,我的目标是读取一个csv文件。然后,文件中的数据将传递到结构数组,然后我想返回到main()中的函数调用,以访问数据以备将来使用。如何正确读取然后返回完整的结构数组?
此功能是现有PLC程序的附加功能,此刻所有系统参数都存储在保留存储器中。目的是将参数读/写到CSV文件中以进行备份。我怀疑我在while循环中做错了什么,但目前还无法弄清楚是什么。也可能是我没有正确使用指针。 CSV文件如下所示:
2;motor nominal current;1700
3;motor nominal speed;2500.0
4;motor nominal power;1200.0
5;motor nominal voltage;690.0
6;Enable motor heating;TRUE
7;Motor heating time on;40.0
我很清楚我没有释放函数中分配的内存。这将进一步处理。
这是包含以下功能的程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BSIZE 80
struct parameter{
int id;
char *name;
char *value;
};
struct parameter* readCSV(const char *file)
{
char buffer[BSIZE];
FILE *f;
char *field;
// open the CSV file
f = fopen(file,"r");
if( f == NULL)
{
printf("Unable to open file '%s'\n",file);
exit(1);
}
static struct parameter *parameters[BSIZE];
int i = 0;
// read the data
while(fgets(buffer,BSIZE,f) != NULL)
{
parameters[i] =(struct parameter*)malloc(sizeof(struct parameter));
// get id
field = strtok(buffer,";");
parameters[i]->id = atoi(field);
// get name
field = strtok(NULL,";");
parameters[i]->name = field;
// get value
field = strtok(NULL,";");
parameters[i]->value = field;
// display the result
printf("ID%d:\t%s\t%s\n",parameters[i].id, parameters[i].name, parameters[i].value);
i++;
}
//close file
fclose(f);
return *parameters;
}
int main()
{
struct parameter *parameters;
parameters = readCSV("QD_Config.csv");
printf("ID%d:\t%s\t%s\n",parameters[0]->id, parameters[0]->name, parameters[0]->value);
return(0);
}
我能够打印文件的内容,但是在传递它之前无法正确存储结构数组。在main()中,调用函数时,我只获得文件中的姓氏和值,但具有名字的ID号。
答案 0 :(得分:0)
您(可能)遇到的问题是strtok
函数返回了指向您要标记的字符串的指针。它不会为您创建新的字符串。
例如,
field = strtok(NULL,";");
parameters[i]->name = field;
将使parameters[i]->name
指向buffer
中的某个字符。一旦函数readCSV
返回变量buffer
,它的生命周期就会结束并不再存在,从而使您留下无效的指针。
您需要自己为字符串分配内存并将数据复制到它们。这可以通过以下方式完成:将结构成员数组制成并使用strcpy
将字符串复制到这些数组中,或者使用非标准但通用的strdup
函数(该函数动态分配堆内存和将字符串复制到其中。
还有另一个与返回结构有关的问题:
return *parameters;
等于
return parameters[0];
也就是说,您将返回一个指向单个parameter
结构的指针。
如果要返回整个数组,则应该这样做
return parameters; // Return the whole array
但是请注意,它会衰减为指向类型为¶meters[0]
的第一个元素(即struct parameter **
)的指针,因此您需要适当地调整返回类型。
您还需要将parameters
初始化为空指针,否则将很难找到数组的结尾:
static struct parameter *parameters[BSIZE] = { NULL };
但是,我更推荐一个更好的解决方案,是将数组作为参数传递,并返回要填充的元素数。然后可以使用结构对象数组(而不是结构指针数组) ),而不必进行任何动态分配,也可以避免内存泄漏的风险。
答案 1 :(得分:0)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BSIZE 80
struct parameter{
int id;
char *name;
char *value;
struct parameter *next;//If you dont sure how many lins in csv you need this
};
typedef struct parameter parameter;
//I'm lazy too type struct
parameter* CreateNewQ_Q(){
parameter *Q_Q=(parameter*)malloc(sizeof(parameter));
Q_Q->name=NULL;//Nothing at first
Q_Q->value=NULL;//Nothing at first
Q_Q->next=NULL;//Nothing at first
return Q_Q;
}
void readCSV(const char *file,parameter *Q_Q)
{
char buffer[BSIZE];
FILE *f;
char *field;
parameter* A_A=Q_Q;
// open the CSV file
f = fopen(file,"r");
if( f == NULL)
{
printf("Unable to open file '%s'\n",file);
exit(1);
}
// read the data
while(fgets(buffer,BSIZE,f) != NULL)
{
if(A_A->next==NULL){//Next Nothing So Create after it
A_A->next=CreateNewQ_Q();
}
A_A=A_A->next;//A_A is New A_A now
// get id
field = strtok(buffer,";");
A_A->id = atoi(field);
// get name
field = strtok(NULL,";");
//Q_Q
//<--------Here alloc memory for your name because strtok not alloc new memory it just return a pointer in buffer[?]-------------->
A_A->name=(char *)malloc((sizeof(strlen(field)+1)*sizeof(char)));//+1 Becuz '\0' at end of string is necessary
//<--------Here Copy Result-------------->
strcpy(A_A->name, field);
//Q_Q
// get value
field = strtok(NULL,";");
//Q_Q
//<--------Here alloc memory for your value because strtok not alloc new memory it just return a pointer in buffer[?]-------------->
A_A->value=(char *)malloc((sizeof(strlen(field)+1)*sizeof(char)));//+1 Becuz '\0' at end of string is necessary
//<--------Here Copy Result-------------->
strcpy(A_A->value, field);
//Q_Q
// display the result
printf("ID%d:\t%s\t%s\n",A_A->id, A_A->name, A_A->value);
}
//close file
fclose(f);
}
void DeleteAllQ_Q(parameter *Q_Q){
if(Q_Q->next){
DeleteAllQ_Q(Q_Q->next);
Q_Q->next=NULL;
}else{
free(Q_Q->name);//I dont have next so i'm free
free(Q_Q->value);
free(Q_Q);
}
}
int main()
{
//memory control is important!!!!!!!!!!!!!!
parameter *parameters=CreateNewQ_Q();
readCSV("QD_Config.csv",parameters);
printf("Ok Load Done A_A\n");
for(parameter *loopQ_Q=parameters->next;loopQ_Q!=NULL;loopQ_Q=loopQ_Q->next){
printf("ID%d:\t%s\t%s\n",loopQ_Q->id, loopQ_Q->name, loopQ_Q->value);
}
DeleteAllQ_Q(parameters);//free parameters's next and next's next and....
free(parameters);//free self
return(0);
}
我花了一段时间,我认为这种方法控制内存更安全!