Qu'est-ce qui provoque le blocage de la réaffectation du pointeur entier?

StackOverflow https://stackoverflow.com/questions/207800

  •  03-07-2019
  •  | 
  •  

Question

Je suis nouveau sur C et j'ai cette question. pourquoi le code suivant se bloque-t-il:

int *a = 10;
*a = 100;
Était-ce utile?

La solution

Parce que vous essayez d'écrire 100 dans l'emplacement de mémoire 0x0000000A qui n'est probablement pas alloué à votre programme. C'est-à-dire

int *a = 10;

ne signifie pas que le pointeur 'a' désignera un emplacement en mémoire ayant la valeur 10. Cela signifie qu'il pointe vers l'adresse 10 (0x0000000A) dans la mémoire. Ensuite, vous voulez écrire quelque chose dans cette adresse, mais vous n'avez pas les "droits". pour ce faire, car il n'est pas alloué

Vous pouvez essayer les solutions suivantes:

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

Cela fonctionnerait, bien qu’horriblement inefficace. Si vous n'avez besoin que d'un seul int, vous devez simplement le placer dans la pile, pas dans le tas . Sur une architecture 32 bits, un pointeur a une longueur de 32 bits et un int a également une longueur de 32 bits. Votre structure pointeur-à-int prend donc la place ( au moins ) 8 octets d'espace mémoire de cette façon au lieu de 4. Et nous n'avons même pas mentionné les problèmes de mise en cache.

Autres conseils

Vous devez affecter le pointeur à un emplacement de mémoire , et non à une valeur arbitraire (10).

int cell = 10;
int *a = &cell; // a points to address of cell
*a = 100;       // content of cell changed

Voir ma réponse à un autre question de faire attention avec C .

Je voudrais proposer un léger changement dans l'utilisation de malloc (), pour toutes les réponses suggérant de l'utiliser pour allouer de la mémoire à l'int. Au lieu de:

a = malloc(sizeof(int));

Je suggérerais de ne pas répéter le type de la variable, car cela est connu du compilateur et de le répéter manuellement, ce qui rend le code plus dense et introduit un risque d'erreur. Si vous modifiez ultérieurement la déclaration, par exemple,

long *a;

Sans changer l'allocation, vous alloueriez une mauvaise quantité de mémoire (dans le cas général, sur les ordinateurs 32 bits int et long sont souvent les mêmes. Taille). C'est, IMO, mieux utiliser:

a = malloc(sizeof *a);

Cela signifie simplement "la taille du type indiqué par un", dans ce cas int , ce qui est bien sûr parfaitement correct. Si vous modifiez le type dans la déclaration comme ci-dessus, cette ligne est toujours correcte. Il existe toujours un risque si vous modifiez le nom de la variable à gauche de l'affectation, mais qu'au moins vous ne répétez plus les informations inutilement.

Notez également qu'aucune parenthèse n'est requise avec sizeof lorsque vous l'utilisez sur des objets réels (variables, par exemple), uniquement avec des noms de type, qui ressemblent à des expressions castées. sizeof n'est pas une fonction, c'est un opérateur.

Parce que vous n’avez jamais alloué de mémoire pour a. Vous venez d'allouer de l'espace de pile pour un pointeur sur un.

int *a = NULL;

a = malloc (sizeof (int));

if (a != NULL)
{
*a =10;
}

Cela fonctionnera.

Vous pouvez également indiquer l'adresse d'une variable existante, ce qui fonctionnerait également.

c'est-à-dire

int a* = NULL;
int b = 10;

a = &b;

Cela signifie maintenant que faire quelque chose comme

*a = 100;

définira également b comme étant == 100

Découvrez ceci: http://home.netcom.com/~tjensen/ptr/pointers.pdf

La ligne suivante,

int *a = 10;

définit un pointeur sur un entier a . Vous devez ensuite pointer le pointeur a sur l'emplacement de mémoire 10.

La ligne suivante,

*a = 100;

Place la valeur 100 dans l’emplacement mémoire indiqué par a.

