Question

J'ai donc du code C:

#include <stdio.h>
#include <string.h>

/* putting one of the "char*"s here causes a segfault */
void main() {
  char* path = "/temp";
  char* temp;
  strcpy(temp, path);
}

Ceci compile, fonctionne et se comporte comme il se doit. Toutefois, si l'un des pointeurs de caractère ou les deux sont déclarés comme variable globale, strcpy entraîne une erreur de segmentation. Pourquoi cela arrive-t-il? Évidemment, il y a une erreur dans ma compréhension de la portée.

Était-ce utile?

La solution

Comme d'autres affiches l'ont mentionné, le problème réside dans le fait que le traitement temporaire n'est pas initialisé. Lorsqu'elle est déclarée comme une variable automatique sur la pile, elle contient toutes les données erronées qui se trouvent dans cet emplacement de mémoire. Apparemment, pour le compilateur + CPU + SE que vous utilisez, la corbeille à cet emplacement est un pointeur valide. La stratégie "réussit". en ce sens qu'il ne s'agit pas d'une erreur de segmentation mais bien d'une copie d'une chaîne vers un emplacement quelconque ailleurs dans la mémoire. Ce genre de problème de corruption de la mémoire fait peur aux programmeurs C partout dans le monde, car il est extrêmement difficile à déboguer.

Lorsque vous déplacez la déclaration de variable temporaire vers la portée globale, elle est placée dans la section BSS et automatiquement mise à zéro. Les tentatives de déréférencement * temp entraînent alors une erreur de segmentation.

Lorsque vous déplacez * path vers une portée globale, * temp déplace alors d'un emplacement vers le haut de la pile. Les ordures à cet endroit ne sont apparemment pas un pointeur valide. Par conséquent, le déréférencement * temp entraîne une erreur de segmentation.

Autres conseils

La variable temporaire ne pointe pas vers un stockage (mémoire) et elle n'est pas initialisée.

si temp est déclaré comme char temp [32]; , le code fonctionnera alors où qu'il soit déclaré. Déclarer temp avec une taille fixe comme celle-ci pose cependant d’autres problèmes, mais c’est une question qui se pose un autre jour.

Maintenant, pourquoi se bloque-t-il lorsqu'il est déclaré globalement et non localement? Chance ...

Lorsqu’elle est déclarée localement, la valeur de temp provient de la valeur qui pourrait figurer sur la pile à ce moment-là. C'est par chance que cela pointe vers une adresse qui ne provoque pas de crash. Cependant, il détruit la mémoire utilisée par quelqu'un d'autre.

Lorsqu'elles sont déclarées globalement, sur la plupart des processeurs, ces variables seront stockées dans des segments de données qui utiliseront des pages sans demande. Ainsi, char * temp apparaît comme s'il avait été déclaré char * temp = 0 .

Vous avez oublié d'allouer et d'initialiser temp:

temp = (char *)malloc(TEMP_SIZE);

Assurez-vous simplement que TEMP_SIZE est suffisamment grand. Vous pouvez également calculer cela au moment de l'exécution, puis assurez-vous que la taille est suffisante (doit être au moins strlen (chemin))

Comme mentionné ci-dessus, vous avez oublié d'allouer de l'espace pour temp. Je préfère strdup à malloc + strcpy . Il fait ce que vous voulez faire.

Non, cela ne fonctionne pas quelles que soient les variables. On dirait que c'est parce que vous avez eu la chance. Vous devez allouer de l'espace pour stocker le contenu de la chaîne plutôt que de laisser la variable non initialisée.

Les variables non initialisées sur la pile vont pointer vers des emplacements de mémoire assez aléatoires. Si ces adresses s'avèrent être valides, votre code piétinera tout ce qui s'y trouvait, mais vous n'obtiendrez pas d'erreur (mais des bogues liés à la corruption de la mémoire risquent de se produire ailleurs dans votre code).

Les globes échouent systématiquement car ils sont généralement configurés pour des modèles spécifiques qui pointent vers une mémoire non mappée. Tenter de les déréférencer vous donne immédiatement une erreur de segmentation (ce qui est mieux - le laisser à plus tard rend le bogue très difficile à détecter).

Je voudrais réécrire le premier fragment d'Adam comme

// Make temp a static array of 256 chars
char temp[256];
strncpy(temp, sizeof(temp), path);
temp[sizeof(temp)-1] = '\0';

Ainsi, vous:

1. don't have magic numbers laced through the code, and
2. you guarantee that your string is null terminated.

Le deuxième point correspond à la perte du dernier caractère de votre chaîne source s'il est composé de > = 256 caractères.

L'important à noter:
La chaîne de destination doit être suffisamment grande pour recevoir la copie.
Dans votre cas, aucune mémoire ne sera allouée à temp.

Copié à partir de la page de manuel de strcpy:

DESCRIPTION
   The  strcpy()  function  copies the string pointed to by src (including
   the terminating '\0' character) to the array pointed to by  dest.   The
   strings  may not overlap, and the destination string dest must be large
   enough to receive the copy.

Vous invoquez un comportement non défini, car vous n'initialisez pas la variable temp . Il pointe vers un emplacement aléatoire dans la mémoire, de sorte que votre programme peut fonctionner, mais il est fort probable qu'il segfault. Vous devez faire en sorte que votre chaîne de destination soit un tableau ou qu'elle pointe vers la mémoire dynamique:

// Make temp a static array of 256 chars
char temp[256];
strncpy(temp, 256, path);

// Or, use dynamic memory
char *temp = (char *)malloc(256);
strncpy(temp, 256, path);

Utilisez également strncpy () au lieu de strcpy () pour éviter les dépassements de mémoire tampon.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top