2009-09-10 3 views
3

мой код segfaults, и я не знаю почему.Запись в c-строку

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 } 

GDB отладчик говорит мне, что проблема находится на линии 6, где я хочу, чтобы сохранить символ, в с-строку (если я использую именующее разыменования указателя, это та же самая проблема.) Это то, что он говорит:

(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 

Я учусь от K & RC книги и это упрощенный пример из главы 2.8 (функция удалить). Я понятия не имею, где проблема.

ответ

17

потому что char * s = "abcde"; создает строку в памяти readonly. попробуйте

char s[] = "abcde"; 

EDIT: объяснение: символ * является указателем, и "ABCDE" создается в постоянной памяти -> неизменны.

символ [] является массивом, который целиком хранится в стеке и инициализируется из памяти, так изменчиво

-2

мое предположение является определение параметров, где вы определяете тип как массив символов. В то время как вы передаете указатель на гольца

Вы можете попробовать изменить первую строку следующим образом:

void overwrite(char *str, char x) { 

массив символов и указатель голец не семантически то же самое.

+0

'символ ул [] и' символ * str' эквивалентны как аргументы функции. – sepp2k

+0

Вы ошибаетесь, 'char str []' распадается на 'char *' при использовании в списке параметров. – avakar

+0

ОК ... Но я прав, что они в некоторых случаях разные. Не могли бы вы уточнить, в каком случае это другое? – Toad

2

Если вы указали указатель на строковый литерал , объявите его как const char *.

const char *s = "abcde"; 

Таким образом, ваш компилятор жалуется, когда вы пытаетесь отправить эту строку в функцию overwrite().

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

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

Не согласен, но просто уточните: подумайте, что произойдет, если компилятор допустил это. Вы могли бы написать:

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

Если компилятор признает, что два литерала одинаковы и повторно использует их, но также позволяет линии 3, ваш выход будет:

xbcde 
xbcde 

Что, вероятно, не то, что вы хотели бы. Это было бы особенно загадочно, если бы два литерала были в широко разделенных частях программы.

+0

Вот почему в .Net строки неизменяемы. Он * делает * повторно использовать строки через что-то, называемое «интернирование строк». –

+0

@Tom Ritter - Да, поэтому .Net - это совершенно другая платформа с совершенно разными целями, чем C. –

-1

Попробуйте:

#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

Вопрос помечен как C ... и если вы собираетесь проверять, что s является NULL, вы можете проверить сразу после strdup() вместо использования недопустимого указателя. – pmg

+0

также strdup делает malloc() ... вызов delete [] на нем неверен. – Nicholaz