Question

Je ne parviens pas à produire une matrice int sans créer de fuites de mémoire. Je veux être capable de transformer une matrice (globale) donnée dans n'importe quelle taille de façon dynamique via read_matrix (). Mais ensuite, je veux pouvoir libérer la mémoire plus tard. Ainsi, dans ma méthode principale, la seconde printf devrait entraîner une erreur de bus car aucune mémoire ne lui est allouée. Comment pourrais-je créer cela?

int**       first_matrix;
int**       second_matrix;
int**       result_matrix;

int** read_matrix(int size_x, int size_y)
{
    int** matrix;
    matrix = calloc(size_x, sizeof(int*));
    for(int i = 0;i<size_x;i++) {
        matrix[i] = calloc(size_y, sizeof(int));
    }
    for(int i = 0;i<size_x;i++) {
        for(int j = 0;j<size_y;j++) {
            matrix[i][j] = i*10+j;
        }
    }
    return matrix;
}

int main(int stackc, char** stack)
{
    first_matrix = read_matrix(10,10);
    printf("9:3 %d - 4:6 %d \n", first_matrix[9][3], first_matrix[4][6]);
    free(*first_matrix);
    free(first_matrix);
    printf("9:3 %d - 4:6 %d \n", first_matrix[9][3], first_matrix[4][6]);
}
Était-ce utile?

La solution

Ce n'est pas parce que la mémoire est libre que vous ne pouvez pas y accéder! Bien sûr, c’est une très mauvaise idée d’y accéder après sa publication gratuite, mais c’est la raison pour laquelle cela fonctionne dans votre exemple.

Notez que free( *first_matrix ) seuls les éléments libres sont first_matrix[0], pas les autres tableaux. Vous voulez probablement une sorte de marqueur pour indiquer le dernier tableau (à moins que vous ne sachiez toujours quand vous libérez le tableau extérieur, combien de tableaux intérieurs vous avez alloués). Quelque chose comme:

int** read_matrix(int size_x, int size_y)
{
    int** matrix;
    matrix = calloc(size_x, 1+sizeof(int*)); // alloc one extra ptr
    for(int i = 0;i<size_x;i++) {
        matrix[i] = calloc(size_y, sizeof(int));
    }
    matrix[size_x] = NULL; // set the extra ptr to NULL
    for(int i = 0;i<size_x;i++) {
        for(int j = 0;j<size_y;j++) {
            matrix[i][j] = i*10+j;
        }
    }
    return matrix;
}

Ensuite, lorsque vous les libérez:

// keep looping until you find the NULL one
for( int i=0; first_matrix[i] != NULL; i++ ) {
    free( first_matrix[i] );
}
free( first_matrix );

Autres conseils

Vous devez libérer chaque ligne individuellement:


void free_matrix(int **matrix, int size_x)
{
    for(int i = 0; i < size_x; i++)
        free(matrix[i]);
    free(matrix);
}

Libérer la mémoire ne la fait pas disparaître, cela signifie simplement qu'une autre allocation pourrait récupérer le même bloc de mémoire. Quoi que vous mettiez dedans, il sera toujours là jusqu'à ce que quelque chose d'autre l'écrase.

En outre, vous ne libérez pas tout ce que vous avez alloué. Vous ne faites que libérer le tableau de pointeurs et la première ligne. Mais même si vous libériez tout correctement, vous auriez toujours le même effet.

Si vous souhaitez créer une " erreur de bus " vous devez pointer sur une mémoire n'appartenant pas à votre processus. Pourquoi voulez-vous faire cela quand même?

Vous avez uniquement libéré la première ligne (ou colonne) de first_matrix. Écrivez une autre fonction comme celle-ci:

void free_matrix(int **matrix, int rows)
{
    int i;
    for(i=0; i<rows; i++)
    {
        free(matrix[i]);
    }
    free(matrix);
}

Vous voudrez peut-être transformer la matrice en une structure permettant de stocker le nombre de ses lignes et de ses colonnes.

Je recommande d'utiliser valgrind pour localiser la mémoire non disponible, au lieu d'essayer de provoquer une erreur de bus. Cela déborde également pour beaucoup d'autres choses.

Sam

Vous obtenez des fuites de mémoire parce que vous libérez la première ligne de la matrice et la liste des lignes, mais aucune des lignes 1 à n. Vous devez appeler gratuitement en boucle.

Il existe cependant plusieurs solutions: - Attribuez sizeof (int *) lignes + lignes cols * sizeof (int) octets et utilisez les premiers octets pour les pointeurs de ligne. De cette façon, vous n'avez qu'un seul bloc de mémoire à libérer (et c'est aussi plus facile pour l'allocateur) - Utilisez une structure contenant le nombre de lignes. Ensuite, vous pouvez éviter complètement la liste des lignes (économiser de la mémoire). Le seul inconvénient est que vous devez utiliser une fonction, une macro ou une notation compliquée pour adresser la matrice.

Si vous optez pour la deuxième option, vous pouvez utiliser une structure comme celle-ci dans n'importe quel compilateur C99, et encore une fois, vous n'avez qu'à allouer un seul bloc de mémoire (de taille numints * sizeof (int) + sizeof (int)):

struct matrix {
    int rows;
    int data[0];
}

Le concept qui vous manque ici, c'est que pour chaque calloc, il doit y avoir un libre. et que free doit être appliqué au pointeur renvoyé de calloc.

Je vous recommande de créer une fonction (nommée delete_matrix) qui utilise une boucle pour libérer tous les pointeurs que vous allouez ici

pour (int i = 0; i < size_x; i ++) {         matrice [i] = calloc (size_y, sizeof (int));     }

puis, une fois que cela est fait, libérez le pointeur alloué par ceci.

matrix = calloc (size_x, sizeof (int *));

La façon dont vous le faites maintenant,

free (* first_matrix);     free (first_matrix);

ne fera pas ce que vous voulez.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top