2015-01-17 55 views
0

我一直在试图编写一个简短的程序,允许用户添加条目到“数据库”,列出他们已经放入的条目,并且能够清除所有条目而无需结束该程序。下面是我得到了创建和清除结构数组

#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; 
} 

现在,这里的交易:将以下代码编译成功,但是当我在“添加”命令类型,程序崩溃(成就解锁,没想到有可能获得用这么短的代码)。最重要的是该数组由多种类型的结构组成,并且“清除”命令清除了数组中的所有条目。

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

回答

0

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

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. 你有内存泄漏。你永远不会拨打delete []什么ptrarr[0] - ptrarr[9]指向。您必须使用:

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

    请记住,每个分配都必须具有相应的释放。否则,你正在泄漏记忆。

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

您需要重新分配内存和复位counter0当用户选择“清除”。

我的建议

你不两级指针。你只需要像:

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

真的很有帮助=)现在我知道究竟是什么导致代码崩溃。此外,从数组中删除每个条目的好处。我的直觉告诉我,这是我应该做的,但我不知道如何。我现在所做的是,该选项清除条目,而不是数组作为整体,重置计数器,然后再次创建数组,使用与主开头相同的代码 – Quit

0

数组索引从0开始。

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

2

全部替换ptrarr[counter][1]ptrarr[counter][0]解决了这个问题。

进一步建议:

此代码有冗余:

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

将其替换为:

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

那么你不需要额外的[0]每个ptrarr的末尾[counter]

二,功能使你的代码更易读:

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;} 

在这里您应该重置计数器。此外,如果你认为我的观点()这部分是好的。否则,如果将newfor循环一起使用,恐怕您需要使用delete以及for循环。仅仅删除数组树的根就会带来内存泄漏!

此外,如果您通过删除清除了列表,那么您是否需要将数据存储在列表中?在链表中使用删除是一个好主意,但它不适用于此。只需重新设置计数器即可完成工作,并且不再显示列表中的ID。列表中的for只计数到计数器。

如果您退出该程序,是不是释放内存?

我说

delete [] ptrarr; 

有利于处于退出。

+0

嗨,非常感谢这里的帮助。说到计数器重置,我意识到了这一点,不知道为什么它没有在这里引用代码。但我想清楚重置内存主要用于培训目的,这个代码的第一个版本只是重置柜台,我觉得作弊=) – Quit

+0

这不是作弊。因为数组总是占用10个对象的内存,无论是否使用它们。该内存分配允许您稍后添加对象。如果你释放内存,你将无法再添加任何对象,除非你再次分配10个块!所以不用担心只能重新设置。这是正确的工作。 – Arashium

0

试试这个:

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; 
     } 
    } 

结论

  • 正如你初始化counter 0,你应该有使用0索引来计算第一个因素;
  • 上市同样如此。
  • 数组基于0索引。