无效写入 Valgrind

Invalid Write Valgrind

我正在编写一个函数,它将 Person 插入到指向 Person 的指针数组中,其中 Person 定义为:

typedef struct Person {
    char *name;
    int age;
} Person;

而我的插入方法是:

static void insert(Person **arr, char *name, int age) {
    static int next_free_place = 0;
    /* put name and age into the next free place in the array parameter here */
    Person *next_person = malloc(sizeof(Person));
    if (!next_person) {
        fprintf(stderr, "Failed to allocate memory");
        exit(-1);
    }
    next_person->name = name;
    next_person->age = age;
    *(arr + next_free_place) = next_person;  // INVALID WRITE HERE FROM VALGRIND

    // move on to next location
    next_free_place++;
}

我的主要:

int main(int argc, char **argv) {

    /* declare the people array here */
    Person **people = NULL;

    for (int i = 0; i < HOW_MANY; i++) {
        insert(people, names[i], ages[i]);
    }

    /* print the people array here*/
    for (int i = 0; i < HOW_MANY; i++) {
        printf("Name: %s, Age: %d\n", people[i]->name, people[i]->age);
    }

    free(people);
    return 0;
}

在头文件中:

#define HOW_MANY 7
char *names[HOW_MANY]= {"Simon", "Suzie", "Alfred", "Chip", "John", "Tim",
                      "Harriet"};
int ages[HOW_MANY]= {22, 24, 106, 6, 18, 32, 24};

当我 运行 我的程序时,我得到 Segmentation Fault 并且 Valgrind 显示存在如上所述的无效写入。
我可以知道为什么会发生这种情况以及如何解决吗?

这里的问题是人们没有指向任何地方。您必须静态创建一个数组,或为其分配动态内存。

最初,Person **people = NULL;。当您调用 insert() 时,**arr 将指向 NULL。

现在,当您执行 *(arr + next_free_place) = next_person; 时,您正在尝试取消引用 NULL 指针,这导致了问题。

解法:

// Static memory - Array of "HOW_MANY" pointers. In this case memory will be 
// allocated on stack. It automatically gets freed once the variable goes 
// out of scope. No explicit free() is required.
Person *people[HOW_MANY] = {NULL}; //Entire memory is set to 0/NULL automatically

// OR

// Dynamic memory - Allocate memory for "HOW_MANY" pointers.In this case 
// memory will be allocated on heap. Explicit free(people); is required.
Person **people = malloc(sizeof(Person*)*HOW_MANY);
if(NULL == people ) {/* handle this case */}
memset(people, 0x00, sizeof(Person*)*HOW_MANY); //You need to reset memory explicitly

对于初学者,您没有为指向 Person 类型的 object 的指针数组分配内存。因此,当您尝试取消引用指针 people(或函数内的 arr)时,程序具有未定义的行为:

*(arr + next_free_place) = next_person;

其次,您还需要为数组中的每个 object 释放所有分配的内存。

考虑到将变量定义放在 header 中是个坏主意。当 header 包含在多个翻译单元中时,这可能会导致链接器错误。您应该在 header 中仅放置变量声明而不使用说明符 extern 定义变量。定义应放在模块中。

这是您更新后的程序。

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

#define HOW_MANY 7

char *names[HOW_MANY] = 
{
    "Simon", "Suzie", "Alfred", "Chip", "John", "Tim", "Harriet"
};

unsigned int ages[HOW_MANY]= { 22, 24, 106, 6, 18, 32, 24 };

typedef struct Person 
{
    const char *name;
    unsigned int age;
} Person;

enum RETURN_CODES { Success, Full, NotEnoughMemory };

static int insert( Person **arr, const char *name, unsigned int age ) 
{
    static size_t next_free_place = 0;

    if ( next_free_place == HOW_MANY ) return Full;

    /* put name and age into the next free place in the array parameter here */
    arr[next_free_place] = malloc( sizeof( Person ) );

    if ( arr[next_free_place] == NULL ) return NotEnoughMemory;

    arr[next_free_place]->name = name;
    arr[next_free_place]->age  = age;

    ++next_free_place;

    return Success;
}

int main(void) 
{
    Person **people = calloc( HOW_MANY, sizeof( Person * ) );

    for ( int i = 0; i < HOW_MANY; i++ ) 
    {
        insert( people, names[i], ages[i] );
    }

    for ( int i = 0; i < HOW_MANY; i++ ) 
    {
        printf( "Name: %s, Age: %u\n", people[i]->name, people[i]->age );
    }

    for ( int i = 0; i < HOW_MANY; i++ ) free( people[i] );

    free( people );

    return 0;
}

程序输出为

Name: Simon, Age: 22
Name: Suzie, Age: 24
Name: Alfred, Age: 106
Name: Chip, Age: 6
Name: John, Age: 18
Name: Tim, Age: 32
Name: Harriet, Age: 24