web-dev-qa-db-fra.com

Erreur de compilation Malloc: une valeur de type "int" ne peut pas être utilisée pour initialiser une entité de type int (*) [30]

Je dois avoir essayé 20 façons de faire maintenant. J'ai vraiment besoin d'aide, peu importe ce que je fais, j'obtiens une erreur similaire à celle-ci.

a value of type "int" cannot be used to initialize an entity of type "int (*)[30]"

c'est-à-dire que cela m'obtiendra une telle erreur

int(*array)[160] = malloc((sizeof *array) * 10);

et faire quelque chose comme ça

int** Make2DintArray(int arraySizeX, int arraySizeY) {
    int** theArray;
    theArray = (int**) malloc(arraySizeX*sizeof(int*));
    int i;
    for (i = 0; i < arraySizeX; i++)
    {
        theArray[i] = (int*) malloc(arraySizeY*sizeof(int));
    }
    return theArray;
}

va me faire ça

"void *(size_t)" in "memory.c" at line 239 and: "int()" 

quelqu'un at-il une solution pour allouer avec succès un 2dArray d'int [160] [10]

13
WIllJBD

Les deux compilent bien pour moi. La première erreur est courante lorsque vous oubliez #include <stdlib.h> avant d'utiliser des fonctions déclarées dans les mêmes (comme malloc(size_t)), ce que j'ai fait ne pas oublier de le faire.

C a des comportements de compilation intéressants, parmi lesquels la possibilité d'invoquer une fonction qui n'a jamais été vue auparavant (ni mise en œuvre de définition de prototype ni ). En rencontrant un tel appel, C suppose que la fonction est:

  • Quelque chose qui renvoie int
  • Prend un nombre inconnu d'arguments, afin que l'appelant puisse passer ce qu'il veut (y compris les mauvaises choses).

Par exemple, la fonction est implicitement supposée être de la forme:

int func();

Souvent, vous ne le remarquerez même pas, sauf pour les avertissements de votre compilateur qui signalent quelque chose à l'effet de:

Warning: implicit declaration of `func` assumed to return `int`

et si vous êtes dans le coup, vos niveaux d'avertissement sont activés et les avertissements en tant qu'erreurs sont activés et vous le verrez.

Et si vous ne le faites pas? Et si la "chose" renvoyée par la fonction ne peut pas être représentée par le contenu par la taille des données dans une implémentation int? Et si, par exemple, int était 32 bits, mais que les pointeurs de données étaient 64 bits? Par exemple, supposons que char *get_str() est déclaré dans un fichier d'en-tête que vous n'incluez pas , et implémenté dans un fichier .c que vous compiler et lier avec votre programme, qui ressemble à ceci:

#include <stdio.h>

// Note: NO prototype for get_str
int main()
{
    char *s = get_str();
    printf("String: %s\n", s);
    return 0;
}

Eh bien, le compilateur devrait vomir, vous disant que int et char* Ne sont pas compatibles (peu de temps après qu'il vous avertit get_str Est supposé renvoyer int). Mais que faire si vous forcez la main du compilateur en en lui disant de faire un char* D'une manière ou d'une autre:

#include <stdio.h>

// Note: NO prototype for get_str
int main()
{
    char *s = (char*)get_str(); // NOTE: added cast
    printf("String: %s\n", s);
    return 0;
}    

Maintenant, sans les avertissements en tant qu'erreurs activés, vous obtiendrez un avertissement de déclaration implicite, et c'est tout. Le code se compilera. Mais sera-t-il exécuté ? Si sizeof(int)! = sizeof(char*), (32 bits vs 64 bits) probablement pas. La valeur renvoyée par get_str Est un pointeur 64 bits, mais l'appelant suppose que seuls 32 bits sont renvoyés, puis le force à un pointeur 64 bits. En bref, le casting a caché l'erreur et ouvert la boîte de Pandore de comportement indéfini.


Alors, comment tout cela est-il lié à votre code? En n'incluant pas <stdlib.h>, Le compilateur ne sait pas ce qu'est malloc. Il suppose donc qu'il est de la forme:

int malloc();

Ensuite, en transtypant le résultat en (int**), Vous dites au compilateur "tout ce qui en sort, faites-en un int**". Au moment de la liaison, _malloc Est trouvé (pas de signature de paramètre via un changement de nom comme C++), câblé et votre programme est prêt à faire la fête. Mais sur votre plate-forme int et les pointeurs de données ne sont pas pas de la même taille, vous vous retrouvez donc avec plusieurs conséquences indésirables:

  • Le casting cache la vraie erreur.
  • Un faux pointeur est fabriqué à partir de la moitié des bits du pointeur renvoyé réel .
  • En tant que dose cruelle de sel à la plaie, la mémoire allouée est divulguée, car il n'y a aucun pointeur valide nulle part qui la référence (vous venez de détruire le seul en n'en gardant que la moitié).
  • Probablement le le plus indésirable, le code présentera un comportement normal s'il est compilé sur une implémentation où sizeof(int) == sizeof(int**).

