C阵列结构分割故障

时间:2015-05-01 17:44:51

标签: c arrays pointers struct malloc

我正在尝试创建一个动态的结构数组,我可以成功地为它添加一个结构。但是我添加的任何结构都会导致分段错误。这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PEOPLE_BLOCK 4

struct Person {
    char *first_name;
    char *last_name;
    unsigned int age;
};

int add_person(struct Person **people, size_t *people_size, size_t *population, struct Person p) {

    if ((sizeof(struct Person) * *population) > *people_size) {
        return -1;
    }

    if ((sizeof(struct Person) * (*population + 1)) >= *people_size) {
        *people_size = *people_size + sizeof(struct Person) * PEOPLE_BLOCK;
        *people = realloc(*people, *people_size);
        if (!*people) {
            return -1;
        }
    }

    *people[*population] = p;
    ++*population;

    return 0;
}

int main(int argc, char const *argv[]) {

    size_t population;
    size_t people_size;
    struct Person *people, timn, batman;

    population = 0;
    people_size = sizeof(struct Person) * PEOPLE_BLOCK;
    people = malloc(people_size);

    timn.first_name = "Timn";
    timn.last_name = "Timothy";
    timn.age = 38;
    add_person(&people, &people_size, &population, timn);

    printf("Person 0's first name: %s\n", people[0].first_name);

    batman.first_name = "Bat";
    batman.last_name = "Man";
    batman.age = 42;
    add_person(&people, &people_size, &population, batman);

    printf("Person 1's first name: %s\n", people[1].first_name);

    free(people);

    return 0;
}

我很感激为什么会这样做有任何帮助,谢谢!

3 个答案:

答案 0 :(得分:2)

问题在于这一行:

*people[*population] = p;

将其更改为:

(*people)[*population] = p;

为什么要求括号?

编译器有rules of operator precedence。应用它们时,它会将您的代码视为:

*(people[*population]) = p;

这不是你想要的。给定指向指针Type **pp

*pp[n] = value;

表示“从n开始pp'指针,并在指针所包含的地址取消引用的位置分配value。换句话说,它实际上意味着:

Type *p = pp[n];
*p = value;

Type *p = *pp;
p[n] = value;

这就是(*pp)[n],区分指针与指针的取消引用,给你。没有它,你使用的是无效指针,导致你的错误。

答案 1 :(得分:1)

不确定这个答案是否会有所帮助,但无论如何。 我不明白你的代码,你想要做什么。

您可以直接使用元素数量,指向第一个人的指针以及最大元素数量。你可能会遇到很多问题。

您将文字字符串直接存储在结构中,这意味着在实际情况下(不使用文字)会导致内存泄漏。

这是我的看法。由于测试原因,我把PEOPLE_BLOCK缩小了。 希望这会有所帮助。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PEOPLE_BLOCK 2

typedef struct _Person {
    char *first_name;
    char *last_name;
    unsigned int age;
} Person;

typedef struct _VectorPeople {
    Person * people;
    size_t num;
    size_t max;
} VectorPeople;

void init(VectorPeople *v)
{
    v->max = PEOPLE_BLOCK;
    v->num = 0;
    v->people = (Person *) malloc( sizeof(Person) * v->max );
}

void clear(VectorPeople *v)
{
    // Clear persons
    Person * it = v->people;
    while( ( it - v->people ) < v->num ) {
        free( it->first_name );
        free( it->last_name );

        ++it;
    }

    // Clear vector
    v->max = v->num = 0;
    free( v->people );
    v->people = NULL;
}

void add(VectorPeople *v, Person *p)
{
    // Reserve
    if ( v->num >= v->max ) {
        v->max += PEOPLE_BLOCK;

        // Realloc
        v->people = realloc( v->people, v->max * sizeof(Person) );
        if ( v->people == NULL ) {
            exit( -1 );
        }
    }

    // Copy strings
    p->first_name = strdup( p->first_name );
    p->last_name = strdup( p->last_name );

    // Insert
    v->people[ ( v->num )++ ] = *p;
}

int main(int argc, char const *argv[]) {

    VectorPeople vp;
    Person timn;
    Person batman;
    Person bond;
    Person superman;

    init( &vp );

    timn.first_name = "Timn";
    timn.last_name = "Timothy";
    timn.age = 38;
    add( &vp, &timn );

    batman.first_name = "Batn";
    batman.last_name = "Man";
    batman.age = 42;
    add( &vp, &batman );

    bond.first_name = "James";
    bond.last_name = "Bond";
    bond.age = 45;
    add( &vp, &bond );

    superman.first_name = "Super";
    superman.last_name = "Man";
    superman.age = 45;
    add( &vp, &superman );

    int i = 0;
    for(; i < vp.num; ++i ) {
        printf( "Person: %s, %s.\n", vp.people[ i ].last_name, vp.people[ i ].first_name );
    }
    clear( &vp );
    return 0;
}

答案 2 :(得分:0)

一个问题是add_person()的最后一个参数是具体的,参数&#39;(struct Person)p&#39;。当&#39; timn&#39;和蝙蝠侠&#39;传递到add_person()函数,它们作为原始结构的副本传递。在add_person()结构中,该数据实际上是堆栈上的 ,并且在函数范围之外是volatile。尝试将最后一个参数更改为指针。