Ошибка сегментации при изменении строки с помощью указателей?

контекст

Я изучаю C, и я пытаюсь изменить строку на месте с помощью указателей. (Я знаю, что вы можете использовать массив, это больше об изучении указателей.)

проблема

При попытке запустить код ниже я продолжаю получать ошибки сегментации. Кажется, что GCC не нравится *end = *begin; линия. Почему это?

Тем более, что мой код почти идентичен не-злой функции C, уже обсуждавшейся в другом вопросе

 #include  #include  void my_strrev(char* begin){ char temp; char* end; end = begin + strlen(begin) - 1; while(end>begin){ temp = *end; *end = *begin; *begin = temp; end--; begin++; } } main(){ char *string = "foobar"; my_strrev(string); printf("%s", string); } в #include  #include  void my_strrev(char* begin){ char temp; char* end; end = begin + strlen(begin) - 1; while(end>begin){ temp = *end; *end = *begin; *begin = temp; end--; begin++; } } main(){ char *string = "foobar"; my_strrev(string); printf("%s", string); } 

Одна из проблем связана с параметром, который вы передаете функции:

 char *string = "foobar"; 

Это статическая строка, выделенная в части только для чтения. Когда вы пытаетесь перезаписать его

 *end = *begin; 

вы получите segfault.

Попробуйте

 char string[] = "foobar"; 

и вы должны заметить разницу.

Ключевым моментом является то, что в первом случае строка существует в сегменте только для чтения, и только указатель на нее используется, а во втором случае массив столбцов с соответствующим размером зарезервирован в стеке и статическая строка (которая всегда существует) копируется в него. После этого вы можете изменять содержимое массива.

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

 #include  void reverse(char *str){ int length=0,i=0; while(str[i++]!='\0') length++; for(i=0;i в #include  void reverse(char *str){ int length=0,i=0; while(str[i++]!='\0') length++; for(i=0;i 

В вашем коде у вас есть следующее:

 *end--; *begin++; 

Это просто удача, что это делает правильную вещь (на самом деле, причина – приоритет оператора). Похоже, вы на самом деле

 (*end)--; (*begin)++; 

Это совершенно неправильно. То, как вы это делаете, происходит

  • end декремента, а затем разыгрывать его
  • приращение begin а затем разыгрывает его

В обоих случаях разыменование является излишним и должно быть удалено. Вероятно, вы предполагали, что это поведение

 end--; begin++; 

Это то, что управляет разработчиком batty, потому что их так сложно отследить.

Это было бы на месте и с помощью указателей

  #include #include #include 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) по пути назад (возврат).

Умный выглядящий код, но ужасный с точки зрения использования стека.

 #include  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 \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; } 

Вот моя версия смены строки на месте.

 #include  #include  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  #include  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] = '\0'; return str; } int main() { char test[13] = "A new string"; std::cout << strRev(test) << std::endl; return 0; } 
  • Что является результатом NULL + int?
  • Объявление указателя на multidimensional array и выделение массива
  • Вызов метода с приемником указателя объектом вместо указателя на него?
  • Тип ссылки в C #
  • Предоставляет ли компилятор возможность переработать освобожденные переменные указателя?
  • В чем причина использования двойного указателя при добавлении узла в связанный список?
  • Ошибка с адресом функции-члена в скобки
  • Функция не меняет пройденный указатель C ++
  • Проверьте, указывает ли указатель на выделенную память в куче
  • C не так сложно: void (* (* f ) ()) ()
  • постоянный указатель vs указатель на постоянное значение
  • Давайте будем гением компьютера.