2009-12-12 4 views
1

J'apprends actuellement libgmp et à cette fin j'écris un petit programme qui trouve les facteurs premiers. Mon programme appelle une fonction qui remplit un tableau avec une quantité variable d'entiers mpz_t, facteurs premiers d'un nombre donné, que j'ai besoin de retourner. Je prévois de mettre le dernier élément à NULL, donc je sais combien de mpz_t entiers la fonction trouvée.double erreur libre avec le pointeur vers le tableau de mpz_t

Mon problème est que j'obtiens des doubles erreurs libres avec mon tableau de pointeurs vers des entiers mpz_t. J'ai rédigé un exemple de code illustrant mon problème:

#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 et 5 sont imprimés à stdout, si l'allocation semble bien. Mais je reçois la double sans erreur ci-dessous:

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] 

Je suis encore totalement habitué à obtenir des pointeurs, et gcc donne aucune erreur, mais je suis assez sûr que ce ne va pas et que je devrais faire quelque chose comme

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

au lieu de:

mpz_init_set_ui(p[0], 2UL); 

Mais cela me donne une erreur du compilateur

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’ 

Quoi qu'il en soit, mes questions sont les suivantes:

  1. Je suis sûr que je devrais déréférencement le pointeur dans la mpz_init_set_ui() appel, pourquoi est-ce mal?
  2. Y a-t-il une meilleure façon de procéder? Dois-je utiliser une liste chaînée (je n'ai pas encore appris les listes chaînées, je pense qu'un tableau est le meilleur pour cela, mais si je suis vraiment en train de compliquer les choses, dites-le moi) 3.Fait-il mieux struct avec un pointeur vers mon tableau et une autre variable avec la quantité d'éléments dans mon tableau et retourner un pointeur à la place?

La plate-forme est Linux 32 bits juste au cas où cela est pertinent.

Voici le code que je viens de faire, que je veux modifier, je déclare le tableau de mpz_t sur la pile. Mais je veux faire main() une fonction:

#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; 
} 

Merci à l'avance, les gens

+0

pourriez-vous poster le reste du code? –

Répondre

3

Cette ligne

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

est probablement la cause de vos problèmes. Vous avez alloué suffisamment d'espace pour cinq pointeurs à mpz_t s, pas pour 5 mpz_t s. En fonction de la taille d'un mpz_t, vous pourriez écrire après la fin du tableau, etc.

Vous voulez dire

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

à allouent un tableau de 5 années mpz_t.

+1

J'aime utiliser l'objet lui-même pour l'argument sizeof: 'mpz_t * p = malloc (5 * sizeof p);' :-) – pmg

+3

pmg, je fais, sauf que vous voulez dire 'sizeof * p' ici, ou bien vous avez le même problème que l'OP;) –

+0

Je m'en souviendrai, je n'ai jamais pensé à utiliser l'objet. Ne cesse jamais de m'étonner à quel point le code est complexe, mais la syntaxe est assez petite. Merci à tous! – CalumMcCall

2

seulement une partie de votre question

mpz_t *p = ...; 

p est un pointer to mpz_t; p[0] (comme *p) est un mpz_t, comme p[1] (comme *(p + 1)), ...

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

p[1] est un mpz_t. Vous ne pouvez pas le déréférencer (je pense).
Vous pouvez utiliser la syntaxe suivante si vous préférez

mpz_init_set_ui(*(p + 1), 5UL); 
Questions connexes