为什么我不能递归调用我的函数?

时间:2016-11-02 14:43:28

标签: c++

我正在尝试编译此代码以反转字符串:

void reverse(char *str, int n)
{
    if (n==0 || n==1) {
        return;         //acts as quit
    } else {
        char i = str[0];    //1st position of string
        char j = str[n-1];  //Last position of string
        char temp = str[i];
        str[i] = str[j];    //Swap
        str[j] = temp;
        reverse(str[i+1],n-1);  // <-- this line
    }
}

#include <iostream>
int main()
{
    char *word = "hello";
    int n = sizeof word;

    reverse(word, n);
    std::cout << word << std::endl;

    return 0;
}

编译器报告错误,我递归地调用reverse()

  

char处从char*reverse(str[i+1], n-1)的无效转换。

为什么?

我的代码中对其他问题的任何建议也是受欢迎的。

3 个答案:

答案 0 :(得分:2)

str[i+1]是一个字符,而不是指向字符的指针;因此错误信息。

当您输入该功能时,str指向您要与n:字符交换的角色,远离str
在递归中你需要做的是增加指针使其指向下一个字符 您还需要将n减少到两个,因为它应距离str + 1,而不是str。 (这很容易出错;请参阅此答案的编辑历史记录。)

交换时,您还使用字符串中的字符作为字符串的索引 (如果你有输入"ab",你会char temp = str['a']; str['a'] = str['b']; str['b'] = temp;。这显然不正确。)
str[0]不是第一个字符的位置,第一个字符。

如果您被允许,请使用std::swap,否则请参阅下文。

更多问题:您不应该使用sizeof word,因为根据您的目标架构,它是4或8 - 它相当于sizeof(char*)
您应该使用strlen来查找字符串的长度。

此外,您应该收到

的警告
char *word = "hello";

因为特定的转化很危险 - "hello"const数组,修改它是未定义的。
(如果你从未修改过阵列,那将是安全的,但你是,所以它不是。)
将其复制到非const数组中:

char word[] = "hello";

并提高编译器的警告级别。

这是一个固定版本:

void reverse(char *str, int n)
{   
    if(n <= 1) // Play it safe even with negative n    
    {
        return;
    }
    else
    {
        // You could replace this with std::swap(str[0], str[n-1])
        char temp = str[0];    //1st character in the string
        str[0] = str[n-1];    //Swap
        str[n-1] = temp;

        // n - 2 is one step closer to str + 1 than n is to str.
        reverse(str + 1, n - 2);
    }
}

int main()
{
    char word[] = "hello";
    // sizeof would actually work here, but it's fragile so I prefer strlen.
    reverse(word, strlen(word));
    std::cout << word << std::endl;
}

答案 1 :(得分:0)

我要剖析您的代码,就像您在Code Review上发布一样。毕竟你确实要求其他观察......

首先,

char *word = "hello";

您的编译器应警告您,将char*指向文字字符串是未定义的行为(如果没有,请确保您实际上已启用了一组良好的警告。许多编译器默认情况下发出的警告非常少,因为历史原因)。你需要确保你有一个可写的字符串;为此你可以使用char[]

char word[] = "hello";

下一行

int n = sizeof word;

现在改变了意义,但仍然是错误的。在原始代码中,它是指向char指针的大小,它不太可能与单词&#34; hello&#34;的长度相同。更改为char[]后,它现在是6个字符数组的大小,即6。第六个字符是结束字符串文字的NUL。您可能不想使用sizeof运算符,而是使用strlen()函数。

转到reverse()

您从字符串中的位置读取字符,然后使用这些字符对其进行索引。这不是你想要的,GCC警告不要使用普通char进行索引,因为它可能是签名或未签名的。您只想在一个地方编制索引,而ij是不必要的。

最后,你问的问题。 str[i+1]是位置i+1 字符,但您的函数需要一个指向字符的指针,它只是str+i+1。或者,自从我们制定出来之后,我们不希望i在那里,只有str+1

另请注意,您需要从n而不是1中减去2,因为它将用作str+1中的字符数。如果你只减去1,你将永远与最后一个字符进行交换,并且你将实现“滚动”。而不是反向&#39;

这是一个有效的版本:

void reverse(char *str, int n)
{
    if (n < 2)
        // end of recursion
        return;         //acts as quit

    char temp = str[0];
    str[0] = str[n-1];    //Swap
    str[n-1] = temp;
    reverse(str+1,n-2);
}

#include <iostream>
#include <cstring>
int main()
{
    char word[] = "hello";
    int n = std::strlen(word);

    reverse(word, n);
    std::cout << word << std::endl;
}

我们可以做出进一步的改变。例如,我们可以使用std::swap更清楚地表达切换。我们可以传递一对指针而不是指针和长度:

#include <utility>              // assuming C++11 - else <algorithm>

void reverse(char *str, char *end)
{
    if (end <= str)
        // end of recursion
        return;

    std::swap(*str, *end);
    reverse(str+1, end-1);
}

并使用reverse(word, word+n-1)调用它。

最后(因为我不提及std::reverse()),这是惯用的迭代版本:

void reverse(char *str, char *end)
{
    while (str < end)
        std::swap(*str++, *end--);
}

答案 2 :(得分:-1)

像这样使用:

     reverse(&str[i+1],n-1);

传递第(i + 1)个位置的地址而不是值。