Перевернув строку, странный вывод 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;
}