You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++自定义String类display方法中cout仅输出首字符后停止的问题排查

C++自定义String类display方法中cout仅输出首字符后停止的问题排查

嘿,我仔细看了你的代码,发现问题的核心是悬空指针导致的未定义行为,这也是C++新手很容易踩的坑!咱们一步步拆解问题:

问题根源:构造函数的致命错误

你的String构造函数里,a = &b[0];只是把指针直接指向了传入的char数组的首地址,完全没有自己分配内存去复制字符串内容。这会引发两个严重问题:

  • 当传入的是栈上的局部数组(比如main里的input1/input2,或者operator+里的temp),这些数组在所在函数执行完毕后就会被系统销毁,你的String对象里的a指针就变成了悬空指针——指向的内存已经不属于你的程序了,访问它的行为是完全不可预测的。
  • 比如你在operator+里创建的temp是栈上的局部数组,当operator+执行完返回时,temp的内存就被释放了,这时候返回的String对象的a指针指向的就是一块无效内存。当你调用display时,访问这块内存就会出现各种奇怪的现象,比如只输出首字符、乱码甚至程序崩溃。

你说在构造函数里用循环输出能正常显示,那是因为构造函数执行时,传入的char数组还在栈上(比如main里的input1还没被销毁),但operator+返回的String对象就没这么幸运了——它的a指向的temp已经被销毁了。

修正方案:修复内存管理问题

要解决这个问题,我们需要让String类真正拥有自己的内存,而不是依赖外部数组。

1. 重写构造函数,手动分配内存并复制内容

把原来的构造函数改成这样,根据传入字符串的实际长度分配内存,而不是固定101:

#include <cstring> // 需要用到strlen和strcpy

class String
{
public:
    char *a;
    int length;
    // 构造函数:接收const char*,避免修改原字符串
    String(const char* b)
    {
        length = strlen(b); // 获取字符串实际长度(不含'\0')
        a = new char[length + 1]; // 给'\0'预留位置
        strcpy(a, b); // 复制字符串内容到自己的内存
    }
    String operator+(const String &other);
    void display();
};

2. 添加析构函数,避免内存泄漏

因为我们用new分配了内存,必须在对象销毁时释放,否则会造成内存泄漏:

~String()
{
    delete[] a; // 释放数组内存,注意用delete[]而不是delete
}

3. 修正operator+函数,避免返回指向栈内存的对象

现在构造函数会自己复制内容,我们可以在operator+里先分配足够的内存,拼接两个字符串后再返回新的String对象:

#include <iostream>
#include "stringConcat.h"
#include <cstring>
using namespace std;

String String::operator+(const String &other)
{
    // 计算总长度:原字符串长度 + 另一个字符串长度 + 1(空格) + 1('\0')
    int totalLen = length + other.length + 2;
    char* temp = new char[totalLen];
    
    // 复制第一个字符串
    strcpy(temp, a);
    // 添加空格
    strcat(temp, " ");
    // 拼接第二个字符串
    strcat(temp, other.a);
    
    String result(temp);
    delete[] temp; // 构造函数已经复制了内容,这里释放临时内存
    return result;
}

void String::display()
{
    cout << a << endl; // 直接输出字符串即可,不用手动循环,'\0'会自动终止输出
}

4. 补充拷贝构造函数和赋值运算符重载(必加!)

C++默认的拷贝构造函数和赋值运算符是浅拷贝——只会复制指针,导致多个String对象指向同一块内存,当其中一个对象销毁时,会释放这块内存,其他对象的指针就变成悬空指针。所以必须实现深拷贝:

// 拷贝构造函数
String(const String& other)
{
    length = other.length;
    a = new char[length + 1];
    strcpy(a, other.a);
}

// 赋值运算符重载
String& operator=(const String& other)
{
    if (this == &other) return *this; // 防止自赋值
    
    delete[] a; // 先释放自己原有的内存
    length = other.length;
    a = new char[length + 1];
    strcpy(a, other.a);
    
    return *this;
}

为什么原来的display只输出首字符?

当operator+返回的String对象的a是悬空指针时,它指向的内存已经被系统重新分配或者覆盖了。可能第一个字符还没被覆盖,但后面的内容已经变成了'\0',所以display函数的循环遇到'\0'就停止了,看起来只输出了首字符——这其实是未定义行为的一种表现,换个环境可能会出现完全不同的结果。

备注:内容来源于stack exchange,提问作者Ham Lemon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 09:29:52