繁体   English   中英

C数组结构分割错误

[英]C array of structs segmentation fault

我正在尝试制作一个动态的结构数组,并且可以成功地向其中添加一个结构。 但是我添加的任何其他结构都会导致分段错误。 这是我的代码:

#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;
}

感谢您对为什么会发生任何帮助,谢谢!

问题在于此行:

*people[*population] = p;

更改为:

(*people)[*population] = p;

为什么要求括号?

编译器具有运算符优先级规则 应用它们时,它将看到您的代码如下:

*(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]区分指针对指针的取消引用的作用。 否则,您将使用无效的指针,从而导致错误。

不确定该答案是否会有所帮助,但是无论如何。 我不了解您的代码,您正在尝试做什么。

您可以直接使用元素数,指向第一人称的指针以及最大元素数。 您可能会在传递这些信息时遇到很多问题。

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

这是我的看法。 由于测试原因,我将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;
}

您的代码中存在许多错误。 要记住的一件事是,当您动态分配内存时, 有责任跟踪它并在不再需要它时释放它(否则,您将像筛子一样泄漏内存)。

在您的代码中,您尝试创建一个结构数组,其中包含指向字符数组的指针。 char *指针未分配,不能简单地按照您尝试的方式分配。 strdup可以提供帮助,但是您刚刚分配了内存,因此请在完成后free它。

尝试分配具有变化的(未知的) first_namelast_name长度的结构数组需要您跟踪每个分配。 从某种意义上说,你是关闭宣告更好的people作为pointer to pointer to Person这样反复在你的people ,而不必存储一些人口让你重复第一至NULL遇到指针。

同样,为您的结构创建typedef可以大大减少您写入sizeof (struct Person) 它可以使代码保持干净,并帮助您思考指针是否模糊。

这是一个使用指针到指针结构的示例,我认为您打算这样做。 下面是仅使用指向struct的指针的实现。 评估两者并确定您更喜欢哪种实现:

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

#define MAXPOP 128

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

Person *add_person (Person ***ppl, Person p, size_t *pop, size_t *max);
Person **realloc_person (Person **ppl, size_t *n);
void free_person (Person *p);
void free_person_names (Person *p);

int main (void) {

    size_t population = 0;
    size_t maxp = MAXPOP;
    size_t i = 0;
    Person timn, batman;
    Person **people = calloc (MAXPOP, sizeof *people);

    if (!people) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return 1;
    }

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

    printf("\nPerson 0\n first name: %s\n last name : %s\n age : %hhu\n",
            people[0]->first_name, people[0]->last_name, people[0]->age);

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

    printf("\nPerson 1\n first name: %s\n last name : %s\n age : %hhu\n",
            people[1]->first_name, people[1]->last_name, people[1]->age);

    for (i = 0; i < population; i++)
        free_person (people[i]);
    free (people);

    return 0;
}

/* add a person to an array of pointers to Person */
Person *add_person (Person ***ppl, Person p, size_t *pop, size_t *max)
{
    if (*pop == *max)
        *ppl = realloc_person (*ppl, max);

    if (!((*ppl)[*pop] = malloc (sizeof ***ppl)))
        return NULL;

    size_t i = (*pop)++;
    (*ppl)[i]-> first_name = strdup (p.first_name);
    (*ppl)[i]-> last_name = strdup (p.last_name);
    (*ppl)[i]-> age = p.age;

    return (*ppl)[i];
}

/* realloc an array of pointers to Person setting memory to 0. */
Person **realloc_person (Person **ppl, size_t *n)
{
    Person **tmp = realloc (ppl, 2 * *n * sizeof *ppl);
    if (!tmp) {
        fprintf (stderr, "Error: struct reallocation failure.\n");
        // return NULL;
        exit (EXIT_FAILURE);
    }
    ppl = tmp;
    memset (ppl + *n, 0, *n * sizeof *ppl); /* memset new ptrs 0 */
    *n *= 2;

    return ppl;
}

/* free memory for a Person */
void free_person (Person *p)
{
    if (!p) return;
    if (p->first_name) free (p->first_name);
    if (p->last_name) free (p->last_name);
    free (p);
}

/* free only names of Person (for temp structs) */
void free_person_names (Person *p)
{
    if (!p) return;
    if (p->first_name) free (p->first_name);
    if (p->last_name) free (p->last_name);
}

注意:已更新以更正重新分配时的ppl起始地址。


仅使用人数组

虽然不是使用指针指向没有本质上的不同Person使用一个简单的指针Person消除了遍历您的阵列,直到能力NULL或(空)指针遇到。 以下是仅使用Person数组的相同代码的实现:

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

#define MAXPOP 128

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

Person *add_person (Person **ppl, Person p, size_t *pop, size_t *max);
Person *realloc_person (Person *ppl, size_t *n);
void free_person_names (Person p);

int main (void) {

    size_t population = 0;
    size_t maxp = MAXPOP;
    size_t i = 0;
    Person timn, batman;
    Person *people = calloc (MAXPOP, sizeof *people);

    if (!people) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return 1;
    }

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

    printf("\nPerson 0\n first name: %s\n last name : %s\n age : %hhu\n", 
            people[0].first_name, people[0].last_name, people[0].age);

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

    printf("\nPerson 1\n first name: %s\n last name : %s\n age : %hhu\n", 
            people[1].first_name, people[1].last_name, people[1].age);

    for (i = 0; i < population; i++)
        free_person_names (people[i]);
    free (people);

    return 0;
}

/* add a person to an array of pointers to Person */
Person *add_person (Person **ppl, Person p, size_t *pop, size_t *max)
{
    if (*pop == *max)
        *ppl = realloc_person (*ppl, max);

    size_t i = (*pop)++;
    (*ppl)[i].first_name = strdup (p.first_name);
    (*ppl)[i].last_name = strdup (p.last_name);
    (*ppl)[i].age = p.age;

    return ppl[i];
}

/* realloc an array Person setting memory to 0. */
Person *realloc_person (Person *ppl, size_t *n)
{
    Person *tmp = realloc (ppl, 2 * *n * sizeof *ppl);
    if (!tmp) {
        fprintf (stderr, "Error: struct reallocation failure.\n");
        // return NULL;
        exit (EXIT_FAILURE);
    }
    ppl = tmp;
    memset (ppl + *n, 0, *n * sizeof *ppl); /* memset new ptrs 0 */
    *n *= 2;

    return ppl;
}

/* free only names of Person (for temp structs) */
void free_person_names (Person p)
{
    if (p.first_name) free (p.first_name);
    if (p.last_name) free (p.last_name);
}

产量

$ ./bin/struct_add_person

Person 0
 first name: Timn
 last name : Timothy
 age : 38

Person 1
 first name: Bat
 last name : Man
 age : 42

一个问题是add_person()的最后一个参数要具体化,即参数“(struct Person)p”。 将“ timn”和“ batman”传递到add_person()函数时,它们将作为原始结构的副本传递。 在add_person()结构中,该数据实际上位于堆栈上,并且在函数范围之外是易失的。 尝试将最后一个参数更改为指针。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM