我在一本书中读到了这个示例代码。我不明白为什么以下示例代码的函数声明的这一部分是必要的:
while (i <= n)
p[i++] = '\0'; // set rest of string to '\0'
这是完整的代码:
#include <iostream>
const int ArSize = 80;
char * left(const char * str, int n = 1);
int main()
{
using namespace std;
char sample[ArSize];
cout << "Enter a string:\n";
cin.get(sample,ArSize);
char *ps = left(sample, 4);
cout << ps << endl;
delete [] ps; // free old string
ps = left(sample);
cout << ps << endl;
delete [] ps; // free new string
return 0;
}
// This function returns a pointer to a new string
// consisting of the first n characters in the str string.
char * left(const char * str, int n)
{
if(n < 0)
n = 0;
char * p = new char[n+1];
int i;
for (i = 0; i < n && str[i]; i++)
p[i] = str[i]; // copy characters
while (i <= n)
p[i++] = '\0'; // set rest of string to '\0'
return p;
}
我删除后运行代码,没有问题。
最佳答案
循环是不必要的。空终止字符串以第一个空字节结束。如果分配的内存多于实际字符串所需的内存,那么这些额外字节中的内容并不重要。所有未损坏的 C 字符串处理代码都在第一个空终止符处停止。所需要的只是一个
p[i] = '\0';
在for
循环之后。然而,该一个空字节是强制性的。 C 字符串函数依赖于它,如果它丢失,将会很高兴地溢出分配的内存。本质上,他们会(尝试)继续前进,直到偶然发现内存中的下一个空字节。如果超过了分配的内存,则会导致未定义的行为,如果幸运的话,会导致崩溃;或者如果您不那么幸运的话,数据也会损坏。
也就是说:扔掉昨天的那本书。这段代码从第一行到最后一行都是一场灾难。它勉强符合 C++ 的资格。大部分都是纯 C 代码。即使作为 C 代码,它也很值得怀疑。
- Why to avoid using namespace std 。 @vol7ron 在评论中指出,主要的提示是反对在 header 中
使用命名空间std
。这里它在 .cpp 文件的函数内部使用,这显着减少了影响。尽管在我看来,这仍然值得避免。如果您不深入了解标准库的实现,您就不会真正了解您拉入范围的所有符号。如果您需要它来提高可读性,则引入特定符号(例如using std::cout;
)是更好的选择。另外,我相信我并不是唯一一个期待std::
前缀的人。例如,std::string
是我期望看到的。string
看起来有点不对劲。总是有一个挥之不去的疑问,它可能不是标准库字符串,而是自定义字符串类型。因此,包含前缀也可以提高可读性。 - 为什么 C 弦疼痛?我们已经使用
std::string
一段时间了…… - 循环复制字符?严重地?这就是
std::strcpy()
的用途。 - 原始
new
和delete
无处不在:容易出错,因为您必须手动跟踪new/delete对以避免内存泄漏。 - 更糟糕的是:不对称地拥有原始指针。
left()
分配并返回一个指针; 调用者有责任删除它。没有比这更容易出错的了。
……这些只是乍一看很突出的问题。
那段代码应该是什么样子:
#include <iostream>
#include <string>
std::string left(const std::string& str, std::size_t len = 1);
int main()
{
// getline can fail. If that happens we get an empty string.
std::string sample;
std::getline(std::cin, sample);
auto ps = left(sample, 4);
std::cout << ps << '\n';
ps = left(sample);
std::cout << ps << '\n';
return 0;
}
// `len` may be longer than the string. In that case a copy
// of the complete input string is returned.
std::string left(const std::string& str, std::size_t len)
{
return str.substr(0, len);
}
关于c++ - for 循环内的 while 循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50545859/