为什么我不能递归调用我的函数?
Why can't I call my function recursively?
我试图编译这段代码,以便反转字符串:
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()
:
在
reverse(str[i+1], n-1)
下由char
转化为char*
无效。
为什么?
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;
}
我要剖析你的代码,就像你在code Review上发表的那样。毕竟,你确实要求进行其他观察……
首先,
char *word = "hello";
编译器应该警告您,将char*
指向文字字符串是未定义的行为(如果不是,请确保您实际上启用了一组良好的警告)。由于历史原因,许多编译器在默认情况下很少发出警告)。你需要确保你有一个可写的字符串;你可以使用char[]
:
char word[] = "hello";
下一行
int n = sizeof word;
现在已经改变了意思,但仍然是错误的。在您的原始代码中,它是指向char
的指针的大小,这不太可能与单词"hello"的长度相同。更改为char[]
后,它现在是6个字符的数组的大小,即6
。第六个字符是结束字符串字面值的NUL。您可能希望使用strlen()
函数而不是sizeof
操作符。
转到reverse()
:
从字符串中的位置读取字符,然后使用这些字符对其进行索引。这不是您想要的,并且GCC警告不要使用普通char
作为索引,因为它可能是有符号的或无符号的。你只想在一个地方索引,你的i
和j
是不必要的。
最后,你问的问题。str[i+1]
是位置i+1
的字符,但是您的函数需要一个指向字符的指针,即str+i+1
。或者,因为我们算出我们不需要i
,只需要str+1
。
还请注意,您需要从n
中减去2,而不是1
,因为它将用作str+1
中的字符计数。如果你只减去1,你将总是与最后一个字符交换,并且你将获得"滚动"而不是"反转"。
这是一个工作版本:
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--);
}
使用如下:
reverse(&str[i+1],n-1);
传递(i+1)位非值的地址。
- 为什么在我的函数类型后使用引用运算符 (&) 允许我修改它返回的值?
- 在哪里放置我的函数?进入我的母语 Gui 还是进入我的演示者?
- 查找定义我的 C/C++ 函数/宏的文件比'grep'更简单的方法
- 为什么我的 constexpr 对象在我的函数中不是 constexpr?
- 为什么我的函数接受"std::string"进行排序不会改变它?
- 为什么 emscripten 不编译我的函数?
- binary_search() 函数在我的函数体中不起作用
- 如何将不同大小的数组传递给我的 C++ 函数?
- 如果我想使用 cout 为我的函数提供任何输入......我该如何给出
- (C++)我的函数不返回数组
- 如何让我的重载<<运算符打印出我的函数?
- 我的函数调用 (C++) 中的未声明标识符
- 钩/绕道 d3d9 (现在/结束场景) - 似乎调用我的函数然后崩溃
- 成员函数的"this"参数具有"const"类型,但我的函数实际上不是"const"
- 我应该声明我的函数模板专业化还是定义它们就足够了
- 为什么我的函数名称中会随机出现一个额外的字母
- 为什么我的函数无法使用指针打印多维数组的元素?
- 当我从头文件和实现文件调用我的函数到我的主文件时,我没有得到任何输出
- 钩子SSDT.其他驱动程序使用我的函数
- 如何修复我的函数 popFront 为我的列表?