如有疑问,请转到Stackoverflow ...
我遇到字符串分配问题。我的目标是存储n个传递的引用字符串的长度。我检查m_p是否为null因为我认为在调试模式下MS喜欢将地址设置为0xcccccccc而不是0x00000000。
我把1分进了长度。但是当我使用new分配它时,我在m_p中得到大约15个符号字符。如果m_size = lenth + 1是2,那该怎么办?我希望它只分配两个单元格。如何将其限制为长度+ 1?
String::String(const char *str, int length) {
m_size = length + 1; // make room for null-terminated string
if (m_p != NULL)
m_p = NULL;
try
{
m_p = new char[m_size];
}
catch (bad_alloc e)
{
throw e;
}
strncpy(m_p, str, m_size);
}
答案 0 :(得分:4)
让我指出这里的缺陷:
答案 1 :(得分:3)
您确定str
的实际长度与length
匹配吗?
http://www.cplusplus.com/reference/clibrary/cstring/strncpy/
没有隐含的空字符 附加到目的地的末尾,所以 目的地只会 如果C的长度,则以null结尾 source中的字符串小于num。
答案 2 :(得分:1)
你在哪里看到15个字符?内存管理器可能决定分配超过2个字节(因为优化)。或者在2个字节之后可能还有另一个内存分配,但是某些巧合也属于您的程序。即使您在Visual C ++调试器中看到15个字符并不意味着您可以安全地在代码中访问这些字符,因为您只能保证分配2个字节。
我还在您的代码中看到了其他一些问题:
if (m_p != NULL) m_p = NULL;
如果已经分配了m_p,这将导致内存泄漏。您应该在构造函数中将m_p设置为NULL,然后将以上行替换为:
if (m_p != NULL) {
delete[] m_p;
m_p = NULL;
}
如果你只在构造函数中使用那部分代码,那么简单的m_p = NULL;
就可以了。
当你立即重新抛出异常时,try .. catch块也没有多大意义。要么立即在catch块中处理它,要么完全删除try catch。
答案 3 :(得分:1)
您可以使用std::string
并观看所有与字符串相关的错误消失吗?
答案 4 :(得分:0)
你如何判断m_p中有“15个符号字符”?
'm_p'(我假设)只是char *
。当您使用new分配内存时,它会为您提供指向该内存的指针。分配给你的内存可能只有2个字节长,但在它之后还有更多的内存 - 现在或将很快被分配给其他人。
现在,如果你在调试器中查看*m_p
(或打印出来),它将被假定为一个nul-terminate字符串,因此它将保持打印字符,直到它达到0-字节。是否所有这些字符都是分配给您的块的一部分是无关紧要的。
答案 5 :(得分:0)
如果要存储传递的带引号字符串的n个字符,则需要考虑如果源字符串的长度大于或等于length参数,则strncpy不会追加空字符。所以你必须要照顾它:
strncpy(m_p, str, length); // or strncpy(m_p, str, m_size-1);
m_p[length] = '\0'; // or m_p[m_size-1] = '\0'
答案 6 :(得分:0)
我认为您观察的是调试器,显示m_p指向的内存位置。调试器显示char数组字符,直到它看到一个你没有附加到C字符串的空字符,因此你提到的附加了大约15个字符。阅读关于你的问题的其他答案,它们将有助于完全缓解这种影响。
答案 7 :(得分:0)
关于strncpy的其他答案是正确的。这可能是你问的问题的根源。
但是我很担心这句话:
我检查m_p是否为null,因为我认为 在调试模式下,MS喜欢设置 地址为0xcccccccc而不是 00000000
它只将未初始化的指针设置为0xcccccccc。这样做有助于捕获代码假定未初始化指针设置为0x00000000的位置。在C ++中,你必须始终记住,如果保持未初始化,原始类型(指针,char,short,int,float等)没有保证值。
因此,如果您在释放模式下未初始化该指针,有时可能是0x00000000,有时它可能是非零的垃圾值。这很可能会导致您尝试做的事情出现问题。
if (m_p != NULL) m_p = NULL;
不是解决方案。解决方案是在类的构造函数中将m_p
设置为NULL
。这样你就可以保证它具有适当的价值。