Инвертирование строки в 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);

}
10
задан Lorenzo Donati supports Monica 3 October 2013 в 18:49
поделиться

6 ответов

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

char *somestring = "hello";

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

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

char somestring[] = "hello";
12
ответ дан 3 December 2019 в 15:21
поделиться

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

5
ответ дан 3 December 2019 в 15:21
поделиться

Я понимаю, что это грязный способ решения проблемы, но прочитав сообщение об ошибке, я знаю об этой проблеме. Так что я хочу избавиться от предупреждений. Я сбросил этот код в среде.rb:

module ActiveSupport
  module Inflector
    # Calling String#parameterize prints a warning under Ruby 1.9,
    # even if the data in the string doesn't need transliterating.
    # Maybe Rails 3 will have fixed it...?
    if RAILS_GEM_VERSION =~ /^2\.3/
      undef_method :transliterate
      def transliterate(string)
        string.dup
      end
    end
  end
end
-121--2698856-

Частота зависит от HAL (уровня абстракции оборудования). Еще в pentium дней, это было обычным использовать ЦПУ тик (который был основан на тактовой частоте ЦПУ), так что вы в конечном итоге с действительно высокочастотных таймеров.

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

-121--2896542-

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

-1
ответ дан 3 December 2019 в 15:21
поделиться

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

#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
ответ дан 3 December 2019 в 15:21
поделиться

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

0
ответ дан 3 December 2019 в 15:21
поделиться

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

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

Ваше решение, по сути, является семантически расширенной версией этого. Поймите разницу между указателем и массивом. В стандарте прямо говорится, что поведение такой операции (изменение содержимого строкового литерала) не определено. Вам также следует посмотреть эту выдержку из 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') в незаписываемой памяти.

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

13
ответ дан 3 December 2019 в 15:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: