Перевернув строку, странный вывод C++

Итак, я пытаюсь перевернуть строку в стиле C в C++ и натолкнулся на какой-то странный вывод. Возможно, кто-то может пролить свет?

Вот мой код:

 int main(){    

    char str[] = "string";
    int strSize = sizeof(str)/sizeof(char);

    char str2[strSize];

    int n = strSize-1;
    int i =0;


    while (&str+n >= &str){ 
        str2[i] = *(str+n);         
        n--;
        i++;
    }

    int str2size = sizeof(str)/sizeof(char);
    int x;

    for(x=0;x<str2size;x++){
        cout << str2[x];
    }

}

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

В данном конкретном случае я получаю вывод: " gnirts". В начале любого вывода есть раздражающий пробел, который, как я предполагаю, является нулевым символом? Но когда я пытаюсь избавиться от него, уменьшая переменную strSize, чтобы исключить его, я получаю другой символ на противоположном конце строки, вероятно, из другого блока памяти.

Есть идеи, как этого избежать? PS: (ребята, вы считаете это хорошей идеей перевернуть строку?)

6 ответов

Решение

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

str2[strSize - 1] = str[strSize - 1]; // Copy the null at the end of the string

int n = strSize - 2; // Start from the penultimate character

Я бы позволил стандартной библиотеке C++ сделать больше работы...

#include <cstddef>
#include <algorithm>
#include <iterator>
#include <iostream>

int main()
{
    typedef std::reverse_iterator<char const*> riter_t;

    char const str[] = "string";
    std::size_t const strSize = sizeof(str);
    char str2[strSize] = { };
    std::copy(riter_t(str + strSize - 1), riter_t(str), str2);
    std::cout << str2 << '\n';
}

@ildjarn и @Blastfurnace уже дали хорошие идеи, но я думаю, что я бы пошел дальше и использовал итераторы для построения обратной строки:

std::string input("string");

std::string reversed(input.rbegin(), input.rend());

std::cout << reversed;

В Стандартной библиотеке есть алгоритм, чтобы изменить последовательность. Зачем изобретать велосипед?

#include <algorithm>
#include <cstring>
#include <iostream>

int main()
{
   char str[] = "string";

   std::reverse(str, str + strlen(str)); // use the Standard Library

   std::cout << str << '\n';
}
 while (&str+n >= &str){

Это ерунда, хочешь просто

while (n >= 0) {

а также

 str2[i] = *(str+n);

должно быть гораздо более читабельным

str2[i] = str[n];

Ваше состояние цикла while (&str+n >= &str) эквивалентно (n >= 0),

Ваш *(str+n) эквивалентно str[n] и я предпочитаю последнее.

Как сказал HappyPixel, вы должны начать n в strSize-2, таким образом, первый скопированный символ будет последним действительным символом str, а не нулевым символом завершения str.

Затем после того, как вы скопировали все обычные символы в цикле, вам нужно добавить нулевой символ завершения в конце str2 с помощью str2[strSize-1] = 0;,

Вот исправленный рабочий код, который выводит "gnirts":

#include <iostream>
using namespace std;
int main(int argc, char **argv){    
    char str[] = "string";
    int strSize = sizeof(str)/sizeof(char);

    char str2[strSize];

    int n = strSize-2;  // Start at last non-null character
    int i = 0;

    while (n >= 0){ 
        str2[i] = str[n];         
        n--;
        i++;
    }
    str2[strSize-1] = 0;   // Add the null terminator.

    int str2size = sizeof(str)/sizeof(char);
    int x;

    cout << str2;
}
Другие вопросы по тегам