创建和清除结构数组

Creating and clearing an array of structures

本文关键字:数组 结构 清除 创建      更新时间:2023-10-16

我一直在尝试编写一个简短的程序,允许用户将条目添加到"数据库"中,列出他们输入的条目,以及清除所有条目而不结束程序的能力。这是我得到的

#include <cstdlib>
#include <iostream>
#include <string>
using namespace std;
struct BIRTH
    {int month; int year;};
struct ID 
    {string name; bool vip; float score; 
        struct BIRTH date;} ;
int main(int argc, char** argv) {
    ID **ptrarr;
    ptrarr = new ID * [10];
    for (int r=0; r<10; r++)
        {ptrarr[r] = new ID[1] ;}

    int counter = 0;
    while(counter<100){
    cout << "Type add to create a new entry" << endl;
    cout << "Type list to see all entries" << endl;
    cout << "Type clear to delete all entries" << endl;
    cout << "Type exit to terminate" << endl;
    string command = "0";
    getline (cin,command);
    if(command=="add")
        {
        cout << "Enter name" << endl;
        getline (cin,ptrarr[counter][1].name);
        cout << "VIP? 1 for yes, 0 for no" << endl;
        cin >> ptrarr[counter][1].vip;
        cout << "Enter score" << endl;
        cin >> ptrarr[counter][1].score;
        cout << "Month of birth" << endl;
        cin >> ptrarr[counter][1].date.month;
        cout << "Year of birth" << endl;
        cin >> ptrarr[counter][1].date.year;
        counter++;
        }
    else if(command=="list")
        {
            for (int i=0; i<counter; i++)
            {int n=i+1;
            cout << n << " " 
                 << ptrarr[i][1].name << "  ";
                    if (ptrarr[i][1].vip)
                    {cout << "VIP   ";}
            cout << "Score: " << ptrarr[i][1].score << "      "
                 << "Born: " << ptrarr[i][1].date.month << "/" << ptrarr[i][1].date.year << endl;
                    }
    }
    else if(command=="clear")
    {delete[] ptrarr;
        cout << "Entries cleared" << endl;}
    else if(command=="exit")
        {return 0;}
    else 
        cout << "try again" << endl;
    }
return 0;
}
现在交易是这样的

:以下代码成功编译,但是当我输入"add"命令时,程序崩溃(成就解锁,认为用这么短的代码无法获得)。最重要的是数组由多类型结构组成,并且"clear"命令会清除数组中的所有条目。

注意:我知道有一千种更好的方法来编写这段代码,但我编写它是为了练习到目前为止我所介绍的有关C++的内容。所以除非代码运行绝对必要,否则请不要引入任何新的噱头=)

将所有ptrarr[counter][1]替换为 ptrarr[counter][0] 可以解决问题。

进一步建议:

I. 此代码具有冗余:

ID **ptrarr;
ptrarr = new ID * [10];
for (int r=0; r<10; r++)
{ptrarr[r] = new ID[1] ;}

将其替换为:

ID *ptrarr;
ptrarr = new ID [10];

那么你不需要在每个 ptrarr[计数器] 的末尾额外 [0]

II. 函数使您的代码更具可读性:

if(command=="add")
    add();
else if(command=="list")
    list();
else if(command=="clear")
    clear();
else if(command=="exit")
    return 0;
else 
    cout << "try again" << endl;

然后在较小的领域做出决策(大型程序的良好做法)。

III. 您的代码中还有一个错误:

else if(command=="clear")
{delete[] ptrarr;
    cout << "Entries cleared" << endl;}

在这里,您应该重置计数器。另外,如果你考虑我的观点(I),这部分很好。否则,如果你用newfor循环,恐怕也需要用for循环delete。仅仅删除数组树的根就会带来内存泄漏!

另外,如果您通过删除清除列表,您是否不再需要在列表中存储数据?在链表中使用删除是一个好主意,但在这里不适用。只需重置计数器即可完成工作,并且它不再在列表中显示 ID。列表中的for仅计入计数器。

如果退出程序,不释放内存吗?

我说

delete [] ptrarr;

适合在出口处。

您正在创建一个指针数组,每个指针都指向一个元素:

  ptrarr[r] = new ID[1] ;

可以与ptrarr[r]一起使用的最大索引是 0 。由于您使用的是 ptrarr[counter][1] ,因此您正在访问越界的内存。这会导致未定义的行为。崩溃就是这样一种未定义的行为。

您可能想要修复代码的其他问题。

更多越界内存访问

您正在使用:

