Quelqu'un pourrait-il me dire ce que je fais mal ici? Pourquoi mon programme se bloque-t-il? J'essaie d'insérer une troisième chaîne entre string1
Et string2
.
#include <stdio.h>
int main (void)
{
char *string1 = "HELLO";
char *string2 = "WORLD";
char *stringX = "++++";
char *string3;
printf ("%s,%s\n",string1,string2);
sprintf(string3,"%s%s%s",string1,stringX,string2);
printf ("NewVar: %s",string3);
}
Pourquoi sprintf
ne stocke-t-il pas la valeur résultante à l'adresse mémoire pointée par string3
? Cela fonctionne quand je déclare string3
Comme un tableau ordinaire mais pas quand c'est un pointeur vers char
tableau.
Je pensais que string3
Ne pointait vers aucun emplacement de mémoire, mais il semble quand je le fais printf("%p",string3);
Production:
# ./concat
HELLO,WORLD,0x40042
Imaginez que vous avez un tas d'argent que vous souhaitez mettre dans une mallette. De quoi avez-vous besoin? Vous devez mesurer la taille de l'argent pour savoir quelle taille de mallette utiliser, et vous avez besoin d'une poignée pour transporter l'argent facilement.
L'argent est vos cordes. La mallette est un espace mémoire. La poignée de la mallette est le pointeur.
strlen(string1) + strlen(string2) + strlen(stringX)
. Appelez cela "total".malloc(total+1)
string3
Bricoler tout ça ensemble ...
char *string3 = malloc(strlen(string1)+strlen(stringX)+strlen(string2)+1);
sprintf(string3, "%s%s%s", string1, stringX, string2);
Alors qu'est-ce qui n'allait pas avec la première tentative? Vous n'aviez pas de mallette. Vous avez de l'argent et vous avez une poignée, mais pas de mallette au milieu. Cela a semblé fonctionner, d'une manière aléatoire, parce que le compilateur vous a donné une poubelle sale pour contenir l'argent. Parfois, la benne à ordures a de la place, parfois non. Quand ce n'est pas le cas, nous appelons cela un "défaut de segmentation".
Chaque fois que vous avez des données, vous devez allouer de l'espace pour ces données. Le compilateur alloue de l'espace pour vos chaînes constantes, comme "HELLO"
. Mais vous devez allouer de l'espace pour les chaînes construites au moment de l'exécution.
sprintf
y stocke la valeur. Le problème est que le pointeur string3 a une valeur non initialisée, donc vous écrasez simplement la mémoire aléatoire.
Une option que vous avez consiste à utiliser un tampon de chaîne statique:
char string3[20];
snprintf(string3, sizeof(string3), "Hello!");
Ou, vous pouvez utiliser asprintf
sur GNU systèmes basés sur libc pour allouer automatiquement l'espace approprié:
char * string3;
asprintf(&string3, "Hello!");
// ... after use
free(string3); // free the allocated memory
sprintf
n'alloue pas de mémoire à la chaîne qu'il écrit. Vous devez fournir une chaîne valide pour qu'elle puisse être écrite, mais vous lui passez actuellement un pointeur non initialisé.
La solution la plus simple consiste à changer
char *string3;
sprintf(string3,"%s%s%s",string1,stringX,string2);
à
char string3[200];
sprintf(string3,"%s%s%s",string1,stringX,string2);
Vous voudrez peut-être vous prémunir contre les dépassements de mémoire tampon dans ce cas en utilisant snprintf
à la place
char string3[200];
snprintf(string3,sizeof(string3),"%s%s%s",string1,stringX,string2);
Vous pouvez également gérer des longueurs de chaîne source plus importantes en déterminant la taille de string3
au moment de l'exécution, en prenant soin de free
cette mémoire lorsque vous en avez terminé.
char* string3 = malloc(strlen(string1) + strlen(stringX) + strlen(string2) + 1);
if (string3 == NULL) {
// handle out of memory
}
sprintf(string3,"%s%s%s",string1,stringX,string2);
...
free(string3);
vous devez allouer de l'espace pour string3
soit avec malloc
si vous avez besoin qu'il soit sur le tas, soit déclarez-le comme un tableau de caractères si ce n'est pas le cas.