C++将字符放入C样式字符串中

C++; Putting characters into a C-Style string

本文关键字:样式 字符串 字符 C++      更新时间:2023-10-16

我一直在读一本自学书(http://www.amazon.com/gp/product/0321992784)我在第17章做练习。其中一个我解决了,但我不满意,希望得到一些帮助。提前谢谢。

练习:编写一个程序,将cin中的字符读取到您在免费存储中分配的数组中。阅读单个字符,直到输入感叹号(!)。不要使用std::string。不要担心记忆力耗尽。

我做了什么:

char* append(const char* str, char ch); // Add a character to the string and return a duplicate
char* loadCstr(); // Read characters from cin into an array of characters
int main()
{
    char* str{ loadCstr() };
    std::cout << str << 'n';
    return 0;
}

我做了两个函数,一个是创建一个比旧字符串大1的新字符串,并在末尾添加一个字符。

char* append(const char* str, char ch)
/*
    Create a new string with a size 1 greater than the old
    insert old string into new
    add character into new string
*/
{
    char* newstr{ nullptr };
    int i{ 0 };
    if (str)
        newstr = new char [ sizeof(str) + 2 ];
    else
        newstr = new char [ 2 ];
    if(str)
        while (str [ i ] != '')
            newstr [ i ] = str [ i++ ]; // Put character into new string, then increment the index
    newstr [ i++ ] = ch; // Add character and increment the index
    newstr [ i ] = ''; // Trailing 0
    return newstr;
}

这是使用我创建的append函数进行练习的函数,它很有效,但据我所知,每次调用append时,都会出现内存泄漏,因为我创建了一个新的字符数组,但没有删除旧的。

char* loadCstr()
/*
    get a character from cin, append it to str until !
*/
{
    char* str{ nullptr };
    for (char ch; std::cin >> ch && ch != '!';)
        str = append(str, ch);
    return str;
}

我尝试添加另一个指针来保存旧数组,并在创建新数组后将其删除,但在这个循环中调用了大约6次之后,我得到了一个运行时错误,我认为这告诉我正在删除一些不应该删除的内容?这就是我感到困惑的地方。

这是一个不能超过6个字符的旧版本:

char* loadCstr()
/*
    get a character from cin, append it to str until !
*/
{
    char* str{ nullptr };
    for (char ch; std::cin >> ch && ch != '!';) {
        char* temp{ append(str, ch) };
        if (str)
            delete str;
        str = temp;
    }
    return str;
}

所以我想知道如何修复这个函数,这样就不会出现内存泄漏。再次感谢。(另外请注意,我知道这些函数已经存在,并且使用std::string为我处理所有免费存储的东西,我只想了解它,这是一个学习练习。)

您必须使用标准的C函数std::strlen而不是sizeof运算符,因为在您的函数中,sizeof运算符返回指针的大小而不是字符串的长度。

此外,您还需要删除已分配的数组。

的功能如下

char* append(const char* str, char ch)
/*
    Create a new string with a size 1 greater than the old
    insert old string into new
    add character into new string
*/
{
    size_t n = 0;
    if ( str ) n = std::strlen( str );
    char *newstr = new char[ n + 2 ];
    for ( size_t i = 0; i < n; i++ ) newstr[i] = str[i];
    delete [] str;
    newstr[n] = ch;
    newstr[n+1] = '';
    return newstr;
}

在函数loadCstr中,它可以像一样调用

str = append( str, ch );

此外,您可以使用标准算法std::copy 来代替复制字符串的循环

学习内存管理或字符串操作如何在内部工作是重点吗?

对于第二个(学习字符串操作),您应该使用std::unique_ptr<char[]>,它将在指针失效时自动释放附加的数组。您仍然需要计算字符串长度、在字符串之间复制、追加——所有您现在正在做的事情。但是std::unique_ptr<char[]>将处理解除分配。

对于第一种情况,您最好编写一个RAII类(std::unique_ptr<T>的自定义版本)并学习如何在析构函数中释放内存,而不是在代码中散布delete []语句。到处写delete []实际上是一个坏习惯,学习它会让你的C++编程能力倒退。