【问题标题】:Realloc an array of structs that contain dynamically sized char pointersRealloc 包含动态大小的 char 指针的结构数组
【发布时间】:2017-07-02 00:43:26
【问题描述】:

这个任务的重点是从一个包含城市状态的文件中读取一行,然后读取包含纬度和经度坐标的两行。然后我们需要像下面写的那样动态分配结构来存储这些坐标。最后,我们将地标导出为 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 的,并且 landmarks 指针设置为 NULL。 然后我们为 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->state) (因为我在这里看到第一个结构的 1-3,然后在 seg 错误之前看到这里的 1-2。)

即使我尝试在 seg 故障之前打印land->state,它只会将 seg 故障向上移动。

【问题讨论】:

    标签: c dynamic struct realloc


    【解决方案1】:

    在进行指针运算时,您不必将偏移量缩放sizeof(struct landmark_t) - 编译器已经为您做到了!

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-10
      • 2013-09-02
      • 2015-02-04
      • 1970-01-01
      相关资源
      最近更新 更多