有没有办法将 int 赋入具有递归函数的字符串中,而无需将数字反转两次
Is there a way to assign an int into a string with a recursive function without reversing the number twice?
有没有办法将 int 赋入具有递归函数的字符串中,而无需在每次递归调用时反转两次数字?
#include <string.h>
#include <iostream>
using namespace std;
int numreverse(long int n, long int rev);
void numtostring(unsigned int n, char str[]);
int main()
{
char n[5];
numtostring(1234, n);
cout << n << endl;
}
void numtostring(unsigned int n, char str[]){
n = numreverse(n, 0);//reverse the int
if (n <= 0)return;
else{
str[0] = (char)(n % 10 + (int)'0');
str[1] = 0;
n /= 10;
n = numreverse(n, 0);//reverse it again before recursive call
numtostring(n, str + 1);
}
}
int numreverse(long int n, long int rev){
if (n == 0)
return rev;
return numreverse(n / 10, rev * 10 + n % 10);
}
注意:numtostring
本身必须是递归的,并且不能修改其签名。
注意 2:不能使用其他库。
注3:应避免使用静态或全局变量。
numtostring()
的接口是一个类似 C 的接口。 除了在问题中显示的main()
测试程序中选择I/O操作之外,代码很可能是C而不是C++。
不将接口更改为numtostring()
并且递归的要求使其比应有的更混乱和效率更低,如果您不被允许使用其他库函数,则更是如此。 在C++中,你真的不应该乱搞char
等的原始数组。 但是,规则就是规则。 代码可以在没有 numreverse()
函数的情况下实现——当用于重新反转以一个或多个零结尾的数字时,该函数会失败(例如,1000 反转是 1,但 1 反转仍然是 1,而不是 1000,或者 100、10 甚至 1,000,000,000?)。
递归的关键技巧是确保您已正确识别和处理基本情况,然后递归案例建立在基本案例之上。 在这里,基本情况需要为"当值小于 10 时",递归情况(值至少为 10)需要获取前导数字的字符串(对应于值除以 10),然后附加最后一个数字。
棘手的是,该函数不能假设任何关于str
的事情,除了"指针指向可修改的内存"和"有足够的空间来容纳正在格式化的数字加上终端空值"时第一次调用它。 特别是,它不能假设str
开头有一个空字节。 因此,基本情况必须确保字符串以 null 结尾;递归大小写必须附加到"已知以 null 结尾"字符串。 这意味着代码的运行速度比约束不那么严格的代码慢,因为递归大小写必须找到字符串的末尾以附加其数字。
#include <iostream>
#include <cstring> // memset() - used in test code
using namespace std;
void numtostring(unsigned int n, char str[]);
int main()
{
int v;
while (cin >> v)
{
char n[32];
memset(n, 'xA5', sizeof(n));
numtostring(v, n);
cout << v << " == [" << n << "]n";
}
}
void numtostring(unsigned int n, char str[])
{
if (n > 9)
{
numtostring(n / 10, str);
while (*str != ' ')
str++;
*str++ = n % 10 + '0';
*str = ' ';
}
else
{
*str++ = n % 10 + '0';
*str = ' ';
}
}
示例运行:
$ n2s < data.n2s
0 == [0]
1 == [1]
2 == [2]
3 == [3]
4 == [4]
5 == [5]
6 == [6]
7 == [7]
8 == [8]
9 == [9]
10 == [10]
11 == [11]
99 == [99]
100 == [100]
999 == [999]
1000 == [1000]
1001 == [1001]
1002 == [1002]
$
(程序源码在n2s.cpp
中,被编译成程序n2s
,要转换的数字存储在data.n2s
中。方括号和memset()
操作只需确保格式化功能正确设置数据。
代码审查有帮助
上面numtostring()
有一个丑陋的重复,多想一想就知道它不仅丑陋而且没有必要。更简化的代码版本是:
void numtostring(unsigned int n, char str[])
{
if (n > 9)
{
numtostring(n / 10, str);
while (*str != ' ')
str++;
}
*str++ = n % 10 + '0';
*str = ' ';
}
while
循环令人讨厌,但很有必要。
使用帮助程序函数
由于numreverse()
是允许的,因此代码显然可以使用作为解决方案的一部分编写的函数,因此更有效的解决方案使用递归帮助程序函数,但此解决方案也违反了规则,因为numreverse()
本身不再是递归的。
#include <iostream>
#include <cstring> // memset() - used in test code
using namespace std;
void numtostring(unsigned int n, char str[]);
int main()
{
int v;
while (cin >> v)
{
char n[32];
memset(n, 'xA5', sizeof(n));
numtostring(v, n);
cout << v << " == [" << n << "]n";
}
}
static char *n2s_helper(unsigned int n, char *str)
{
if (n > 9)
str = n2s_helper(n / 10, str);
*str = n % 10 + '0';
return str + 1;
}
void numtostring(unsigned int n, char str[])
{
str = n2s_helper(n, str);
*str = ' ';
}
对于相同的输入,它产生相同的输出。 它更有效,因为它只将一个空字节写入结果字符串,并且因为它不需要在每次需要添加数字时都找到字符串的末尾。 当然,需要大量的转换才能发现性能的差异。
在这两种解决方案中,操作代码(numtostring()
和n2s_helper()
)都是有效的C函数,就像它们是有效的C++函数一样,它们的行为在两种语言中都是相同的。
注意:
numtostring
本身必须是递归的,并且不能修改其签名。
这是一个愚蠢的要求。我至少可以更改返回类型吗?使代码更简单:
char * numtostring(unsigned int n, char * str)
{
if (n >= 10) str = numtostring(n / 10, str);
*str = n % 10 + '0';
*++str = 0;
return str;
}
终于做到了!(编辑 - OP 编辑的问题,不使用静态和全局变量)
#include <iostream>
using namespace std;
void numtostring(unsigned int n, char str[]) //no change made to the functionn signature
{
char* count = str;
static int counter = 0; //static integer does the trick
char temp = 0;
if (n)
{
temp = n%10 + '0';
numtostring(n/10, count);
}
*(count+counter) = temp;
if (temp) count[++counter] = ' ';
else counter = 0;
}
int main()
{
char n[5] = "TECH";
numtostring(12, n);
cout << n << endl;
numtostring(32, n);
cout << n << endl;
}
- g++的分段错误(在NaN上使用to_string两次时)
- 蛇在C++不会连续转两次
- 检查一个数组是否包含在另一个数组中,以相反的顺序,至少两次
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- 我应该如何去缓解两次出现的cin?
- Realloc 两次无法在 Visual Studio 上运行
- 使用 getline(cin, var) 两次在进行字符串比较时会产生错误 (==)
- 为什么映射插入和 map.find() 的单次迭代比插入和 map.find() 的两次单独迭代慢得多
- C++析构函数调用两次,堆栈分配的复合对象
- 为什么参数在构造 std::thread 时移动两次
- Qt插槽调用了两次
- 做 std::用相同的unique_ptr移动两次
- C++两次定义相同的函数会导致错误
- 为什么具有静态存储持续时间的同一内联变量在包含在 VS2017 编译的两个翻译单元中时会构造和销毁两次
- 对于优化级别为 0 的 std::vector,析构函数被调用两次
- 带有文件结束函数的 while 循环重复输出文件中的最后一个数字两次
- 连续两次写入数字时出现逻辑错误 (C++)
- C++:对数组进行排序,最后一个数字重复两次
- 有没有办法将 int 赋入具有递归函数的字符串中,而无需将数字反转两次
- 为什么我的代码要求"请输入 2-12 之间的数字:"两次?