Сторнирование строки в C - PullRequest
       15

Сторнирование строки в C

10 голосов
/ 27 февраля 2010

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

#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);

}

Ответы [ 6 ]

13 голосов
/ 27 февраля 2010

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

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

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

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

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») в недоступной для записи памяти.

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

12 голосов
/ 27 февраля 2010

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

char *somestring = "hello";

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

объявите это вместо этого

char somestring[] = "hello";
5 голосов
/ 27 февраля 2010

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

0 голосов
/ 01 марта 2010

Я так понимаю, вызов strrev () исключен?

0 голосов
/ 01 марта 2010

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

#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;
}
0 голосов
/ 27 февраля 2010

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

...