Неверная запись Valgrind - PullRequest
       47

Неверная запись Valgrind

1 голос
/ 26 сентября 2019

Я пишу функцию, которая вставляет 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++;
}

My main:

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 показывает, что запись невернакак указано выше.
Могу ли я знать, почему это происходит и как это решить?

Ответы [ 2 ]

1 голос
/ 26 сентября 2019

Для начала вы не выделяли память для массива указателей на объекты типа Person.Таким образом, программа имеет неопределенное поведение, когда вы пытаетесь разыменовать людей-указателей (или arr внутри функции):

*(arr + next_free_place) = next_person;

Во-вторых, вам также необходимо освободить всю выделенную память для каждого объекта в массиве.

Учтите, что помещать определения переменных в заголовки - плохая идея.Это может привести к ошибке компоновщика, когда заголовок включен в несколько блоков перевода.Вы должны размещать в заголовке только объявления переменных без их определений с использованием спецификатора 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
1 голос
/ 26 сентября 2019

Проблема в том, что люди никуда не указывают.Вы должны создать массив статически или выделить для него динамическую память.

Изначально 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. No 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...