web-dev-qa-db-fra.com

erreur en C en utilisant malloc: taille corrompue vs taille_précédente

J'ai trouvé une réponse pour python mais je ne l'ai pas comprise.

Le code est un tri de fusion modifié. Cela fonctionne bien pour un petit nombre d'entrées que j'ai vérifiées jusqu'à 10. Mais quand je l'ai exécuté par un juge en ligne, lorsque le nombre d'entrées était élevé (500), cela m'a donné cette erreur:

Error in 'a.out': corrupted size vs. prev_size: 0x0000000000d5b8b0
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f3b83a5b7e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x80dfb)[0x7f3b83a64dfb]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f3b83a6853c]
a.out[0x4009d1]
a.out[0x400ac7]
a.out[0x400a87]
a.out[0x400aa4]
a.out[0x400a87]
a.out[0x400bc7]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f3b83a04830]
a.out[0x4005b9]
======= Memory map: ========

et cela vaut pour 15 autres lignes. Pourquoi ai-je cette erreur? Est-ce à cause d'une erreur que je fais lors de l'allocation dynamique de mémoire à l'aide de malloc?

Voici mon code:

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

void *Merge(int *A,int l,int m,int r,int *B,int *F);
void *Merge(int *A,int l,int m,int r,int *B,int *F){
  int i=l,j=m,k=0,*C,x,y=l,z,cSize,temp,*D,*E;

  cSize = r-l;
  C = (int *) malloc (cSize * sizeof(int));
  D = (int *) malloc (cSize * sizeof(int));
  E = (int *) malloc (cSize * sizeof(int));

  while (k < cSize){
    if((j==r) || ((i!=m) && ((A[j]*B[i]) >= (A[i]*B[j])))){
        C[k] = A[i];
        D[k] = B[i];
        E[k] = F[i];
        i++;
        k++;
    }
    if((i>=m) || ((j!=r) && ((A[j]*B[i]) < (A[i]*B[j])))){
        C[k] = A[j];
        D[k] = B[j];
        E[k] = F[j];
        j++;
        k++;
    }
  }
  for(x=0;x<k;x++){
    A[y] = C[x];
    B[y] = D[x];
    F[y] = E[x];
    y++;
  }
  free(C);
  free(D);
  free(E);
}

void *MergeSort(int *A,int left,int right,int *B,int *C);
void *MergeSort(int *A,int left,int right,int *B,int *C){
  int mid,i,j,k=0,l=0,*R,*L;
  if(right - left == 1){
    A[left] = A[left];
  }
  if(right-left > 1){
    mid = (left+right)/2;

    MergeSort(A,left,mid,B,C);
    MergeSort(A,mid,right,B,C);

    Merge(A,left,mid,right,B,C);
  }
}

int main(){
  int n,i=0,newNumt,newNumo,*a,*b,*c;

  scanf("%d",&n);
  a = (int *) malloc (n * sizeof(int));
  b = (int *) malloc (n * sizeof(int));
  c = (int *) malloc (n * sizeof(int));

  for(i=0;i<n;i++){
    scanf("%d %d",&a[i],&b[i]);
    c[i]= i+1;
  }
  MergeSort(a,0,n,b,c);
  for(i=0;i<n;i++){
    printf("%d\n",c[i]);
  }

  return 0;
}
11
ab29007

Ceci est un ancien message, mais plusieurs problèmes semblent ne pas être résolus, donc les tentatives suivantes pour résoudre certains de ceux que vous avez spécifiquement mentionnés dans votre message.

Comme mentionné dans les commentaires, la nature des problèmes à l'origine de votre principal problème déclaré a été trouvée en définissant -Wall pendant la compilation, puis en l'exécutant via un débogueur, avec jusqu'à 20 ensembles de paires entières entrés lors de l'invite.

Voici votre code complet avec plusieurs modifications. Certains ne sont que des suggestions, mais d'autres sont des réponses à des avertissements de compilation, certains plus importants que d'autres. Ce sont tous commentés.

Répondre à l'une de vos principales questions: Pourquoi est-ce que j'obtiens cette erreur? Est-ce à cause d'une erreur que je fais pendant l'allocation dynamique de la mémoire à l'aide de malloc?:
Comme mentionné mon @Jonathan Leffler, ce n'est probablement pas un problème d'allocation de mémoire, mais la tentative d'accès à la mémoire qui n'a pas été allouée.
L'erreur d'exécution notable à ce sujet a été observée lors de l'exécution de votre code non modifié et est signalée par un commentaire dans la fonction Merge(), où l'index k est incrémenté de une valeur plus grande qu'elle ne le devrait, provoquant une erreur Déréférencement du pointeur hors limites. La solution rapide consistait à rendre les deux sections if mutuellement exclusives en ajoutant un else à la seconde. Cette modification empêche l'erreur d'exécution, mais n'est pas nécessairement la bonne (ou la seule) modification nécessaire.

