c++ - 字符串反向功能不适用于奇数长度的字符串

标签 c++ string algorithm debugging

我试图用C ++编写以下代码以反转字符串。由于某些原因,当字符串为奇数长度时,会给出错误的输出。

#include <iostream>
using namespace std;

void swapWithOutThirdVar(char &a, char &b) {
    a = a + b;
    b = a - b;
    a = a - b;
}

void reverse(char string[]) {
    int length = 0;
    while (string[length] != '\0') {
        length++;
    }
    int left = 0, right = length - 1;
    while (left <= right) {
        swapWithOutThirdVar(string[left], string[right]);
        left++;
        right--;
    }
}

int main() {
    char string[25];
    cin>>string;

    reverse(string);
    cout<<string<<endl;
}


例如,如果我在控制台中输入lappy,则后续输出为yp。我是编程新手,所以无论潜在错误有多愚蠢,请对我友善。

最佳答案

有很多方法可以解决代码中的错误,但是代码中的主干错误在于您自己定义的交换函数。

void swapWithOutThirdVar(char &a, char &b) {
    a = a + b;
    b = a - b;
    a = a - b;
}


我知道这是一个非常著名的函数,用于不使用第三个变量就交换两个变量。但是它有两个问题:


对于ab的某些值,操作a + b可能导致溢出。
(这里就是这种情况)如果遇到将完全相同的变量传递给函数的情况,交换将最终变得不稳定。原因如下:


假设您要将变量char c传递给函数的两个参数。由于在函数中参数是通过引用传递的,因此虚拟变量ab实际上是相同的变量,也就是说,它们是相同的c的别名。简而言之,ab表示相同的变量c
因此,现在当您执行a = a + b时,该操作实际上会导致c = c + c,这意味着c的(ASCII)值在该语句执行结束时已加倍。
当第二条语句生效时,乐趣就来了。 b = a - b生成c = c - c,将0分配给c。那是你做错的地方,孩子。
第三条语句对该过程没有任何好处。 a = a - b导致c = c - c,这仍然使c保持0

因此,您的变量被分配了值0,而不是被交换(本身?)。

现在,您可能想知道到底要在哪里交换相同的变量,对吗?
当您使用奇数长度的字符串时,请注意在第二个while循环的最后一次迭代中,leftright的值相同。在这种情况下,leftright对于string具有相同的索引,因此string[left]string[right]是相同的变量。相同的变量将在该迭代中传递给交换函数。
现在,正如我之前所说:将相同的变量传递给swap函数将最终将0传递给已传递给它的变量。对于您的示例案例,这是上次迭代结束时string的样子:
['y', 'p' '\0', 'a', 'l']

在C / C ++中,null0)标记字符串的结尾。因此,奇怪的输出(yp)是合理的。

在偶数长度的字符串中,在第二个left循环的任何迭代中,right都不会等于while。这就是为什么永远不会将相同的变量传递给交换函数,这就是为什么reverse函数的工作原理与从未传递给相同的变量一样好。

因此,首先,您需要注意相同变量的情况。如果ab是相同的变量,则只需从函数返回即可,因为从技术上讲,将变量与自身交换是毫无意义的。利用以下事实:如果两个变量基本上是对同一变量的引用,则它们必须具有相同的地址。

void swapWithOutThirdVar(char &a, char &b) {
    if (&a == &b)
        return;

    a = a + b;
    b = a - b;
    a = a - b;
}


但这不能解决溢出问题。因此,您需要做其他事情。

假设这是一个编程分配问题,您需要自己实现所有操作,那么您可以进行XOR交换,该交换使用按位XOR交换两个变量。按照交换函数的名称,我认为您知道老式的三变量交换技术,并且使用第三个变量进行交换也是分配的限制。

对两个数字进行异或运算不会导致溢出,因此该问题已得到解决。尽管XOR方法不能独立解析相同变量的情况,并最终在第一条语句本身中将变量0交给了它,所以您需要保留地址相等性检查部分:

void swapWithOutThirdVar(char &a, char &b) {
    if (&a == &b)
        return;

    a ^= b;
    b ^= a;
    a ^= b;
}


另外,您可以保持交换功能不变,并稍微修改第二个while循环的条件以解决错误:
对于奇数长度的字符串,反转时中间字符的位置保持不变。想一想:当leftright(都)都指向字符串的中间字符时,出现left-等于-right的情况。因此,循环只需要运行,只要left < right保持true。对于偶数长度的字符串,left永远不会等于right。当whileleft是字符串的两个相邻中间元素的索引时,right循环就结束了。因此,left < right修改不会损害均匀长度的情况。因此,相应的修复方法是:

void reverse(char string[]) {
    int length = 0;
    while (string[length] != '\0') {
        length++;
    }
    int left = 0, right = length - 1;
    while (left < right) {
        swapWithOutThirdVar(string[left], string[right]);
        left++;
        right--;
    }
}


到此结束了错误的解释和纠正部分。但是,如果这不是针对您必须自己实现所有事情的编程任务,也就是说,您没有限制,则应该考虑以下内容:

从代码中的using namespace std;来看,它似乎适用于C ++ 0x或更高版本。因此,您应该考虑以下事项:


从C ++ 0x开始,您已经具有预定义的交换功能(std :: swap)。您可以改用它。传递给它的溢出和同变量在这里不是问题。请参见here
您在程序中使用了C样式的字符串。不再建议使用C型字符串。此外,您正在使用C ++ 0x或更高版本。因此,您应该改用std :: string。请参见here
您可以使用reverse标头中的algorithm函数。请参见here

关于c++ - 字符串反向功能不适用于奇数长度的字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59128881/

相关文章:

c# - 随机序列的周期长度

c++ - 在函数中增加数组索引

通过算法生成斑马/爱因斯坦拼图

c++ - C++ 中内置类型的运算符重载以访问二维数组中的元素

C 字符串声明

jquery - 使用 JQuery 将新属性添加到 HTML 字符串

python - 如何概括这个正则表达式,以便它开始捕获字符串开头的子字符串或者后面跟着其他单词的子字符串?

python - 在 Python 中从 A 到 B 算法切割路径所需的最小移除节点

c++ - 我们传递给参数的无符号类型是什么?

c++ - 如何使用 std::imbue 设置 std::wcout 的语言环境?