web-dev-qa-db-fra.com

Tableau dynamique en C - Ma compréhension de malloc et realloc est-elle correcte?

J'apprends à créer des tableaux 1D dynamiques en C. Le code ci-dessous essaie de faire ce qui suit:

  1. À l'aide de malloc, créez un tableau dynamique de longueur 10, qui contient des valeurs de type double.
  2. Définissez chaque entrée du tableau sur j/100 pour j = 0, 1,..., 9. Imprimez-le ensuite.
  3. Ajoutez une entrée vide supplémentaire à la fin du tableau à l'aide de realloc.
  4. Définissez la nouvelle entrée sur j/100 et réimprimez chaque entrée.

Essai:

 double* data = (double*)malloc(10*sizeof(double));

 for (j=0;j<10;j++)
 {
      data[j]= ((double)j)/100;
      printf("%g, ",data[j]);
 }

 printf("\n");

 data = (double*)realloc(data,11*sizeof(double));

 for (j=0;j<11;j++)
 {
     if (j == 10){ data[j]= ((double)j)/100; }
     printf("%g, ",data[j]);
 }

 free((void*) data);

Questions

  1. Suis-je en train de coder ce droit?

  2. Les didacticiels que j'ai trouvés utilisent malloc sans mettre le (double*) devant. Par exemple.,

    int * pointeur;
    pointeur = malloc (2 * sizeof (int));

Cela ne se compile pas pour moi sur Visual Studio 2010, Windows 7. Le message d'erreur est

la valeur de type void ne peut pas être affectée à l'entité de type int.

Pourquoi ça marche pour ces tutoriels et pas pour moi? Ai-je raison de supposer que c'est parce que les compilateurs qu'ils utilisent remplissent automatiquement le (int*) pour eux dans mon exemple?

28
Legendre

Tu es proche.

En C (au moins depuis la version 1989 de la norme), la conversion avant malloc et realloc est inutile, car C peut convertir des valeurs de type void * En int * Sans plâtre. Ceci est pas vrai pour C++, donc en fonction de l'erreur que vous obtenez, il semble que vous compiliez ce code en C++ et non en C. Consultez la documentation de VS2010 pour déterminer comment compiler le code comme C.

Voici mon style préféré pour écrire un appel malloc:

double *data = malloc(10 * sizeof *data);

Comme le type de l'expression *data Est double, sizeof *data Est équivalent à sizeof (double). Cela signifie également que vous n'avez pas à ajuster vos appels malloc si le type de data change.

Quant à l'appel realloc, il est plus sûr d'affecter le résultat à une valeur de pointeur temporaire. realloc renverra NULL s'il ne peut pas étendre le tampon, il est donc plus sûr d'écrire

double *tmp;
...
tmp = realloc(data, 11 * sizeof *data);
if (!tmp)
{
  // could not resize data; handle as appropriate
}
else
{
  data = tmp;
  // process extended buffer
}

Sachez que la prise en charge de Microsoft pour C prend fin avec la version 1989 du langage; il y a eu deux révisions de la norme de langage depuis lors, qui ont introduit de nouvelles fonctionnalités et des anciennes obsolètes. Ainsi, bien que certains compilateurs C prennent en charge les fonctionnalités C99 comme les déclarations et le code mixtes, les tableaux de longueur variable, etc., VS2010 ne le fera pas.

34
John Bode

1) Suis-je en train de coder ce droit?

La plupart. Mais data = (double*)realloc(data,11*sizeof(double)); perd la référence à la mémoire allouée si realloc échoue, vous devez utiliser un pointeur temporaire pour conserver la valeur de retour de realloc et vérifier si c'est NULL (et vous devez également vérifier la valeur de retour de malloc).

2) Tutoriels J'ai trouvé utiliser malloc sans mettre le (double *) devant.

En C, malloc renvoie un void* qui peut être implicitement converti en tout autre type de pointeur, donc aucun transtypage n'est nécessaire (et largement déconseillé car un transtypage peut masquer des erreurs). Visual Studio compile apparemment le code en C++ où la conversion est requise.

12
Daniel Fischer

En C, vous ne devez pas transtyper la valeur de retour de malloc().

De plus, c'est une mauvaise idée de coder le type dans l'argument malloc(). C'est une meilleure façon:

double* data = malloc(10 * sizeof *data);
5
unwind