创建和清除结构数组
Creating and clearing an array of structures
我一直在尝试编写一个简短的程序,允许用户向 "database" 添加条目,列出他们输入的条目,并能够在不结束程序的情况下清除所有条目。这是我得到的
#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++ 的内容。所以除非绝对需要代码到运行,否则请不要引入任何新的噱头=)
数组索引从 0 开始。
ptrarr[counter][1]
指的是ptrarr[counter]
的第二个元素。 ptrarr[counter]
指向一个元素的数组。
将所有 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];
那么你不需要在每个 ptarrr[counter] 的末尾额外添加 [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),这部分很好。否则,如果您将 new
与 for
循环一起使用,恐怕您也需要将 delete
与 for
循环一起使用。仅仅删除数组树的根就会导致内存泄漏!
还有,如果你用delete清除了列表,是不是就不需要在列表中存储数据了?在链表中使用 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;
}
这有几个问题:
您有内存泄漏。你永远不会在 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;
}
请记住,每个分配都必须有一个相应的释放。否则,你正在泄漏内存。
一旦你调用delete [] ptrarr;
,它指向悬空内存。当您继续使用它时,我没有看到任何为 ptrarr
重新分配内存的代码。
当用户选择"clear"时,您需要重新分配内存并将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){
处理"clear"时,不需要释放或分配内存。只需重置 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;
}
试试这个:
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 索引的。
我一直在尝试编写一个简短的程序,允许用户向 "database" 添加条目,列出他们输入的条目,并能够在不结束程序的情况下清除所有条目。这是我得到的
#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++ 的内容。所以除非绝对需要代码到运行,否则请不要引入任何新的噱头=)
数组索引从 0 开始。
ptrarr[counter][1]
指的是ptrarr[counter]
的第二个元素。 ptrarr[counter]
指向一个元素的数组。
将所有 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];
那么你不需要在每个 ptarrr[counter] 的末尾额外添加 [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),这部分很好。否则,如果您将 new
与 for
循环一起使用,恐怕您也需要将 delete
与 for
循环一起使用。仅仅删除数组树的根就会导致内存泄漏!
还有,如果你用delete清除了列表,是不是就不需要在列表中存储数据了?在链表中使用 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;
}
这有几个问题:
您有内存泄漏。你永远不会在
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; }
请记住,每个分配都必须有一个相应的释放。否则,你正在泄漏内存。
一旦你调用
delete [] ptrarr;
,它指向悬空内存。当您继续使用它时,我没有看到任何为ptrarr
重新分配内存的代码。
当用户选择"clear"时,您需要重新分配内存并将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){
处理"clear"时,不需要释放或分配内存。只需重置 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;
}
试试这个:
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 索引的。