7

因此,在尝试学习如何在 C++ 中使用 C-Strings 时,我遇到了内存分配问题。

这里的想法是创建一个格式为 (s1 + sep + s2) 的新字符串。我使用的文本提供了标题,所以我无法更改它,但我在尝试设置大小时遇到​​了问题的字符 str []。我收到一条错误消息,说 sLength 不是常量,因此不能用于设置数组的大小。我对 C++ 比较陌生,所以这是一个两部分的问题。

  1. 这个策略实际上是为新数组分配内存吗?

  2. 如果无法使用 strlen(char*) 获得常量值,如何正确设置数组大小?

    char* concatStrings(char* s1, char* s2, char sep){
        int sLength = strlen(s1) + strlen(s2) + 3; 
        //+1 for char sep +2 for \0 at end of string
        char *str = new char[sLength];
        strcpy (str, s1);
        str [sLength(s1)] = sep;
        strcat (str, s2);
        return str;
    }
    

进行了编辑,所以现在我没有收到编译器错误,但是...

该函数的调用在这里:

    char* str = concatStrings("Here is String one", "Here is String two" , c);
    cout<< str;

我的输出变为:

这是字符串 onec==================22221/21/21/21/2 / (等) / 这是字符串二

4

3 回答 3

9

错误是返回本地数组变量的地址str它的作用域concatStrings()在你声明的函数内,一旦控制从函数返回就无法访问。

要在外部访问它,您需要使用new运算符从堆中为字符串动态分配内存。

char* concatStrings(char* s1, char* s2, char sep){
    int s1Length = strlen(s1);
    int sLength = s1Length + strlen(s2) + 2; 
    // +1 for sep and +1 \0 at end of string
    char* str = new char[sLength];
    strcpy (str, s1);
    // Use strlen here instead of sizeof()
    str [s1Length] = sep;
    str [s1Length + 1] = '\0';
    strcat (str, s2);
    return str;
}

并且在程序使用从concatStrings它返回的字符串完成后,应该确保通过调用来释放内存delete

char* str = concatStrings(s1, s2, sep);

// Do something

// Free up memory used by str
delete[] str; 

此处必须使用 delete[] 而不是 delete,否则会导致未定义的行为

我还编辑了concatStrings()要使用的函数,strlen而不是sizeof

更新:感谢您指出我们只需要 +2 而不是 +3 并确保需要在调用之后str1和之前附加一个 '\0'sepstrcat

于 2013-03-02T22:13:43.357 回答
5

您可以动态分配生成的字符串内存(在运行时,在堆上),new[]在 C++ 中使用(或malloc更类似于 C 的风格):

char* concatStrings(const char* s1, const char* s2, char sep) // enforced const correctness
{
    const size_t totalLength = strlen(s1) + strlen(s2) 
                            + 2; // +1 for sep char, +1 for '\0' 

    // Dynamically allocate room for the new string (on the heap)
    char* str = new char[totalLength];    

    strcpy(str, s1);
    str[strlen(s1)] = sep; // note that you had a typo with sizeof(s1) here
    strcat(str, s2);
    return str;
}

请注意,此内存必须在代码中的某处释放,delete[]如果它是用 分配的new[],或者free()如果它是用 分配的malloc()

这是相当复杂的。

如果你使用一个健壮的 C++ 字符串类,你会大大简化你的代码std::string,它有方便的构造函数来分配内存,析构函数来自动释放它,operator+以及operator+=重载来连接字符串。查看如何使用以下代码简化代码std::string

#include <string> // for std::string

std::string str = s1;
str += sep;
str += s2;

(请注意,使用原始 C 字符串也可能使您的代码更容易受到安全问题的影响,因为您必须非常注意正确调整目标字符串的大小,避免缓冲区溢出等。这是更喜欢 RAII 健壮的字符串类(如std::string. )

于 2013-03-02T22:21:13.713 回答
1

sizeof(s1)返回指针变量的大小,而不是它指向的数组的长度。由于您知道它s1指向 C 字符串,因此您应该改用该strlen()函数。

于 2013-03-02T22:11:49.180 回答