类数组内部的C++深拷贝const char *?

Posted

技术标签:

【中文标题】类数组内部的C++深拷贝const char *?【英文标题】:C++ deep copy const char * inside of class array? 【发布时间】:2020-04-06 18:18:11 【问题描述】:

所以我在上课时遇到问题。在这个类中,我应该有一些数据数组。我对分配和创建新数据没有问题,例如 x2.NewAccount("123456" , 1000);这很好用,问题是当我尝试使用针对某个变量的字符串创建数据时。我对深度复制有所了解,但我不知道如何在我的情况下编程 = 运算符 + 我认为 strcpy 但这也不起作用。

PS:它是一个学校项目,所以请不要因为我没有使用标题和使用一堆我没有在代码中使用的包含而评判我。它由我的学校制作,我不允许更改它们+添加它们(我知道使用 c++ 中的字符串会容易得多。)。 谢谢你的帮助。

#ifndef __PROGTEST__
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cassert>
#include <cctype>
#include <cmath>
#include <iostream>
#include <iomanip>
#include <sstream>
using namespace std;
#endif /* __PROGTEST__ */

struct data_history
    int money = 0;
    bool Income;
    const char * UnStr;
    const char * to_from;
;

struct client
    const char * accID;
    int Balance;
    int def_bal;
    data_history * history;
    int in_index = 0;
    int in_cap = 10;

    friend ostream &operator << (ostream &output , client p)
        output << p.accID << ":" << endl << "   " << p.def_bal << endl;
        for (int i = 0 ; i < p.in_index ; i++)
            if (p.history[i].Income == false)
                output << " - " << abs(p.history[i].money) << ", to: " << p.history[i].to_from << ", sign: " << p.history[i].UnStr << endl;
            else
                output << " + " <<abs(p.history[i].money) << ", from: " << p.history[i].to_from << ", sign: " << p.history[i].UnStr << endl;
        
        output << " = " << p.Balance << endl;
        return output;
    
;

class CBank

public:
    int cap = 10;
    int index = 0;
    client * database;
    ~CBank()
        for (int i = 0 ; i < index ; i++)
                delete[] database[i].history;
        delete[]database;
    
    CBank()
        database = new client[cap];
    
    bool NewAccount ( const char * accID, int initialBalance )
        for(int i = 0 ; i < index ; i ++)
            if (accID == database[i].accID) 
                return false;
            
        //strcpy (database[index].accID , accID );  // Im getting errors while compileing (cuz I was using const char * for database.accID when i chenged it i got program crash. 
        database[index].accID = accID;
        database[index].Balance = initialBalance;
        database[index].def_bal = initialBalance;
        database[index].in_cap = 10;
        database[index].history = new data_history[database[index].in_cap];
        index ++;
        return true;
    
    client Account (const char * accID )
        const char * input  =accID;
        for (int i = 0 ; i < index ; i++)
            if (database[i].accID == input )
                return database[i];
        
        throw "error";
    
    void print ()
        for (int i = 0 ; i  < index ; i ++) 
            cout << endl;
            cout << i << " = "<< " ID = " << database[i].accID << " | Balance = " << database[i].Balance << endl;
            cout << "===Account history ===\n\n";
            for (int y = 0 ; y < database[i].in_index; y++) 
                cout << "Was it for him? : " << boolalpha << database[i].history[y].Income
                    << "\nHow much : " << database[i].history[y].money << "\nUnique string : "
                    << database[i].history[y].UnStr << "\nfrom/to: " << database[i].history[y].to_from << endl << endl;
            
        
    

private:

;


#ifndef __PROGTEST__
int main ( void )

    char accCpy[100], debCpy[100], credCpy[100], signCpy[100];
    CBank x2;
    strncpy ( accCpy, "123456", sizeof ( accCpy ) );
    assert ( x2 . NewAccount ( accCpy, 1000 ) );
    x2 . print();
    cout << "\n\n\n\n";
    strncpy ( accCpy, "987654", sizeof ( accCpy ) );
    assert ( x2 . NewAccount ( "987654", -500 ) );
    x2 . print();

#endif /* __PROGTEST__ */

【问题讨论】:

与您的问题无关,但如果您打算学习 c++ 并且不仅想解决作业,那么我强烈建议您从一本好书上学习它 - 至少关于给定的风格代码 - 通过后忘记课程中教过的内容。 client::accID 只是一个指针。您永远不会将其初始化为指向任何地方。您需要一个为您分配内存的client 类的构造函数accID(以及复制复制构造函数、赋值运算符和解构函数),或者您需要将其更改为char accID[10](或20 或30 或更多您需要的空间)。 data_history 也是如此。 【参考方案1】:

当使用database[index].accID = accID; 时,你只是在做一个浅拷贝(并且依赖于调用者来保持这个内存有效,因为指针可能被访问)。

您已正确确定需要执行深拷贝,但 client::accID 只是一个指针,但您可能无法将其复制到其中,直到您将其初始化为指向某个内存。

这样做的一种方法是动态分配和管理client::accID,类似于动态分配和管理client::history

不要使用strcpy (database[index].accID , accID );database[index].accID = accID;,试试:

size_t bufsize = strlen(accID) + 1;
char *buf = new char[bufsize];
memcpy(buf, accID, bufsize);
database[index].accID = buf;

并在析构函数中添加:

delete[] database[i].accID

正如其他人所指出的,这种 C++ 编程风格非常容易出错,并且社区并不看好。使用标准库类可以轻松避免这种手动内存管理。即使在进行了上述更改后,如果您开始复制 CBank 对象,您的程序也会遇到未定义的行为。

即使您的作业不需要这样做,您也应该考虑尝试将其重写为练习:

std::string 而不是 accID; 的 C 字符串 std::vector 而不是 data_history 数组

也仅供参考:

if (database[i].accID == input )

不会用 c-strings 做预期的事情......

【讨论】:

以上是关于类数组内部的C++深拷贝const char *?的主要内容,如果未能解决你的问题,请参考以下文章

C++的深拷贝与浅拷贝

c++关于派生类的拷贝构造函数

C++类的浅拷贝深拷贝以及写时拷贝问题

C语言面试题C++中String类引用计数器的浅拷贝写法与深拷贝写法

C++ 类的深拷贝和浅拷贝完美解决

C++入门拷贝构造函数详解