5
votes

Confusion entre "int array [int]" et "int * array"

int array[100];

int *array;
I am confused about the differences between int array[100] and int *array.Essentially, when I do int array[100] (100 it's just an example of an int), I just reserved space in memory for 100 ints, but I can do int * array and I didn't specify any type of size for this array, but I can still do array[9999] = 30 and that will still make sense.So what's the difference between these two?

5 commentaires

"Je n'ai spécifié aucun type de taille pour ce tableau" Vous devez cependant faire quelque chose dans la veine de int * array = malloc (sizeof (int) * 10000) < / code>, ici le 10000 est la taille. Si vous ne faites pas pointer votre pointeur vers une mémoire valide, alors array [9999] = 30; est un comportement indéfini et risque de planter votre programme ou de provoquer d'autres résultats erronés / imprévisibles.


pour commencer, int * array doit être malloc () - édité manuellement.


ohh merci beaucoup


Je suggère les sections 4, 5, 6 et 7 du c-faq .


@JoaoParente: vous pouvez accepter l'une des réponses en cliquant sur la coche grise sous son score.


7 Réponses :


2
votes

La différence est que lorsque vous faites int array [100] , un bloc mémoire de 100 * sizeof (int) est alloué sur la pile , mais lorsque vous faites int * array , vous devez allouer dynamiquement de la mémoire (avec la fonction malloc par exemple) pour utiliser la variable array . La mémoire allouée dynamiquement se trouve sur le tas , pas sur la pile .


1 commentaires

La question ne montre pas si ces déclarations apparaissent à l'intérieur ou à l'extérieur d'une fonction, ce qui affecte la façon dont la mémoire est allouée. Et la façon dont la mémoire est fournie dépend de l'implémentation. En outre, il n'est pas nécessaire d'allouer dynamiquement de la mémoire pour utiliser un pointeur. Le pointeur peut être défini pour pointer vers une autre mémoire, comme à l'intérieur d'un autre tableau.



6
votes

Un pointeur est un pointeur , il pointe ailleurs (comme le premier élément d'un tableau). Le compilateur n'a aucune information sur l'endroit où il pourrait pointer ou la taille des données vers lesquelles il pourrait pointer.

Un tableau est, bien, un tableau d'un certain nombre d'éléments consécutifs du même type. Le compilateur connaît sa taille, car elle est toujours spécifiée (bien que parfois la taille ne soit spécifiée qu'implicitement).

Un tableau peut être initialisé, mais pas assigné. Les tableaux se désintègrent souvent en pointeurs vers leur premier élément.

Exemple de désintégration de tableau:

int array[10];

int *pointer = array;  // Here the symbol array decays to the expression &array[0]

// Now the variable pointer is pointing to the first element of array

Les tableaux ne peuvent naturellement pas être passés à la fonction. Lorsque vous déclarez un argument de fonction comme int arr [] , le compilateur le traduira comme int * arr .

Toutes ces informations, et plus, devrait être dans n'importe quel bon livre, tutoriel ou classe.


1 commentaires

Le compilateur ne connaît pas toujours la taille d'un tableau. Par exemple, extern int array []; déclare un tableau défini dans un autre module ou simplement plus tard dans le même module. La taille est inconnue et sizeof (array) devrait produire une erreur.



2
votes

int array [100] signifie une variable array qui pourra contenir 100 valeurs int cette mémoire sera allouée à partir de la pile. La variable array aura l'adresse de base du tableau et la mémoire lui sera allouée.

Mais dans le cas de int * array puisque vous déclarez ceci comme une variable locale, la variable de pointeur array aura une adresse de garbage. Donc, si vous utilisez array [9999] , cela pourrait provoquer une violation de segmentation car vous essayez d'accéder à l'emplacement de la mémoire des déchets en dehors de votre programme.


4 commentaires

L'accès au array [9999] ne provoquera pas toujours une violation de segment. Le comportement n'est pas défini par la norme C. L'adresse peut se trouver dans une mémoire accessible ou le code peut être transformé de manière inattendue par optimisation.


Oui c'est correct. Mais dans la plupart des cas, un crash se produira.


La réponse pourrait indiquer que l'accès à un tableau hors limites provoque souvent une violation de segment, mais cela ne devrait pas amener le lecteur à croire qu'il peut s'attendre à ce comportement. Les réponses doivent contenir des déclarations vraies et ne doivent pas contenir de fausses déclarations.


> typedef struct edge {int dest; int cost; struct edge ∗ next;} ∗ EList; > typedef EList Graph [100] donc si j'avais quelque chose comme ça, je pourrais faire: EList hash; hash [30] = NULL, car en déclarant sur le type la taille de celui-ci lorsque je déclare le hachage EList, il créera automatiquement une table de hachage de taille 100, n'est-ce pas?



2
votes

Une explication non technique:

Le contenu d'un pointeur fait référence à une adresse (qui peut être valide ou non). Un tableau a une adresse (qui doit être valide pour que le tableau existe).

Vous pouvez considérer un pointeur comme une enveloppe - vous pouvez mettre l'adresse de votre choix dessus, mais si vous voulez qu'il soit envoyé quelque part en particulier, cette adresse doit être correcte.

Un tableau est comme votre maison - il existe quelque part, donc il a un adresse. Les objets correctement adressés y sont envoyés.

En bref:

Un pointeur contient une adresse.

Un tableau a une adresse.

array[9999] = 30;

crée un pointeur de valeur indéterminée (il peut pointer n'importe où!).

Lorsque vous avez alors

int *array;

vous essayez de définir le 9999e int valeur d'où array pointe vers la valeur de 30. Mais vous ne savez pas où pointe array car vous ne lui a pas donné de valeur réelle.

Et c'est un comportement indéfini.


0 commentaires

0
votes

Sans spécifier la taille dans int * array , array [9999] = 30 peut provoquer une erreur de segmentation car cela peut conduire à l'accès à une mémoire inaccessible

En gros, int * array pointe vers un emplacement aléatoire. Pour accéder au 9999ème élément, le tableau doit pointer vers un emplacement ayant autant d'espace suffisant. Mais l'instruction int * array ne crée explicitement aucun espace pour cela.


0 commentaires

1
votes

Quelques points que vous pouvez trouver utiles à connaître:

  • Via int arr [N] vous spécifiez un tableau de type int qui peut stocker N entiers. Pour obtenir des informations sur la capacité de la matrice mémoire, vous pouvez utiliser l'opérateur sizeof . Multipliez simplement le nombre d'éléments dans un tableau par la taille du type: N * sizeof (int) .
  • Le nom du tableau pointe vers le premier élément d'un tableau, par exemple * arr est identique à arr [0] , vous pouvez également vous demander pourquoi a [5] == 5 [a] .
  • Un tableau non initialisé de durée de stockage non statique est rempli de valeurs indéterminées.
  • La taille d'un tableau peut être connue à l'exécution, si vous écrivez int arr [] = {1, 2} la taille est calculée par un compilateur.
  • L'accès à un élément inexistant peut entraîner un comportement indéfini , ce qui signifie que tout peut arriver, et dans la plupart des cas, vous obtiendrez des valeurs inutiles.

  • Via int * array vous spécifiez un pointeur array de type int
  • Sauf si une valeur est attribuée, un pointeur pointera vers une adresse de garbage par défaut.
  • Si vous n'allouez pas du tout de la mémoire ou si vous ne l'allouez pas complètement ou si vous accédez à un élément inexistant mais que vous essayez d'utiliser un pointeur comme tableau, vous obtiendrez un comportement non défini comme prévu.
  • Après l'allocation de mémoire (lorsque le pointeur n'est plus nécessaire), la mémoire doit être libérée.

0 commentaires

0
votes

int array [100]; définit un tableau de int .

int * array; définit un pointeur vers un int . Ce pointeur peut pointer sur une variable int ou sur un élément d'un tableau de int , ou sur rien du tout ( NULL ), voire à une adresse arbitraire, valide ou invalide en mémoire, ce qui est le cas lorsqu'il s'agit d'une variable locale non initialisée. Il est un peu trompeur d'appeler ce pointeur array , mais il est couramment utilisé pour nommer un argument de fonction qui pointe effectivement vers un tableau réel. Le compilateur ne peut pas déterminer la taille du tableau, le cas échéant, à partir de la valeur du pointeur.

Voici une métaphore topographique:

  • Pensez à un tableau comme une rue avec des bâtiments. Il a des coordonnées GPS (adresse mémoire) un nom (mais pas toujours) et un nombre fixe de bâtiments (à un moment donné, difficile à changer). Le nom de la rue avec le numéro de bâtiment spécifie un bâtiment précis. Si vous spécifiez un nombre plus grand que le dernier, c'est une adresse non valide.

  • Un pointeur est une chose très différente: considérez-le comme une étiquette d'adresse. C'est un petit morceau de papier qui peut être utilisé pour identifier un bâtiment. S'il est vide (un pointeur nul), il est inutile et si vous le collez à une lettre et l'envoyez, la lettre sera perdue et rejetée (comportement indéfini, mais il est facile de dire qu'elle n'est pas valide). Si vous écrivez une adresse invalide dessus, l'effet est similaire, mais peut coûter beaucoup plus cher avant l'échec de la livraison (comportement non défini et difficile à tester).

  • Si une rue est rasée (si la mémoire a été libérée), les étiquettes d'adresse précédemment écrites ne sont pas modifiées, mais elles ne pointent plus le rien d'utile (comportement indéfini si vous envoyez la lettre, le type difficile). Si une nouvelle rue est nommée plus tard avec le nom sur l'étiquette, la lettre peut être livrée, mais probablement pas comme prévu (comportement non défini à nouveau, la mémoire a été libérée et un autre objet alloué se trouve être à la même adresse mémoire).

  • Si vous transmettez un bâtiment à une fonction, vous ne le déterrerez généralement pas pour le transporter par camion, mais vous passeriez simplement son adresse (un pointeur vers le n-ième bâtiment de la rue , & array [n] ). Si vous ne spécifiez pas un bâtiment et nommez simplement la rue, cela signifie aller au début de la rue. De même, lors du passage d'un tableau à une fonction est C, la fonction reçoit un pointeur vers le début du tableau, nous disons que les tableaux se désintègrent comme des pointeurs .


0 commentaires