2017-10-09 14 views
-5

J'ai un tableau dynamique en deux dimensions dont la taille est height * width. Je veux changer la taille du tableau en utilisant realloc.Modification d'un tableau dynamique bidimensionnel (realloc en c)

Ceci est mon code mais cela ne fonctionne pas.

Que dois-je faire? Aidez moi!!

int main(){ 
     char **img; 
     img = (char**)malloc(sizeof(char*)*height); 

     for(i=0;i<height;i++){ 
     img[i] = (char*) malloc(sizeof(char)*width); 
     } 

     resize(height*2, width*2, img); 
} 

void resize(int height, int width, char **img){ 
     int i; 
     img = (char**)realloc(img, sizeof(char)*height); 
     for(i=0;i<h;i++){ 
     img[i] = (char*)realloc(img[i], width); 
     } 

} 
+0

Pour commencer, je vous recommande de faire des recherches sur * émulant passe par référence en c *. Pour continuer, quels seront les éléments * new * de 'img' après la réallocation? Astuce: ils sont * non initialisés * et ne peuvent être transmis tels quels à 'realloc'. Enfin, vous ne devriez jamais revenir au pointeur que vous passez à 'realloc', au cas où' realloc' échouerait. –

+0

Ceci n'est pas ** un tableau 2d. Et la logique est imparfaite, d'abord 'free()' tableaux individuels qui ne sont plus nécessaires (le cas échéant), puis redimensionner votre tableau de pointeurs, puis allouer les tableaux individuels nouvellement nécessaires et redimensionner ceux qui étaient là avant. Et bien sûr, vérifiez les erreurs sur ** chaque ** 'appel malloc()'/'realloc()'. Enfin, modifier une variable locale modifie une ** copie **, vous devez par ex. retourner 'img' quand vous avez terminé. –

+3

Et en général, "* mais cela ne fonctionne pas. *" ** n'est pas ** une description de problème appropriée. –

Répondre

0

De plus, vous

  • ne traitent pas avec une 2D-tableau et
  • et la mémoire de fuite de code si la nouvelle hauteur est plus petite que l'ancienne hauteur et
  • vous n'avez pas besoin de jeter void -pointers en C et
  • tous int s devraient être size_t s

il y a deux bugs majeurs ici, comme le code

  • passe la mauvaise taille de réallouer le tableau extérieur. Il multiplie height par sizeof (char) au lieu de sizeof (char*).
  • manque d'initialiser les pointeurs supplémentaires realloc dans le tableau "externe" avec NULL avant de les passer à realloc() via la boucle de redimensionnement interne.

Ainsi, les ajustements minimes en supposant que la nouvelle hauteur est supérieure ou égale à la vieille hauteur pourrait ressembler

void resize(size_t height, size_t height_current, size_t width, char **img){ 
    int i; 
    img = (char**)realloc(img, sizeof(char*)*height); 
    for(i=height_current;i<height;i++){ 
    img[i] = NULL; 
    } 
    for(i=0;i<width;i++){ // correct copypasta mistake here 
    img[i] = (char*)realloc(img[i], width); 
    } 
} 

Une version plus agréable pourrait ressembler à ceci

void resize(size_t height, size_t height_current, size_t width, size_t char **img) 
{ 
    if (height != height_current) 
    { 
    if (height < height_current) 
    { 
     for (size_t i = height; i < height_current; ++i) 
     { 
     free(img[i]); 
     } 
    } 

    img = realloc(img, height * sizeof *img); 

    if (height > height_current) 
    { 
     for (size_t i = height_current; i < height; ++i) 
     { 
     img[i] = NULL; 
     } 
    } 
    } 

    for (size_t i = 0; i < width; ++i) 
    { 
    img[i] = realloc(img[i], width * sizeof *img[i]); 
    } 
} 

Appelez comme ceci:

resize(height*2, height, width*2, img); 

Vous aussi vraiment voulez ajouter la vérification d'erreur à tous les appels à malloc() et realloc() car ils pourraient très bien échouer!

+0

Le "réglage minimal" ne résout pas le problème d'un changement de pointeur "img"; et vous mélangez la largeur et la hauteur dans la deuxième version. –

+0

@StephanLechner: Correction en ajoutant des commentaires et du code. Sry. – alk

+0

'pour (i = largeur_courant; i

0