int counter = 0;
while(counter<100){
...
getline (cin,ptrarr[counter][1].name);

如果counter > 10,这将再次导致未定义的行为,因为您只为ptrarr分配了10指针。

删除内容

您正在使用:

  else if(command=="clear")
  {
     delete[] ptrarr;
     cout << "Entries cleared" << endl;
  }

这有几个问题:

  1. 您有内存泄漏。你从不就ptrarr[0] - ptrarr[9]指向的内容打电话给delete []。您必须使用:

    else if(command=="clear")
    {
       for ( int i = 0; i < 10; ++i )
       {
          delete [] ptrarr[i];
       }
       delete[] ptrarr;
       cout << "Entries cleared" << endl;
    }
    

    请记住,每个分配都必须有相应的释放。否则,您将泄漏内存。

  2. 一旦你调用delete [] ptrarr;,它就指向悬空的记忆。我没有看到任何代码在您继续使用它时重新分配内存ptrarr

您需要重新分配内存并将counter重置为0当用户选择"清除"时。

我的建议

您没有两级指针。你只需要这样的东西:

int const MAX_ITEMS = 100;
ID* IDarr  = new ID[MAX_ITEMS];

代替ptrarr[counter][1],使用 IDarr[counter]

while 语句的表达式中使用 MAX_ITEMS 而不是幻数100

int counter = 0;
while(counter<MAX_ITEMS){

处理"清除"时,不需要释放或分配内存。只需重置counter.

  else if(command=="clear")
  {
     counter = 0;
     cout << "Entries cleared" << endl;
  }

确保在从main返回之前释放内存。

以下是包含更改的完整main函数:

int main(int argc, char** argv) {
   const int MAX_ITEMS = 100;
   ID* IDarr = new ID[MAX_ITEMS];
   int counter = 0;
   while(counter < MAX_ITEMS){
      cout << "Type add to create a new entry" << endl;
      cout << "Type list to see all entries" << endl;
      cout << "Type clear to delete all entries" << endl;
      cout << "Type exit to terminate" << endl;
      string command = "0";
      getline (cin,command);
      if(command=="add")
      {
         cout << "Enter name" << endl;
         getline (cin, IDarr[counter].name);
         cout << "VIP? 1 for yes, 0 for no" << endl;
         cin >>  IDarr[counter].vip;
         cout << "Enter score" << endl;
         cin >>  IDarr[counter].score;
         cout << "Month of birth" << endl;
         cin >>  IDarr[counter].date.month;
         cout << "Year of birth" << endl;
         cin >>  IDarr[counter].date.year;
         counter++;
      }
      else if(command=="list")
      {
         for (int i=0; i<counter; i++)
         {
            int n=i+1;
            cout << n << " " << IDarr[i].name << "  ";
            if (IDarr[i].vip)
            {
               cout << "VIP   ";
            }
            cout 
               << "Score: " << IDarr[i].score << "      "
               << "Born: " << IDarr[i].date.month << "/" << IDarr[i].date.year << endl;
         }
      }
      else if(command=="clear")
      {
         counter = 0;
         cout << "Entries cleared" << endl;
      }
      else if(command=="exit")
      {
         // Don't use return 0;
         // Just break out of the while loop so that memory
         // can be deallocated at the end of this function.
         break;
      }
      else 
         cout << "try again" << endl;
   }
   delete [] IDarr;
   return 0;
}

数组索引从 0 开始。

ptrarr[counter][1]是指ptrarr[counter]的第二个元素。 ptrarr[counter]指向一个元素的数组。

试试这个:

if(command=="add") {
        cout << "Enter name" << endl;
        getline (cin,ptrarr[counter][0].name);
        cout << "VIP? 1 for yes, 0 for no" << endl;
        cin >> ptrarr[counter][0].vip;
        cout << "Enter score" << endl;
        cin >> ptrarr[counter][0].score;
        cout << "Month of birth" << endl;
        cin >> ptrarr[counter][0].date.month;
        cout << "Year of birth" << endl;
        cin >> ptrarr[counter][0].date.year;
        counter++;
    }
    else if(command=="list") {
        for (int i=0; i<counter; i++){
            int n=i+1;
            cout << n << " "<< ptrarr[i][0].name << "  ";
            if (ptrarr[i][0].vip){
                cout << "VIP   ";
            }
            cout << "Score: " << ptrarr[i][0].score << "      "
             << "Born: " << ptrarr[i][0].date.month << "/" << ptrarr[i][0].date.year << endl;
        }
    }

结语

  • 就像你用 0 初始化counter一样,你应该使用 0 索引来访问第一个元素;
  • 上市时也是如此。
  • 数组基于 0 索引。