2009-09-10 6 views
3

mes codes segfaults et je ne sais pas pourquoi.Écriture dans c-string

1 #include <stdio.h> 
2 
3 void overwrite(char str[], char x) { 
4 int i; 
5 for (i = 0; str[i] != '\0'; i++) 
6  str[i] = x; 
7 } 
8 
9 int main(void) { 
10 char *s = "abcde"; 
11 char x = 'X'; 
12 overwrite(s, x); 
13 printf("%s\n", s); 
14 return 0; 
15 } 

Le débogueur gdb me dit, ce problème est sur la ligne 6, où je veux stocker un char, en c-string (si j'utiliser un pointeur lvalue déréférencement, ce problème est le même.) Voilà ce que il dit:

(gdb) run 
Starting program: /tmp/x/x 

Breakpoint 1, overwrite (str=0x8048500 "abcde", x=88 'X') at x.c:5 
5   for (i = 0; str[i] != '\0'; i++) 
(gdb) s 
6   str[i] = x; 
(gdb) 

Program received signal SIGSEGV, Segmentation fault. 
0x080483e3 in overwrite (str=0x8048500 "abcde", x=88 'X') at x.c:6 
6   str[i] = x; 
(gdb) q 

J'apprends de K & livre RC et cet exemple est simplifié du chapitre 2.8 (la fonction de suppression). Je n'ai aucune idée d'où est le problème.

Répondre

17

car char * s = "abcde"; crée une chaîne dans la mémoire en lecture seule. essayez

char s[] = "abcde"; 

EDIT: explication: char * est pointeur, et "ABCDE" est créé en mémoire morte -> immuable.

char [] est un tableau, qui est entièrement stocké sur pile et initialisé à partir de la mémoire, est donc mutable

-2

ma conjecture est la définition des paramètres où vous définissez le type comme un tableau de caractères. Pendant que vous passez un pointeur vers char

Vous pouvez essayer de changer la première ligne à ceci:

void overwrite(char *str, char x) { 

Un tableau de caractères et un pointeur char ne sont pas sémantiquement les mêmes.

+0

'char str [] 'et' char * str' sont équivalentes comme arguments de la fonction. – sepp2k

+0

Vous avez tort, 'char str []' se désintègre en 'char *' lorsqu'il est utilisé dans une liste de paramètres. – avakar

+0

ok .... Mais je suis juste qu'ils sont différents dans certains cas, non? Pourriez-vous préciser dans quel cas c'est différent? – Toad

2

Lorsque vous définissez un pointeur sur un littéral de chaîne , déclarez-le en tant que const char *. De cette façon, votre compilateur se plaint lorsque vous essayez d'envoyer cette chaîne à la fonction overwrite().

const char *s = "abcde"; 
char t[] = "fghij"; 
char x = 'X'; 

overwrite(s, x); /* oops */ 
overwrite(t, x); /* ok */ 
1

Non en désaccord, mais juste pour élaborer: Considérez ce qui se passerait si le compilateur le permettait. Vous pouvez écrire:

char *s1="abcde"; 
char *s2="abcde"; 
s1[0]='x'; 
puts(s1); 
puts(s2); 

Si le compilateur reconnaît que les deux littéraux sont les mêmes et les réutilise, mais permet également la ligne 3, votre sortie serait:

xbcde 
xbcde 

Ce qui est probablement pas ce que tu voudrais. Ce serait particulièrement mystérieux si les deux littéraux étaient dans des parties largement séparées du programme.

+0

C'est la raison pour laquelle les chaînes .Net sont immuables. Il réutilise les chaînes via quelque chose appelé "string interning". –

+0

@Tom Ritter - Oui, c'est pourquoi .Net est une plate-forme complètement différente avec des objectifs complètement différents de C. –

-1

Essayez sur:

#include <iostream> 
#include <cstring> 

using namespace std; 

void overwrite(char[], char); 

int main(void) 
{ 
     char *s = strdup("abcde"); 
     char X = 'X'; 
     overwrite(s, X); 
     cout << s << endl; 

     if(s!=NULL) 
       delete [] s; 

     return 0; 
} 

void overwrite(char str[], char x) 
{ 
     for(int i=0; str[i]!='\0'; i++) 
       str[i] = x; 
} 
+0

Question est étiqueté comme C ... et si vous allez vérifier s étant NULL, vous pouvez vérifier immédiatement après le strdup() appel, plutôt que d'utiliser un pointeur invalide. – pmg

+0

aussi strdup fait un malloc() ... appeler delete [] sur c'est faux. – Nicholaz