Ошибка двойного освобождения с указателем на массив mpz_t

В настоящее время я изучаю libgmp и с этой целью пишу небольшую программу, которая находит основные факторы. Моя программа вызывает функцию, которая заполняет массив различным количеством целых чисел mpz_t, простых множителей заданного числа, которые мне нужно вернуть. Я планирую установить последний элемент в NULL, поэтому я знаю, сколько mpz_t целых чисел найдена функцией.

Моя проблема в том, что я получаю двойные бесплатные ошибки с моим массивом указателей на целые числа mpz_t. Я написал пример кода, иллюстрирующего мою проблему:

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

int main(void)
{
    mpz_t *p = malloc(5*sizeof(mpz_t*));
    mpz_init_set_ui(p[0], 2UL);
    mpz_init_set_ui(p[1], 5UL);
    gmp_printf("%Zd %Zd\n", p[0], p[1]);
    mpz_clear(p[0]);
    mpz_clear(p[1]);
    free(p);
    return 0;
}

2 и 5 печатаются на стандартный вывод, поэтому распределение кажется хорошим. Но я получаю двойную ошибку ниже:

2 5
*** glibc detected *** ./lol: double free or corruption (out): 0x08e20020 ***
======= Backtrace: =========
/lib/libc.so.6(+0x6b6c1)[0xb77126c1]
/lib/libc.so.6(+0x6cf18)[0xb7713f18]
/lib/libc.so.6(cfree+0x6d)[0xb7716f8d]
/usr/lib/libgmp.so.3(__gmp_default_free+0x1d)[0xb77f53fd]
/usr/lib/libgmp.so.3(__gmpz_clear+0x2c)[0xb77ff08c]
./lol[0x80485e3]
/lib/libc.so.6(__libc_start_main+0xe6)[0xb76bdb86]
./lol[0x80484e1]

Я все еще полностью привыкаю к ​​указателям, и gcc не выдает ошибок, однако я вполне уверен, что это неправильно, и я должен делать что-то вроде

mpz_init_set_ui(*p[0], 2UL);

вместо:

mpz_init_set_ui(p[0], 2UL);

Но это дает мне ошибку компилятора

test.c:8: error: incompatible type for argument 1 of ‘__gmpz_init_set_ui’
/usr/include/gmp.h:925: note: expected ‘mpz_ptr’ but argument is of type ‘__mpz_struct’

Во всяком случае, мои вопросы:

  1. Я уверен, что я должен разыменовывать указатель в вызове mpz_init_set_ui(), почему это неправильно?
  2. Есть ли лучший способ сделать это? Должен ли я использовать связанный список?(Я еще не изучил связанные списки, я думаю, что для этого лучше всего подойдет массив, но если я действительно все усложняю, скажите мне) 3. Было бы лучше создать структуру с указателем на мой массив и другой переменной с количеством элементов в моем массиве и вместо этого вернуть указатель на это?

Платформа Linux 32-битная на всякий случай.

Вот код, который у меня есть сейчас, который я хочу изменить, я объявляю массив mpz_t в стеке. Но я хочу сделать main() функцией:

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

#define MAXFACTORS 100

int main(void)
{
    mpz_t numToFactor, factor;
    mpz_t result;/* used to pass return values from getPrimeFactor() */
    mpz_t primeFactors[MAXFACTORS];

    mpz_init_set_str(numToFactor, "18 446 744 073 709 551 615 436 457 568", 10);
    mpz_init(factor);
    mpz_init(result);

    int pFLen = 0;
    mpz_init(primeFactors[pFLen]);

    getPrimeFactor(numToFactor, result);
    mpz_set(factor, result);
    while(mpz_cmp_ui(factor, 0UL))
    {
        mpz_set(primeFactors[pFLen], factor);
        pFLen++;
        if(pFLen == MAXFACTORS)
        {
            puts("Ran out of space to store prime factors, quitting...");
        }
        mpz_init(primeFactors[pFLen]);

        mpz_divexact(factor, numToFactor, factor);
        mpz_set(numToFactor, factor);

        getPrimeFactor(factor, result);
        mpz_set(factor, result);
    }
    mpz_set(primeFactors[pFLen], numToFactor);
    pFLen++;

    int i;
    for(i = 0; i < pFLen; i++)
    {
        gmp_printf("%Zd ", primeFactors[i]);
    }
    puts("");

    mpz_clear(numToFactor);
    mpz_clear(factor);
    return 0;
}

Заранее спасибо людям,

2 ответа

Решение

Эта линия

 mpz_t *p = malloc(5*sizeof(mpz_t*));

скорее всего причина ваших неприятностей. Вы выделили достаточно места для пяти указателей mpz_tс не за 5 mpz_ts. В зависимости от размера mpz_t, вы можете писать после конца массива и т. Д.

Вы хотите сказать

 mpz_t *p = malloc(5*sizeof(mpz_t));

выделить массив из 5 mpz_t.

Просто часть вашего вопроса

mpz_t *p = ...;

p это pointer to mpz_t; p[0] (такой же как *p) это mpz_t, как есть p[1] (такой же как *(p + 1)), ...

mpz_init_set_ui(*p[1], 5UL); /* error */

p[1] это mpz_t, Вы не можете разыменовать это (я думаю).
Вы можете использовать следующий синтаксис, если вы предпочитаете

mpz_init_set_ui(*(p + 1), 5UL);
Другие вопросы по тегам