Le problème est le suivant:

  1. Vous ne savez pas où un pointeur. (Vous ne connaissez pas la valeur de l'emplacement mémoire 10)
  2. Où qu'un point pointe vers, vous n'avez probablement aucun droit de changer cette valeur. C'est probablement la mémoire d'un autre programme / processus. Voleur!

Étant donné que vous déclarez un pointeur sur int, initialisez le pointeur à 10 (une adresse), puis essayez d'attribuer une valeur à un int à cette adresse. Comme la mémoire à l'adresse 10 n'appartient pas à votre processus, vous obtenez un blocage. Cela devrait fonctionner:

int *a;
a = malloc(sizeof(int));
*a = 10;
printf("a=%i\n", *a);
free(a);

Ce code est-il même compilé? 10 n'est pas convertible en int * , à moins que vous ne le diffusiez comme suit:

int *a = (int *) 10;
*a = 100;

Dans ce cas, vous essayez d'écrire 100 dans l'adresse mémoire située à l'adresse 10. Cela n'est généralement pas une adresse mémoire valide. Votre programme se bloque.

Il se bloque probablement car vous attribuez le pointeur à une partie de la mémoire à laquelle vous n’avez pas accès, puis vous attribuez une valeur à cet emplacement mémoire (ce que vous n’êtes pas autorisé à faire!).

Vous pouvez également l'écrire comme suit:

int* a = 10;
*a = 100;

Notez les différents espacements sur la première ligne. Ce n'est pas un style populaire, mais je pense personnellement que c'est plus clair. Il a exactement la même signification pour le compilateur.

Ensuite, lisez-le à haute voix:

"Pointer-to-int 'a' becomes 10"
"Value-pointed-to-by 'a' becomes 100"

Substituer la valeur réelle:

"Value-pointed-to-by 10 becomes 100"

... où vous vous rendez compte qu'il est peu probable que 10 indique un morceau de mémoire utilisable.

Vous n’attribuerez pratiquement jamais un pointeur avec un littéral:

int* ptr = (int*)10;  // You've guessed at a memory address, and probably got it wrong
int* ptr = malloc(sizeof(int)); // OS gives you a memory address at runtime  

Je suppose qu'il pourrait y avoir des très travaux de bas niveau dans lesquels vous spécifiez directement des adresses de mémoire absolue. La mise en oeuvre du noyau par exemple?

D'accord, essayez de donner l'explication la plus simple aujourd'hui, tout en essayant de vous donner une image plus détaillée de la situation. Ajoutons des parenthèses, allons-nous?

(int*) a = 10;
(*a) = 100;

Vous essayez d'écrire quatre octets dans la plage d'adresses [10-13]. La disposition de la mémoire de votre programme commence généralement plus haut, de sorte que votre application n'écrase pas accidentellement quoi que ce soit où elle pourrait et fonctionnerait toujours (par exemple, à partir de .data, .bss et stack). Donc, il finit simplement par planter, car la plage d'adresses n'a pas été allouée.

Le pointeur pointe sur un emplacement mémoire et le typage statique C définit un type pour un pointeur. Bien que vous puissiez facilement remplacer le pointeur. Simplement:

(void*) v = NULL;

Ici, nous allons plus loin dans les choses. Qu'est-ce qu'un pointeur nul? Il s'agit simplement d'un pointeur pointant vers l'adresse 0.

Vous pouvez également donner un type de structure pour votre pointeur:

struct Hello {
    int id;
    char* name;
};

...

struct Hello* hello_ptr = malloc(sizeof Hello);
hello_ptr->id = 5;
hello_ptr->name = "Cheery";

Ok, c'est quoi Malloc? Malloc alloue de la mémoire et renvoie un pointeur sur la mémoire allouée. Sa signature de type est la suivante:

void* malloc(size_t size);

Si vous ne disposez pas d'un récupérateur de place conservateur, il est probable que votre mémoire ne sera pas libérée automatiquement. Par conséquent, si vous souhaitez récupérer la mémoire à partir de ce que vous venez d’allouer, vous devez procéder:

free(hello_ptr);

Chaque malloc que vous faites contient une balise de taille. Vous n'avez donc pas besoin d'indiquer la taille du morceau que vous avez désigné pour le programme libre.

D'accord, il reste une chose: à quoi ressemble une chaîne de caractères en mémoire? Celui qui ressemble à "Cheery" par exemple. Réponse simple. C'est un tableau d'octets à zéro terminal.

0.1.2.3.4.5. 6
C h e e r y \0
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top