human
Pointeurs C : comment les utiliser , et pourquoi je suis un programmeur C débutant , et si quelque chose n'est pas déréférencé , j'ajoute généralement des * au hasard jusqu'à ce qu'il compile . Rien de ce que j'ai trouvé en ligne jusqu'à présent n'a été une excellente explication. Explique comme si j'avais cinq ans.
gpt
Lorsque les ordinateurs exécutent des programmes , toutes les informations avec lesquelles ils travaillent sont stockées dans la mémoire de l' ordinateur , ou " RAM " ( qui est l' abréviation de random - access - memory ) . C'est ce qu'on appelle l'accès aléatoire car le programme peut accéder rapidement aux informations de n'importe où dans la mémoire, en une seule instruction. Maintenant , à l' intérieur d' un programme informatique , tout est un nombre . C'est ainsi que les ordinateurs représentent toutes les informations qu'ils détiennent. Eh bien, lorsqu'un programme a besoin d'accéder à certaines informations de la mémoire, il doit émettre une instruction indiquant à l'ordinateur de les récupérer à partir d'une partie particulière de la mémoire. Comment indique-t-il à l'ordinateur dans quelle partie de la mémoire le récupérer ? Eh bien, la mémoire des ordinateurs est représentée par une liste de boîtes très binaires, chacune pouvant stocker un petit nombre (de 0 à 255). Nous appelons ces boîtes " octets " . Un octet est une petite boîte de mémoire qui peut stocker un nombre compris entre 0 et 255 . Le programme peut lire (regarder) ou écrire (modifier) ​​le nombre à l'intérieur de n'importe quel octet en mémoire. Mais pour ce faire , il doit indiquer à l' ordinateur _ quel octet _ lire ou écrire . Pour permettre cela, chaque octet en mémoire est associé à une _adresse_. Une adresse est juste un nombre, et chaque octet a un nombre différent comme adresse, et l'adresse de l'octet suivant est toujours supérieure d'une unité à l'adresse de l'octet précédent. Pensez à la mémoire comme à un très long train avec de nombreux wagons, et chacun des wagons a un numéro peint dessus, et le numéro sur n'importe quel wagon est toujours supérieur d'une unité au numéro du wagon précédent. Les octets sont les voitures, et les nombres sont leurs adresses. Tout comme le numéro d'un wagon restera le même quel que soit ce que vous mettez à l'intérieur du wagon, l'adresse d'un octet reste la même quel que soit le numéro que vous y mettez. Pour dire à l'ordinateur de faire des choses sur un octet particulier, le programme utilise simplement le numéro de l'adresse d'un octet particulier (ou le premier octet d'une séquence d'octets avec lequel il veut faire quelque chose), et dit à l'ordinateur de lire ou écrire à cet endroit. Lorsque vous programmez en C, tout est un nombre. Mais cela peut devenir déroutant pour le programmeur s'il considère tout comme un nombre. Lorsqu'un nombre particulier est l'adresse d'un octet, le programmeur ne se soucie généralement pas de savoir si le nombre est un 234 ou un 92384. Elle ne se soucie que de la signification de l'adresse et de la manière d'accéder aux adresses des objets à proximité en mémoire (qui peuvent stocker des informations relatives à l'adresse d'origine). Pour aider le programmeur à garder les choses claires, C propose des pointeurs, qui sont une sorte de type que les variables peuvent avoir. Si une variable a un type pointeur, alors la valeur qu'elle stocke est l'adresse d'un octet particulier en mémoire. Même s'il s'agit en fait d'un nombre, le C ne vous permet pas d'utiliser des pointeurs exactement comme il vous permet d'utiliser des nombres. Si vous ajoutez un nombre à un pointeur, vous obtenez l'adresse d'un octet voisin en mémoire (donc si vous ajoutez 1 à un pointeur d'octet, vous obtenez un pointeur vers l'octet suivant). Ainsi, un pointeur plus un nombre, vous donne un autre pointeur, pointant vers un endroit proche en mémoire. Il en va de même pour la soustraction d'un pointeur à un nombre. Vous ne pouvez pas multiplier un pointeur par un nombre , car cela n'a aucun sens . L'idée de "l'adresse 10 fois plus bas dans la mémoire qu'une autre adresse" n'a pas beaucoup de sens, donc C empêche la multiplication des pointeurs. Si vous soustrayez un pointeur d'un autre, C vous renvoie un nombre régulier, qui est la distance entre les deux pointeurs. Ajouter un nombre à un pointeur , et soustraire un pointeur d' un autre pointeur , sont des opérations appelées " arithmétique de pointeur " , car elles ressemblent un peu à l' arithmétique normale , mais elles sont effectuées sur des pointeurs . Parce que certaines opérations sont vraiment courantes, C fournit des moyens spéciaux de spécifier facilement ces opérations. L'une de ces opérations est le déréférencement. si vous écrivez : p[i ] = x ; où p est un pointeur , et i est un certain nombre .. alors ce que cela signifie vraiment est : " ajouter i au pointeur p , puis écrire la valeur x à cet emplacement en mémoire " . Lorsque vous écrivez simplement " x = p[i ] ; " , cela signifie " ajouter i au pointeur p , lire la valeur à cet emplacement en mémoire et la stocker dans la variable x " . C fournit également une syntaxe spéciale pour accéder à la mémoire à un emplacement identifié par un pointeur , sans arithmétique : Dans une expression , * p est identique à p[0 ] , donc : * p = 5 signifie " stocker 5 à l'emplacement en mémoire identifié par le pointeur p " . De même, l'expression : p[2 ] = 9 ; Est égal à : * ( p + 2 ) = 9 ; Les notations ' * ' et ' [ ] ' ne sont que deux façons différentes d'exprimer la lecture et l'écriture en mémoire. Il reste une dernière chose à couvrir avec des pointeurs. Les programmeurs travaillent souvent avec des valeurs supérieures à un seul octet. Les grands nombres (comme les entiers) peuvent occuper jusqu'à 4 ou 8 octets d'espace en mémoire. Des choses encore plus grandes comme les « structs » peuvent être constituées de plusieurs valeurs différentes. Tout cela prend plus d'un octet de mémoire. Les pointeurs de C sont basés sur des types sous-jacents. Par exemple , " int * " est le type de " pointeur vers int " . Lorsque le programmeur fait de l'arithmétique de pointeur, l'arithmétique est toujours en termes de taille du type sous-jacent. donc , si vous écrivez ' intp + 1 ' , et que intp est un pointeur sur int , alors le pointeur résultant est l' adresse du prochain entier ( qui est généralement 4 ou 8 octets en avant , selon la taille d' un entier ) . De même, si vous dites "intp1 - intp2", et que les deux sont des pointeurs vers des entiers .. alors le nombre résultant (distance entre eux), n'est pas la distance directe entre les adresses, mais en fait cette distance divisée par la taille de int. C'est donc tout ce qu'il y a à faire avec les pointeurs. Les pointeurs sont des types spéciaux pour les nombres qui représentent des adresses en mémoire. Ils restreignent certaines opérations (comme la multiplication et la division), modifient le comportement d'autres opérations (comme + et -), et ils ont une syntaxe spéciale qui les rend pratiques pour manipuler la mémoire.