重新分配包含动态大小的char指针的结构数组

时间:2017-02-13 21:42:50

标签: c dynamic struct realloc

此分配的目的是从包含城市状态的文件中读取一行,后跟两行包含纬度和经度坐标的行。然后我们需要完全按照下面的描述动态分配结构来存储这些坐标。最后,我们将地标导出为google earth使用的KML格式。

此时我可以从我的结构中正确编写KML。然而,在我的grow_whole函数中有几个脏for循环(见下文)。问题是我稍后释放所有已分配的指针。 (相信我,它存在以下的顺序粘贴它)。我很确定问题是堆损坏。然而,我一直在这方面工作太久,我觉得它可以更简单。

文件格式。 (其中有150个。)

city, state
40 30 N
40 20 W

Wholesome_t只是一个容器,可以保存有关地标结构数量的信息以及指向第一个地标的指针。 Landmark_t保存着指向字符的指针,这些字符分配了他们需要包含解析的城市名称所需的空间量等等。

struct landmark_t {
char *city;
char *state;
char *country;
float longitude;
float latitude;
};

struct wholesome_t {
struct landmark_t *landmarks;
int landcount;
int landmax;
};

下面是处理读取行并将它们发送到正确解析器的代码块。

最初有益健康的是malloc' d并且地标指针设置为NULL。 然后我们malloc空间为2个标志性结构,并开始下面的while循环。

struct landmark_t *land = NULL;
int coorflag = 0;
int flagcount = 0;
//Parse lines
while(fgets(buf, LEN, in)){
    //Does that thing where we realloc
    if(whole->landcount == whole->landmax){
        grow_whole(whole);
    }

    //remove trailing newline
    buf[strcspn(buf, "\n")] = 0;

    if(!coorflag){//Check to see if we are on a flag or coordinate
        //set land to be the pointer to our next empty landmark struct
        land = whole->landmarks + (sizeof(struct landmark_t) * whole->landcount);
        set_city_state_country(buf, land);
        coorflag = 1; //Set flag to get a coordinate line next
    }else{//We are on a coordinate line which will use 
          //the same land struct pointer as above
        if(!flagcount){//Have we seen a coordinate line already?
            land->latitude = number_muncher(buf);
            flagcount = 1;
        }else{//We have seen a coordinate line
            land->longitude = number_muncher(buf); 
            //We are done filling this structure. Reset flags and move to the next.
            flagcount = 0;
            coorflag = 0;
            whole->landcount++;
        }
    }
}

问题在于grow_whole。我之前遇到过一个问题,在运行realloc之后,第一个地标结构将包含正确分配的指针,但是在它之后的任何地方,直到靠近文件末尾的某个地方,所有城市,州和国家以及经度和纬度的指针都将是被淘汰了。我添加了for循环,在我们重新分配之前保存了所有指向数组的指针,然后将这些指针重写回正确的结构。

void grow_whole(struct wholesome_t *whole)
{
//First collect all of the pointers inside our current landmark structs.
struct landmark_t *land = NULL;
char *city[whole->landcount];
char *state[whole->landcount];
char *country[whole->landcount];
float longitude[whole->landcount];
float latitude[whole->landcount];
for (int i = 0; i < whole->landcount; i++){
    land = whole->landmarks + (sizeof(struct landmark_t) * i);
    city[i] = land->city;
    state[i] = land->state;
    country[i] = land->country;
    longitude[i] = land->longitude;
    latitude[i] = land->latitude;
}
land = realloc(whole->landmarks, (GROW + whole->landmax) * sizeof(struct landmark_t));
if(land == NULL){
    printf("Error in grow_whole.\n");
    return;
}else{whole->landmarks = land;}
//Update landmax to represent aftergrow.
whole->landmax = GROW + whole->landmax;
//Refill all of the re allocated structs with their pointers.
for (int i = 0; i < whole->landcount; i++){
    land = whole->landmarks + (sizeof(struct landmark_t) * i);
    land->city = city[i];
    land->state = state[i];
    land->country = country[i];
    land->longitude = longitude[i];
    land->latitude = latitude[i];
}
//Fill two new structs with blank data.
for(int i = whole->landcount; i < whole->landmax; i++){
    land = whole->landmarks + (sizeof(struct landmark_t) * i);
    empty_fill(land);
}
return;
}

在上面的while循环之后立即运行

fclose(in);
char *s = argv[1];
s = strtok(s, ".");
s = strncat(s, ".kml", 4);
FILE *out = fopen(s, "w");
//Finally done lets write some KML
kml_begin(out);
for (int i=0; i < whole->landcount; i++){
    land = whole->landmarks + (sizeof(struct landmark_t) * i);
    kml_placemark(out, i, land);
}
kml_end(out);
fclose(out);
tea_party(whole);//free land
free(whole->landmarks);
free(whole);

哪个到达kml_end(out)。 (我知道因为我的格式正确,格式正确.kml文件)但是在tea_party期间,我得到了一个seg_fault。

void tea_party(struct wholesome_t *whole)
{
    struct landmark_t *land = NULL; 
    for (int i = 0; i < whole->landcount; i++){
        land = whole->landmarks + (sizeof(struct landmark_t) * i);
        printf("here\n");
        free(land->city);
        printf("here2\n");
        free(land->state);
        printf("here3\n");
       free(land->country);
    }
return;
}

它出现在我们的第二个里程碑结构中。

land = whole->landmarks + sizeof(struct landmark_t)

并且在free(land-&gt;状态)发生(因为我在这里看到第一个结构的1-3,然后在seg错误之前的1-2)。

即使我尝试在seg故障之前打印land-&gt;状态,它也只是将seg故障向上移动。

1 个答案:

答案 0 :(得分:0)

在进行指针运算时,您不必按sizeof(struct landmark_t)缩放偏移量 - 编译器已经为您执行了此操作!

如果指针p在数组中,则下一个数组元素位于p + 1。就这么简单。

此外,当您应该创建一个记录数组时,您似乎创建了一个数组记录。但这是一个不同的问题。