C++ 可能的内存泄漏:新字符[strlen()]

C++ 可能的内存泄漏:新字符[strlen()],c++,memory-leaks,C++,Memory Leaks,这是一个相当基本的问题,我很确定我知道答案,但我想我应该问的是错误的后果。我已经以以下方式使用了strlen()和new char[]操作符很长一段时间了,我刚刚注意到有一个问题出现了: void genericCopy(char *somestring, char *someOtherString) { someOtherString = new char[strlen(somestring)]; strcpy(someOtherString,somestring); } 我

这是一个相当基本的问题,我很确定我知道答案,但我想我应该问的是错误的后果。我已经以以下方式使用了
strlen()
new char[]
操作符很长一段时间了,我刚刚注意到有一个问题出现了:

void genericCopy(char *somestring, char *someOtherString) {
    someOtherString = new char[strlen(somestring)];
    strcpy(someOtherString,somestring);
}
我的问题是,既然字符串应该以null结尾,我是否应该这样做:

void genericCopy(char *somestring, char *someOtherString) {
    someOtherString = new char[strlen(somestring)+1];
    strcpy(someOtherString,somestring);
    someOtherString[strlen(someOtherString)] = '\0';
}

到目前为止,我对第一种方法从未遇到过问题,但这并不意味着我做得对。由于
strlen()
返回的长度是字符串中不带空终止符的字符数,因此new不会为“/0”保留空间。。。至少我不这么认为。

首先,你应该知道你的这个函数写起来是没有意义的,只要使用(如果你的系统上有)

但是,是的,您需要一个额外的字节来存储
\0
,因此请始终执行类似
新字符[strlen(somestring)+1]的操作。但是,不需要手动添加
\0
<代码>strcpy
已执行此操作

您应该使用类似的方法来发现代码中的此类错误和类似错误

但是,代码中还有一个额外的问题;您的代码将始终泄漏到其他字符串中;它将不会返回到您调用它的位置。您需要将方法更改为以下内容:

char *genericCopy(char *something) {
    char *copy = new char[strlen(somestring)+1];
    strcpy(copy,somestring);
    return copy;
}
void genericCopy(char *something, char **copy) {
    *copy = new char[strlen(somestring)+1];
    strcpy(*copy,somestring);
}
然后按如下方式获取副本:

copy = genericCopy(something);
或者您需要将您的方法更改为:

char *genericCopy(char *something) {
    char *copy = new char[strlen(somestring)+1];
    strcpy(copy,somestring);
    return copy;
}
void genericCopy(char *something, char **copy) {
    *copy = new char[strlen(somestring)+1];
    strcpy(*copy,somestring);
}
并称之为:

genericCopy(something, &copy);
genericCopy(something, copy);

如果您使用C++,您也可以将方法原型更改为:

void genericCopy(char* somestring, char*& someOtherString)
并称之为:

genericCopy(something, &copy);
genericCopy(something, copy);

然后,
someOtherString
将作为引用传递,并且您分配给它的新值将在您的方法之外传播。

首先,您应该知道,您的这个函数编写起来没有意义,只需使用(如果在您的系统上可用)

但是,是的,您需要一个额外的字节来存储
\0
,因此请始终执行类似
新字符[strlen(somestring)+1]的操作。但是,不需要手动添加
\0
<代码>strcpy
已执行此操作

您应该使用类似的方法来发现代码中的此类错误和类似错误

但是,代码中还有一个额外的问题;您的代码将始终泄漏到其他字符串中;它将不会返回到您调用它的位置。您需要将方法更改为以下内容:

char *genericCopy(char *something) {
    char *copy = new char[strlen(somestring)+1];
    strcpy(copy,somestring);
    return copy;
}
void genericCopy(char *something, char **copy) {
    *copy = new char[strlen(somestring)+1];
    strcpy(*copy,somestring);
}
然后按如下方式获取副本:

copy = genericCopy(something);
或者您需要将您的方法更改为:

char *genericCopy(char *something) {
    char *copy = new char[strlen(somestring)+1];
    strcpy(copy,somestring);
    return copy;
}
void genericCopy(char *something, char **copy) {
    *copy = new char[strlen(somestring)+1];
    strcpy(*copy,somestring);
}
并称之为:

genericCopy(something, &copy);
genericCopy(something, copy);

如果您使用C++,您也可以将方法原型更改为:

void genericCopy(char* somestring, char*& someOtherString)
并称之为:

genericCopy(something, &copy);
genericCopy(something, copy);

然后,
someOtherString
将作为引用传递,您分配给它的新值将在您的方法之外传播。

是的,您的怀疑是正确的。您应该分配一个额外的字符,并确保复制的字符串以null结尾。(strcpy()本身可以做到这一点,但当有人建议您切换到strncpy()时,他们无疑会这样做(这样更安全!),您需要格外小心,因为它不能保证复制“/0”。)

如果你已经使用C++,那么建议你切换到使用STD::String。这通常是一种操作字符数组的更简单、更不容易出错的方法

然而,还有一个问题需要解决。您正在将新字符数组分配给其他字符串的副本。您需要进行一些更改:

void genericCopy(char *somestring, char **someOtherString) {
    *someOtherString = new char[strlen(somestring)+1];
    strcpy(*someOtherString,somestring);
    (*someOtherString)[strlen(somestring)] = '\0';
}

通过这种方式,您将在函数调用之外获得新的字符缓冲区。

是的,您的怀疑是正确的。您应该分配一个额外的字符,并确保复制的字符串以null结尾。(strcpy()本身可以做到这一点,但当有人建议您切换到strncpy()时,他们无疑会这样做(这样更安全!),您需要格外小心,因为它不能保证复制“/0”。)

如果你已经使用C++,那么建议你切换到使用STD::String。这通常是一种操作字符数组的更简单、更不容易出错的方法

然而,还有一个问题需要解决。您正在将新字符数组分配给其他字符串的副本。您需要进行一些更改:

void genericCopy(char *somestring, char **someOtherString) {
    *someOtherString = new char[strlen(somestring)+1];
    strcpy(*someOtherString,somestring);
    (*someOtherString)[strlen(somestring)] = '\0';
}

通过这种方式,您将在函数调用之外返回新的字符缓冲区。

“到目前为止,我从未遇到过问题”。。。。幸运鸭:)第二种方法更好,但两者都不能解决内存泄漏!您不需要自己设置终止符:strcpy。此外,通过使用strcpy而不是strncpy或strlcpy(您应该在函数顶部设置
n=strlen()
,并在需要长度时使用它,而不是反复调用strlen),您也可以使用strcpy)。@dbaupp我从未想过TOCTOU问题。谢谢你指出这一点!:-如果你使用C++,为什么不使用<代码> STD::String ?“到目前为止我从来没有遇到过问题”…幸运鸭:)第二种方法更好,但两者都不能解决内存泄漏!您不需要自己设置终止符:strcpy。此外,通过使用strcpy而不是strncpy或strlcpy(您应该在函数顶部设置
n=strlen()
,并在需要长度时使用它,而不是反复调用strlen),您也可以使用strcpy)。@dbaupp我从未想过TOCTOU问题。谢谢你指出这一点!:-如果你使用C++,为什么不使用“代码> STD::String ?谢谢人类!所有的答案都很棒,但你的答案排在第一,所以你得到了饼干。感谢您对Valgrind的介绍,它似乎是一个强大的工具,我将考虑将它添加到我的兵工厂。
strdup()
是非标准的(它由POSIX定义,但不是由C标准定义),并且一致的C实现甚至不允许提供该名称的函数。然后调用方负责applyin