Il y a deux problèmes principaux. Tout d'abord, realloc peut déplacer le bloc de mémoire à une nouvelle position. Par conséquent realloc a une valeur de retour pointant soit sur le "vieux" bloc de mémoire si aucun déplacement n'était nécessaire, soit sur un nouveau bloc si un déplacement était nécessaire, soit sur NULL si une erreur se produisait. Pourtant, vous négligez ce fait dans resize, car il ne peut pas changer l'objet pointeur un visiteur passe. Je suggère d'adapter le prototype de telle sorte que resize renvoie un (probablement nouveau) pointeur tout comme realloc fait. Deuxièmement, lors de la réallocation de chaque ligne, il se peut qu'il y ait des valeurs non initialisées dans le tableau, indiquant probablement "quelque part". Réallouer une telle valeur non initialisée est un comportement indéfini. Je suggère de définir les "nouvelles" lignes à NULL de telle sorte que realloc puisse se comporter correctement par la suite. Il est donc nécessaire de connaître la "vieille" hauteur, puisque vous n'avez aucune chance de distinguer un pointeur initialisé régulièrement d'un pointeur "garbage".

Voir le code adapté. J'espère que cela aide.

char** resize(int oldHeight, int oldWidth, int height, int width, char **img){ 
    int i; 
    img = realloc(img, sizeof(char)*height); 
    for (int i=oldHeight; i<height; i++) 
     img[i] = NULL; 

    for(i=0;i<height;i++){ 
     img[i] = realloc(img[i], width); 
     for (int col=oldWidth; col < width; col++) { 
      img[i][col] = 0; 
     } 
    } 

    return img; 
} 

int main(){ 
    int height = 10; 
    int width = 20; 

    char **img; 
    img = malloc(sizeof(char*)*height); 

    for(int i=0;i<height;i++){ 
     img[i] = malloc(sizeof(char)*width); 
    } 

    img = resize(height, width, height*2, width*2, img); 
} 
0

Pour ce faire correctement, vous devez savoir au moins le nombre de lignes avant le redimensionnement. Une possibilité est de définir un struct contenant des informations supplémentaires (genre d'approche POO, ont toutes les données pertinentes ensemble), comme dans l'exemple suivant (stockage aussi le nombre de colonnes, juste pour être complet, code non testé ici):

#include <stdlib.h> 
#include <string.h> 

typedef struct Lookup Lookup; 

struct Lookup 
{ 
    size_t rows; 
    size_t cols; 
    char **data; 
}; 

static void Lookup_destroy(Lookup *self) 
{ 
    if (!self) return; 
    for (size_t r = 0; r < self->rows; ++r) 
    { 
     free(self->data[r]); 
    } 
    free(self->data); 
    free(self); 
} 

static Lookup *Lookup_create(size_t rows, size_t cols) 
{ 
    Lookup *self = malloc(sizeof *self); 
    if (!self) return 0; 

    self->rows = rows; 
    self->cols = cols; 
    self->data = malloc(rows * sizeof *(self->data)); 
    if (!self->data) 
    { 
     free(self); 
     return 0; 
    } 
    memset(self->data, 0, rows * sizeof *(self->data)); 
    for (size_t r = 0; r < rows; ++r) 
    { 
     self->data[r] = malloc(cols * sizeof *(self->data[r])); 
     if (!self->data[r]) 
     { 
      Lookup_destroy(self); 
      return 0; 
     } 
    } 

    return self; 
} 

static Lookup *Lookup_resize(Lookup *self, size_t rows, size_t cols) 
{ 
    if (!self) return Lookup_create(rows, cols); 

    // free rows that are no longer needed, if any: 
    for (size_t r = rows; r < self->rows; ++r) 
    { 
     free(self->data[r]); 
     self->data[r] = 0; 
    } 

    // reallocate array of rows: 
    char **newdata = realloc(self->data, rows * sizeof *newdata); 
    if (!newdata) 
    { 
     Lookup_destroy(self); 
     return 0; 
    } 

    // update row array and row count: 
    self->data = newdata; 
    size_t oldrows = self->rows; 
    self->rows = rows; 

    // initialize new rows to NULL, if any: 
    if (rows > oldrows) 
    { 
     memset(self->data + oldrows, 0, 
       (rows - oldrows) * sizeof *(self->data)); 
    } 

    // reallocate individual rows: 
    for (size_t r = 0; r < rows; ++r) 
    { 
     char *newrow = realloc(self->data[r], cols * sizeof *newrow); 
     if (!newrow) 
     { 
      Lookup_destroy(self); 
      return 0; 
     } 
     self->data[r] = newrow; 
    } 

    // update col count: 
    self->cols = cols; 

    return self; 
} 

Notez comment le résultat de realloc() est toujours stocké dans une variable temporaire d'abord, cela est nécessaire pour gérer correctement les erreurs. Ce code jette simplement tout l'objet en cas d'erreur - vous pouvez faire différentes choses avec plus de code bien sûr.

Vous pouvez l'utiliser dans votre code comme ceci:

int main(){ 
     Lookup img; 
     img = Lookup_create(height, width); 
     // check for NULL here 

     img = Lookup_resize(img, height*2, width*2); 
     // and check for NULL here 
}