Ошибка сегментации, возникающая при изменении строки с помощью указателей?
контекст
Я учусь C и я пытаюсь изменить строку на месте, используя указатели. (Я знаю, что вы можете использовать массив; это больше касается изучения указателей.)
8 ответов
одна проблема заключается в параметре, который вы передаете функции:
char *string = "foobar";
это статическая строка, выделенная в разделе только для чтения. Когда вы пытаетесь перезаписать его с помощью
*end = *begin;
вы получите segfault.
попробовать
char string[] = "foobar";
и вы должны заметить разницу.
ключевым моментом является то, что в первом случае строка существует в сегменте только для чтения и используется только указатель на нее, а во втором случае массив символов с правильным размером зарезервирован в стеке, и статическая строка (которая всегда существует) копируется в нее. После этого вы можете изменять содержимое массива.
вы также можете использовать нулевой символ в конце строки для замены символов в строке, тем самым избегая использования дополнительного пространства. Вот код:
#include <stdio.h>
void reverse(char *str){
int length=0,i=0;
while(str[i++]!='')
length++;
for(i=0;i<length/2;i++){
str[length]=str[i];
str[i]=str[length-i-1];
str[length-i-1]=str[length];
}
str[length]='';
}
int main(int argc, char *argv[]){
reverse(argv[1]);
return 0;
}
в вашем коде у вас есть следующее:
*end--;
*begin++;
это только чистая удача, что это делает правильную вещь (на самом деле, причина-приоритет оператора). Похоже, вы намеревались сделать код на самом деле
(*end)--;
(*begin)++;
что совершенно неправильно. Как у вас это есть, операции происходят как
- декремента
end
и затем разыменовать его - инкремент
begin
и затем разыменовать его
в обоих случаях разыменование является излишним и должно быть удалено. Вы, вероятно, предполагали, что поведение будет
end--;
begin++;
Это вещи, которые приводят разработчика в бешенство, потому что их так трудно отследить.
Это было бы на месте и с помощью указателей
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void reve(char *s)
{
for(char *end = s + (strlen(s) - 1); end > s ; --end, ++s)
{
(*s) ^= (*end);
(*end) ^= (*s);
(*s) ^= (*end);
}
}
int main(void)
{
char *c = malloc(sizeof(char *) * 250);
scanf("%s", c);
reve(c);
printf("\nReverse String %s", c);
}
изменить char *string = "foobar";
до char string[] = "foobar";
. Проблема в том, что char *
указывает только для чтения памяти, которую вы затем пытаетесь изменить, вызывая ошибку сегментации.
Это создает небольшую рекурсивную функцию (ish) и работает, сохраняя значения на пути вниз по стеку и увеличивая указатель на начало строки (*s) на обратном пути (return).
умный код, но ужасный с точки зрения использования стека.
#include <stdio.h>
char *reverse_r(char val, char *s, char *n)
{
if (*n)
s = reverse_r(*n, s, n+1);
*s = val;
return s+1;
}
int main(int argc, char *argv[])
{
char *aString;
if (argc < 2)
{
printf("Usage: RSIP <string>\n");
return 0;
}
aString = argv[1];
printf("String to reverse: %s\n", aString );
reverse_r(*aString, aString, aString+1);
printf("Reversed String: %s\n", aString );
return 0;
}
вот моя версия разворота строки на месте C.
#include <stdio.h>
#include <string.h>
int main (int argc, const char * argv[])
{
char str[] = "foobar";
printf("String:%s\n", str);
int len = (int)strlen(str);
printf("Lenth of str: %d\n" , len);
int i = 0, j = len - 1;
while(i < j){
char temp = str[i];
str[i] = str[j];
str[j] = temp;
i++;
j--;
}
printf("Reverse of String:%s\n", str);
return 0;
}
ниже вы можете увидеть мой код для этой проблемы:
#include <string>
#include <iostream>
char* strRev(char* str)
{
char *first,*last;
if (!str || !*str)
return str;
size_t len = strlen(str);
for (first = str, last = &str[len] - 1; first < last ; first++, last--)
{
str[len] = *first;
*first = *last;
*last = str[len];
}
str[len] = '';
return str;
}
int main()
{
char test[13] = "A new string";
std::cout << strRev(test) << std::endl;
return 0;
}