Donc, vous construisez cela sur votre boîte Debian 32 bits, tout semble bien. Vous remettez vos devoirs au professeur qui le construit sur son Mac 64 bits et il se bloque, vous échouez la tâche, échouez en classe, abandonnez vos études et passez les dix prochaines années à caresser le chat tout en regardant Seinfeld rediffuser dans le sous-sol de votre mère me demande ce qui a mal tourné. Aie.

Ne traitez pas le casting comme une balle d'argent. Ce n'est pas le cas. En C, il est nécessaire loin moins souvent que les gens l'utilisent, et s'il est utilisé au mauvais endroit, peut cacher des erreurs catastrophiques. Si vous trouvez un point dans votre code où quelque chose ne se compilera pas sans conversion en dur, regardez à nouveau . À moins que vous ne soyez absolument, positivement sûr que le casting est la bonne chose à faire, les chances sont que mal .

Dans ce cas, il a caché la vraie erreur, que vous avez négligé de donner suffisamment d'informations à votre compilateur pour savoir ce que malloc fait vraiment.

12
WhozCraig

Essaye ça:

int **array;
array = malloc(rows * sizeof(int *));
for (i = 0; i < rows; i++)
  array[i] = malloc(cols * sizeof(int));

// Some testing
for (i = 0; i < rows; i++) {
  for (j = 0; j < cols; j++)
    array[i][j] = 0; // or whatever you want
}

for (i = 0; i < rows; i++) {
  for (j = 0; j < cols; j++)
    printf("%d ", array[i][j]);
}

Dans votre cas, les lignes = 160 et cols = 10. Est une solution possible.

Avec cette approche, vous pouvez utiliser les deux index:

17
rendon

Pour allouer le tableau:

int *array = malloc(sizeof(int) * 160 * 10);

Ensuite, utilisez du code comme:

array[10 * row + column] = value;

(Où row va de 0 à 159 inclus et column va de 0 à 9 inclus.)

5
David Schwartz

J'ai une note pour la réponse de rendon:

Pour son code, Visual C++ indique pour chaque opération "=": error C2440: '=' : cannot convert from 'void *' to 'int **'

En faisant quelques changements, cela fonctionne pour moi, mais je ne suis pas sûr que cela fasse la même chose, j'ai donc peur d'éditer son code. Au lieu de cela, voici le code qui semble fonctionner pour une première impression.

int **a;    

a = (int **)malloc(rows * sizeof(int));

for (i = 0; i < rows; i++)
{
    a[i] = (int *)malloc(cols * sizeof(int));
}

for (j=0;j<rows;j++)
{
    for (i=0;i<cols;i++)
    {
        a[i][j] = 2;
    }
}

En fait, je l'ai fait avec un struct personnalisé au lieu de ints mais je pense que dans tous les cas cela devrait fonctionner.

0
Zoltán Schmidt

Ne me dérange pas, j'ajoute juste un exemple en utilisant calloc

void allocate_fudging_array(int R, int C)
{
    int **fudging_array = (int **) calloc(R, sizeof(int *));
    for(int k = 0; k < R; k++)
    {
        fudging_array[k] = (int*) calloc(C, sizeof(int));
    }
}


// a helper function to print the array 
void print2darr(int **arr, int R, int C)
{
    for(int i = 0; i < R; i++)
    {
        for(int j = 0; j < C; j++)
        {
            printf(" %d  ", arr[i][j]);
        }
        printf("\n");
    }
}
0
Reno