Qu'est-ce qu'une faute de segmentation? Est-ce différent en C et C++? Comment les fautes de segmentation et les pointeurs en suspens sont-ils liés?
L’erreur de segmentation est un type d’erreur spécifique provoquée par l’accès à une mémoire qui "ne vous appartient pas". Il s’agit d’un mécanisme d’aide qui vous empêche de corrompre la mémoire et d’introduire des bogues mémoires difficiles à déboguer. Chaque fois que vous obtenez une erreur de segmentation, vous savez que vous faites quelque chose de mal avec la mémoire - accéder à une variable déjà libérée, écrire dans une partie en lecture seule de la mémoire, etc. En ce qui concerne la gestion de la mémoire, il n’ya pas de différence principale entre les segfaults en C et C++.
Il y a beaucoup de façons d'obtenir un segfault, du moins dans les langages de bas niveau tels que C (++). Un moyen courant d'obtenir un segfault consiste à déréférencer un pointeur nul:
int *p = NULL;
*p = 1;
Une autre erreur de segmentation se produit lorsque vous essayez d'écrire dans une partie de la mémoire marquée en lecture seule:
char *str = "Foo"; // Compiler marks the constant string as read-only
*str = 'b'; // Which means this is illegal and results in a segfault
Le pointeur suspendu pointe vers une chose qui n’existe plus, comme ici:
char *p = NULL;
{
char c;
p = &c;
}
// Now p is dangling
Le pointeur p
pendille car il pointe vers la variable de caractère c
qui a cessé d'exister après la fin du bloc. Et lorsque vous essayez de déréférencer le pointeur en suspens (comme *p='A'
), vous obtiendrez probablement une erreur de segmentation.
Il convient de noter que l'erreur de segmentation n'est pas causée par l'accès direct à une autre mémoire de processus (c'est ce que j'entends parfois), car ce n'est tout simplement pas possible. Avec la mémoire virtuelle, chaque processus a son propre espace d'adressage virtuel et il n'y a aucun moyen d'accéder à un autre en utilisant une valeur de pointeur. Une exception à cela peut être les bibliothèques partagées qui sont le même espace d'adressage physique mappé vers (éventuellement) différentes adresses virtuelles et la mémoire du noyau qui est même mappée de la même manière dans chaque processus (pour éviter le vidage de TLB sur syscall, je pense). Et des choses comme shmat;) - c’est ce que je considère comme un accès "indirect". On peut toutefois vérifier qu’ils sont généralement situés loin du code de processus et que nous sommes généralement en mesure d’y accéder (c’est pourquoi ils sont là, mais leur accès de manière incorrecte produira une erreur de segmentation).
Néanmoins, une erreur de segmentation peut survenir en cas d'accès incorrect à notre mémoire (de processus) (par exemple, en essayant d'écrire dans un espace non-inscriptible). Mais la raison la plus courante en est l'accès à la partie de l'espace d'adressage virtuel qui est non mappée à un emplacement physique du tout.
Et tout cela en ce qui concerne les systèmes de mémoire virtuelle.
Une erreur de segmentation est provoquée par une requête pour une page que le processus n'a pas répertoriée dans sa table de descripteur ou par une requête non valide pour une page qu'il a répertoriée (par exemple, une requête d'écriture sur une page en lecture seule).
Un pointeur suspendu est un pointeur qui peut ou non pointer vers une page valide, mais qui pointe vers un segment "inattendu" de la mémoire.
Pour être honnête, comme d'autres affiches l'ont mentionné, Wikipedia a un très bon article à ce sujet jetez-y un coup d'œil. Ce type d'erreur est très courant et s'appelle souvent autre chose, telle que Violation d'accès ou Protection générale. Faute.
Ils ne sont pas différents en C, C++ ou dans tout autre langage autorisant les pointeurs. Ces types d’erreurs sont généralement causées par des pointeurs qui sont
Selon Wikipédia:
Une erreur de segmentation se produit lorsqu'un programme tente d'accéder à un emplacement mémoire auquel il n'est pas autorisé ou tente d'accéder à un emplacement mémoire d'une manière non autorisée (par exemple, une tentative d'écriture dans un emplacement en lecture seule ou écraser une partie du système d’exploitation).
L'erreur de segmentation est également causée par des défaillances matérielles, dans ce cas les mémoires RAM. C'est la cause la moins fréquente, mais si vous ne trouvez pas d'erreur dans votre code, peut-être qu'un memtest pourrait vous aider.
La solution dans ce cas, changez la RAM.
modifier:
Il y a ici une référence: erreur de segmentation par le matériel
erreur de segmentation se produit lorsqu'un processus (instance en cours d'un programme) tente d'accéder à une adresse mémoire en lecture seule ou à une plage de mémoire utilisée par un autre processus ou d'accéder à une adresse mémoire inexistante (non valide) . problème de référence en suspens (pointeur) signifie que tenter d'accéder à un objet ou à une variable dont le contenu a déjà été supprimé de la mémoire, par exemple:
int *arr = new int[20];
delete arr;
cout<<arr[1]; //dangling problem occurs here
La page Segmentation_fault de Wikipedia contient une description très agréable, citant simplement les causes et les raisons. Consultez le wiki pour une description détaillée.
En informatique, une erreur de segmentation (souvent abrégée en erreur de segment) ou une violation d'accès est une erreur générée par le matériel avec protection de la mémoire, avertissant le système d'exploitation de la violation de l'accès à la mémoire.
Voici quelques causes typiques d'une erreur de segmentation:
Celles-ci sont souvent causées par des erreurs de programmation qui entraînent un accès invalide à la mémoire:
Déréférencement ou attribution à un pointeur non initialisé (pointeur joker, qui pointe vers une adresse mémoire aléatoire)
Déréférencement ou attribution à un pointeur libéré (pointeur suspendu, qui pointe vers la mémoire libérée/désaffectée/supprimée)
Un débordement de tampon.
Un débordement de pile.
Tenter d'exécuter un programme qui ne se compile pas correctement. (Certains compilateurs produiront un fichier exécutable malgré la présence d’erreurs lors de la compilation.)
En termes simples: erreur de segmentation: le système d’exploitation envoie un signal au programme indiquant qu’il a détecté un accès illégal à la mémoire et met fin prématurément au programme afin d’empêcher que la mémoire ne soit corrompue.
Une erreur de segmentation ou une violation d'accès se produit lorsqu'un programme tente d'accéder à un emplacement de mémoire inexistant ou tente d'accéder à un emplacement de mémoire d'une manière non autorisée.
/* "Array out of bounds" error
valid indices for array foo
are 0, 1, ... 999 */
int foo[1000];
for (int i = 0; i <= 1000 ; i++)
foo[i] = i;
Ici, je [1000] n'existe pas, alors segfault se produit.
Causes de l'erreur de segmentation:
it arise primarily due to errors in use of pointers for virtual memory addressing, particularly illegal access.
De-referencing NULL pointers – this is special-cased by memory management hardware.
Attempting to access a nonexistent memory address (outside process’s address space).
Attempting to access memory the program does not have rights to (such as kernel structures in process context).
Attempting to write read-only memory (such as code segment).
Il existe plusieurs bonnes explications de "Erreur de segmentation" dans les réponses, mais comme avec erreur de segmentation, il y a souvent un vidage du contenu de la mémoire, je voulais partager la relation entre la partie "noyau vidée" dans Erreur de segmentation (noyau vidé) et la mémoire provient de:
Entre 1955 et 1975 - avant les mémoires à semi-conducteurs - la technologie dominante dans la mémoire d'ordinateur utilisait de minuscules beignets magnétiques attachés à des fils de cuivre. Les beignets étaient appelés "noyaux de ferrite" et la mémoire principale, aussi appelée "mémoire centrale" ou "noyau".
Tiré de ici .
"Erreur de segmentation" signifie que vous avez essayé d'accéder à une mémoire à laquelle vous n'avez pas accès.
Le premier problème est avec vos arguments de main. La fonction principale doit être int main (int argc, char * argv []) et vous devez vérifier que argc vaut au moins 2 avant d'accéder à argv [1].
De plus, puisque vous passez un float à printf (qui, en passant, est converti en double lors du passage à printf), vous devez utiliser le spécificateur de format% f. Le spécificateur de format% s concerne les chaînes (tableaux de caractères terminés par "\ 0").