Обращение строки в C

Я знаю, что это было задано тысячи раз, но я просто не могу найти ошибку в моем коде. Может ли кто-то любезно указать, что я делаю неправильно?

#include <stdlib.h>
#include <string.h>

void reverseString(char *myString){
  char temp;
  int len = strlen(myString);

  char *left = myString;
  //  char *right = &myString[len-1];                                                                                        
  char *right = myString + strlen(myString) - 1;

  while(left < right){
    temp = *left;
    *left = *right; // this line seems to be causing a segfault                                                              
    *right = temp;
    left++;
    right--;
  }
}

int main(void){
  char *somestring = "hello";
  printf("%s\n", somestring);
  reverseString(somestring);

  printf("%s", somestring);

}

Ответ 1

проблема здесь

char *somestring = "hello";

somestring указывает на строковый литерал "привет". стандарт С++ не гарантирует этого, но на большинстве машин это будут данные только для чтения, поэтому вам не будет разрешено его изменять.

объявите это таким образом вместо

char somestring[] = "hello";

Ответ 2

В конечном счете, было бы проще отменить его на месте, например:

#include <stdio.h>
#include <string.h>

void
reverse(char *s)
{
    int a, b, c;
    for (b = 0, c = strlen(s) - 1; b < c; b++, c--) { 
        a = s[b]; 
        s[b] = s[c]; 
        s[c] = a; 
    }

    return; 
}

int main(void)
{
    char string[] = "hello";
    printf("%s\n", string);
    reverse(string);
    printf("%s\n", string);

    return 0;
}

Ваше решение по существу является семантически более крупной версией этого. Поймите разницу между указателем и массивом. В стандарте явно указано, что поведение такой операции (модификация содержимого строкового литерала) составляет undefined. Вы также должны увидеть этот отрывок из eskimo:

Когда вы инициализируете массив символов со строковой константой:

char string[] = "Hello, world!";

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

string[0] = 'J';

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

char *p1 = "Hello";
int len = strlen("world");

это почти так, как если бы вы сказали

char internal_string_1[] = "Hello";
char internal_string_2[] = "world";
char *p1 = &internal_string_1[0];
int len = strlen(&internal_string_2[0]);

Здесь массивы с именем internal_string_1 и internal_string_2 должны предполагать, что компилятор фактически генерирует небольшие временные массивы каждый раз, когда вы используете строчную константу в своем коде. Тем не менее, тонкий факт заключается в том, что массивы, которые являются "позади", строковыми константами, необязательно могут быть модифицируемыми. В частности, компилятор может хранить их в режиме "только для чтения". Поэтому, если вы пишете

char *p3 = "Hello, world!";
p3[0] = 'J';

ваша программа может потерпеть крах, так как она может попытаться сохранить значение (в данном случае символ "J" ) в незаписываемую память.

Мораль заключается в том, что всякий раз, когда вы создаете или изменяете строки, вы должны убедиться, что память, которую вы создаете или изменяете, доступна для записи. Эта память должна быть либо выделенным массивом, либо некоторой памятью, которую вы динамически распределяете по методам, которые мы увидим в следующей главе. Убедитесь, что никакая часть вашей программы никогда не попытается изменить строку, которая на самом деле является одним из неназванных, неназываемых массивов, которые компилятор генерирует для вас в ответ на одну из ваших строковых констант. (Единственное исключение - инициализация массива, потому что если вы пишете в такой массив, вы пишете массив, а не строковый литерал, который вы использовали для инициализации массива.) "

Ответ 3

Вы вызываете Undefined Поведение, пытаясь изменить потенциально доступную для чтения область памяти (строковые литералы неявно const - это нормально читать, но не записывать их). Создайте новую строку и верните ее, или передайте достаточно большой буфер, и напишите в нее обратную строку.

Ответ 4

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

#include<stdio.h>
#include<string.h>
#include<malloc.h>
char * reverse(char*);

int main()
{
        char* string = "hello";
        printf("The reverse string is : %s", reverse(string));
        return 0;
}

char * reverse(char* string)
{

   int var=strlen(string)-1;
     int i,k;
     char *array;
     array=malloc(100);
     for(i=var,k=0;i>=0;i--)
    {
           array[k]=string[i];
            k++;
   }
  return array;
}

Ответ 5

Я понимаю, что вызов strrev() не может быть и речи?

Ответ 6

Ваша логика кажется правильной. Вместо использования указателей более чистое дело с char[].