Une autre suggestion que je n'ai pas abordée dans le code est la sélection des noms de variables. Comme écrit, beaucoup sont trop cryptiques et n'ajoutent pas de lisibilité ou de compréhension à ce que le code tente de faire. La suggestion serait d'utiliser des noms de variables qui permettraient à une autre personne (ou même à vous-même, lorsque dans 3 ans vous regardez à nouveau.) De comprendre immédiatement quel est le but de la variable.

Lisez les commentaires des changements pour comprendre pourquoi ils sont là ...

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

void *Merge(int *A,int l,int m,int r,int *B,int *F);
void *MergeSort(int *A,int left,int right,int *B,int *C);

int main()
{
   // int n,i=0,newNumt,newNumo,*a,*b,*c;
    int n,i=0,*a,*b,*c; //removed unused newNumt & newNumo

    printf("\nEnter number of integer pairs:\n");//user input instructions
    scanf("%d",&n);
    a = calloc (n, sizeof(int));//see comment in MergeSort for similar
    b = calloc (n, sizeof(int));//suggested change for malloc/calloc
    c = calloc (n, sizeof(int));

    for(i=0;i<n;i++)
    {
        printf("\n%d) Enter two integer values:\n", i);//user input instructions
        scanf("%d %d",&a[i],&b[i]);
        c[i]= i+1;
    }
    MergeSort(a,0,n,b,c);
    for(i=0;i<n;i++)
    {
        printf("%d\n",c[i]);
    }

    return 0; 
}

void *Merge(int *A, int l, int m, int r, int *B, int *F)
{
    //int i=l,j=m,k=0,*C,x,y=l,z,cSize,temp,*D,*E;    
    int i=l,j=m,k=0,*C,x,y=l,cSize,*D,*E;//removed unused z and temp

    cSize = r-l;
   // C = (int *) malloc (cSize * sizeof(int));
   // D = (int *) malloc (cSize * sizeof(int));
   // E = (int *) malloc (cSize * sizeof(int));
    C = calloc (cSize, sizeof(int)); //it is not recommended to cast the return
    D = calloc (cSize, sizeof(int)); //of malloc/calloc/realloc in C
    E = calloc (cSize, sizeof(int)); //changed malloc to calloc to initialize
                                      //variable memory to zero before use

// Only one or the other of the following two if statements should be executed per loop, 
// by running both an access violation occurs causing crash. (eg. when k is incremented twice 
// before being tested.) 
    while (k < cSize)//k is tested only once per loop...
    {
        if((j==r) || ((i!=m) && ((A[j]*B[i]) >= (A[i]*B[j]))))
        {
            C[k] = A[i];
            D[k] = B[i];
            E[k] = F[i];
            i++;
            k++;//if k == csize-1, it will be incremented to k == csize, then go into the next section
        }
        else if((i>=m) || ((j!=r) && ((A[j]*B[i]) < (A[i]*B[j])))) //added else
        {
            C[k] = A[j]; //Dereference of out-of-bounds pointer occurs here when k is too large.
            D[k] = B[j];
            E[k] = F[j];
            j++;
            k++;// ... but possibly increment twice!
        }
    }
    for(x=0;x<k;x++)
    {
        A[y] = C[x];
        B[y] = D[x];
        F[y] = E[x];
        y++;
    }
    free(C);
    free(D);
    free(E);

    return 0; //function prototype requires a return to quiet the warnings
              //Only void function prototypes do not require a return statement

}


void *MergeSort(int *A,int left,int right,int *B,int *C)
{
    //int mid,i,j,k=0,l=0,*R,*L;
    int mid = 0; //removed all unused variables and initialized mid

    if(right - left == 1)
    {
        A[left] = A[left];
    }
    if(right - left > 1)
    {
        mid = (left + right)/2; // integer rounding

        MergeSort(A, left, mid, B, C);
        MergeSort(A, mid, right, B, C);

        Merge(A, left, mid, right, B, C);
    }

    return 0; //function prototype requires a return to quiet the warnings
              //Only void function prototypes do not require a return statement

}
1
ryyker