我试图弄清楚如何修改我的代码以实际允许我在readFile中创建一个结构数组,然后将数组返回到main。
这是我的数据结构
struct data{
char *model;
float engineSize;
int cost;
char *color;
};
这是我当前设置的readFile函数,然后是我目前用于此函数的调用。
struct data * readFile(){
FILE *fp;
int c;
int count = 0;
char *line = NULL;
size_t len = 0;
fp = fopen("hw3.data", "r");
while ((c = fgetc(fp)) != EOF){
count++;
}
if (feof(fp)){
rewind(fp);
struct data *vehicles = malloc((sizeof(struct data))* count);
count = 0;
char *token = NULL;
while (getline(&line, &len, fp)!= -1){
printf("%s", line);
token = strtok(line, " ");
vehicles[count].model = token;
token = strtok(NULL, " ");
vehicles[count].engineSize = atof(token);
token = strtok(NULL, " ");
vehicles[count].cost = atoi(token);
token = strtok(NULL, " ");
vehicles[count].color = token;
}
}
}
这是我拥有菜单的主要地方,我将调用readFile函数。
int main(){
int check = 1;
int input;
while (check == 1){
printf("Enter a value corresponding to a option on the menu below\n\n");
printf("1. Sort data by the float value & print high to low\n");
printf("2. Sort data by the float value & print low to high\n");
printf("3. Sort data by the int value & print high to low\n");
printf("4. Sort data by the int value & print low to high\n");
printf("5. Exit\n\n");
printf("Enter a value corresponding to the above menu\n");
scanf("%d", &input);
//readFile()
if(input == 1 || input == 2 || input == 3 || input == 4 || input == 5){
if (input == 5){
exit(0);
}if (input == 1){
//sort float high to low
}if (input == 2){
//sort float low to high
}if (input == 3){
//sort int value high to low
}if (input == 4){
//sort int value low to high
}
}else{
printf("Enter a correct value for the menus above\n\n" );
}
readFile();
}
}
由于
答案 0 :(得分:2)
这几乎是正确的,这个想法还可以,但有一些问题:
while ((c = fgetc(fp)) != EOF){
count++;
}
计算字节数,我想根据你想要的后面的代码 行数。
while ((c = fgetc(fp)) != EOF){
if(c == '\n')
count++;
}
会给你一些行数。
在那里
token = strtok(line, " ");
vehicles[count].model = token;
...
token = strtok(NULL, " ");
vehicles[count].color = token;
是有效的,但也许不是你想要的。 strtok
成功返回line + some_offset
,因此如果您以后需要
您可以添加更多字符到vehicles[i].mode
或vehicles[i].color
覆盖记忆。 vehicles[i].color
只是偏移量
vehicles[i].model
。如果您甚至想重新分配,realloc
将失败,
因为你不会在请求的内存开头重新分配
块。通过这样做,你将失去所请求的内存的开始,
它会泄漏内存,因为你无法释放它(free(vehicles[i].color)
是
无效) 1 。
另一个问题是只有初始线犯规才有正确数量
分配内存,如果你使用非getline
指针调用NULL
非零长度,getline
将在必要时重新分配内存并更新
指针和长度。如果重新分配返回相同的地址,那么你的
以前的值将被覆盖。如果重新分配返回a
不同的地址,你以前的指针将变为无效。
我建议(并且我认为这是唯一安全的方法)您使用strdup
(如果可用,或malloc
+ strcpy
执行令牌副本)
之后:
while (getline(&line, &len, fp)!= -1){
// the strtok calls
...
free(line);
line = NULL;
len = 0;
}
通过这种方式,您的代码不会泄漏内存,也不会覆盖内存。
修改强>
我应该改为使用strcpy设置模型和颜色的值
您可以使用strcpy
,但您需要先分配内存,因为
model
和color
只是指针。 malloc
只调用保留的内存,
它没有初始化它。所以只是做
strcpy(vehicles[count].model, token);
会出错,因为你会尝试复制未定义的东西 地点。这就是我的意思
我建议(并且我认为这是唯一安全的方法),您使用
strdup
(如果可用,或malloc
+ {{}执行令牌的副本1}})强>
strcpy
函数vehicles[count].model = malloc(strlen(token) + 1);
if(vehicles[count].model == NULL)
{
// error handling
// for example
// free everything and return
return NULL;
}
strcpy(vehicles[count].model, token);
基本上是这样做的:strdup
+ malloc
,所以如果你的话
系统有strcpy
你可以这样做:
strdup
另一个选择是改变你的结构,而不是指向
vehicles[count].model = strdup(token);
if(vehicles[count].model == NULL)
{
// error handling
// for example
// free everything and return
return NULL;
}
,使用char
数组:
char
现在你可以保存最大长度为99个字符的字符串(应该足够了)
对于模型名称和颜色而言,只需使用struct data{
char model[100];
float engineSize;
int cost;
char color[100];
};
,而无需使用
额外的内存分配:
strncpy
此外,我还没有机会更改免费代码(line)line = null和len = 0
我不知道你的意思。只需在
之后添加行strncpy(vehicles[count].model, token, sizeof vehicles[count].model);
// making sure to terminate the string
vehicles[count].model[sizeof(vehicles[count].model) - 1] = 0;
在vehicles[count].color = token;
循环结束之前。
那么我也应该像通过文件的第二次迭代一样使用get行,因为我目前正在分配?
第二个循环很好,问题是你被分配了相同的(+
偏移)内存位置到不同的指针以及while
何时重新分配
并获取一个不同的地址,前一个指针变为无效。这就是
getline
很重要,你肯定应该这样做。
总结一下:你的循环很好,但你需要做出这些改变:
free(line);
line = NULL;
len = 0;
的副本或更改结构以使用token
数组添加
char
循环结束时的行,你会没事的。
<强> fotenotes 强>
1 free(line);
line = NULL;
len = 0;
只会指向内存的开头
阻止当且仅当该行不以空白空格开头时。就像你一样
阅读文件,你不能保证这是真的。即使它是
是的,我不会指望这一点。更好地做好安全的事情,做一个
复制。 vehicles[i].mode
肯定是错的。