Проблема со свободной функцией в C для указателей - PullRequest
0 голосов
/ 21 января 2019

У меня есть два указателя, и я хочу заполнить указатель somme значениями, содержащимися в указателе v.

Это метод:

somme[0]=v[0] + v[1];
somme[1]=v[2] + v[3];
somme[2]=v[4] + v[5];

...

Ошибка возникает при выполнении функции distruggi_vec(somme);, а не distruggi_vec(v);.

у вас есть идеи? Спасибо за ваше время.

Это мой код c:

#include <stdlib.h>
#include <stdint.h>

extern uint32_t *crea_vec(size_t  n)
{
    uint32_t *p;
    p = malloc(n * sizeof(uint32_t));
    for (size_t i = 0; i < n; ++i)
    {
        p[i] = i;
    }

    return p;
}

uint32_t *somme_2a2(uint32_t *vett, size_t size) 
{
    if (size % 2 != 0) 
    {
        size = size - 1;
    }

    size_t j = 0;
    for (size_t i = 0; i < size; ++i) 
    {
        if (i >= 10) { goto a; }
        j = i * 2;
        vett[i] = vett[j] + vett[j + 1];
    }
    a:
    size = size / 2;
    vett = realloc(vett, size * sizeof(uint32_t));

    return vett;
}

extern void distruggi_vec(uint32_t *p)
{
    free(p);
}

int main(void) 
{
    size_t n = 20;
    uint32_t *v = crea_vec(n);
    uint32_t *somme = somme_2a2(v, n);
    distruggi_vec(v);
    distruggi_vec(somme);

    return 0;
}

когда я отлаживаю свой код, возникает проблема:

Ответы [ 3 ]

0 голосов
/ 21 января 2019

Неважно, сколько звонков на realloc вы делаете, вы все равно будете иметь только один указатель: один последний , возвращаемый malloc, calloc или realloc.

После вызова realloc исходный указатель становится недействительным, и вы должны использовать только тот указатель, который он возвращает.

Это означает, что при вызове distruggi_vec с неверным указателем v у вас будет неопределенное поведение .

0 голосов
/ 21 января 2019

Спасибо всем за потраченное время, это окончательное решение моей проблемы без ошибок:

Код:

`

#include <stdlib.h>
#include <stdint.h>

extern uint32_t *crea_vec(size_t  n)
{
    uint32_t *p;
    p = malloc(n * sizeof(uint32_t));
    for (size_t i = 0; i < n; ++i)
    {
        p[i] = i;
    }

    return p;
}

uint32_t *somme_2a2(uint32_t *vett, size_t size) 
{
    uint32_t *vett2 = calloc(size/2, sizeof(uint32_t));
    if (size % 2 != 0) 
    {
        size = size - 1;
    }

    size_t j = 0;
    for (size_t i = 0; i < size; ++i) 
    {
        if (i >= 10) { break; }
        j = i * 2;
        vett[i] = vett[j] + vett[j + 1];
        vett2[i] = vett[i];
    }

    return vett2;
}

extern void distruggi_vec(uint32_t *p)
{
    free(p);
}

int main(void) 
{
    size_t n = 20;
    uint32_t *v = crea_vec(n);
    uint32_t *somme = somme_2a2(v, n);
    distruggi_vec(v);
    distruggi_vec(somme);

    return 0;
}

`

0 голосов
/ 21 января 2019

Прежде всего, не пишите код вроде

 vett = realloc(vett, size * sizeof(uint32_t));

в случае сбоя realloc() вы также потеряете исходный указатель.

Из C11, глава §7.22.3.5

Если память для нового объекта не может быть после выделения старый объект не освобождается, а его значение не изменяется.

и

Функция realloc возвращает указатель на новый объект (который может иметь тот же значение как указатель на старый объект), или нулевой указатель, если новый объект не может быть выделяется.

Всегда перехватывайте возвращаемое значение realloc() во временном указателе, сверяйте его с NULL и, если оно допустимо, вы можете (необязательно) присвоить его исходному указателю. Нечто подобное (псевдокод)

pointer temp = NULL;
temp = realloc (oldPOinter, size);
if (!temp) 
{
    printf ("Some error message");
    return SOME_ERROR_CODE;
}
oldPOinter = temp;

Тем не менее, проблема здесь в том, что в случае успеха realloc() исходный указатель больше не будет использоваться. v передается somme_2a2() в качестве аргумента, а в соответствии с C - передачей по значению. Таким образом, любое изменение, внесенное в vett, не будет отражено для вызывающего абонента в v.

Однако, поскольку realloc() меняет действительность указателя памяти на vett, после успешного возврата из вызова somme_2a2() в main(), v больше не действует, и вы не не нужно передавать это free().

Цитата C11, глава §7.22.3.5

Функция realloc освобождает старый объект, на который указывает ptr, и возвращает указатель на новый объект, размер которого указан size. [...]

Передача vett в free() приведет к неопределенному поведению, потому что вы в конечном итоге попытаетесь free() указатель, который уже был free() -d [через успех realloc()].

Цитировать главу §7.22.3.3

[...] если аргумент не совпадает с указателем, ранее возвращенным управлением памятью функции, или если пространство было освобождено путем вызова free или realloc, поведение не определено.

...