質問

私は現在 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;
}

よろしくお願いします。

役に立ちましたか?

解決

この行

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

おそらくあなたの悩みの原因です。あなたはmpz_tsに、ない5 mpz_tsのために5 のポインタのための十分なスペースが割り当てられました。 mpz_tの大きさに応じて、など、配列の末尾を越えて書き込みをすることができます。

あなたが言いたいのでしょう。

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

5つのmpz_t年代のアレイを割り当てる。

他のヒント

あなたの質問のほんの一部。

mpz_t *p = ...;

ppointer 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);
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top