第一次尝试使用new动态创建struct数组,程序无误挂起
First attempt at using new to dynamically create struct array, program hangs without error
我正在努力研究如何为赋值创建动态数组,但无论我做什么,我的程序在输入 3 个或更多条目后仍然挂起。
我没有收到任何错误,必须手动关闭控制台 window,但没有任何指示,我不确定我到底做错了什么。
如果我在控制台中创建 3 个以上的结构,无论我如何更改,我的程序在输入 'n' 以结束新事件的创建后都会挂起。
int readEvents(Event* ev_ptr[], int size)
{
char answer = 'y', slash;
int i = 0;
cout << "\nCreate an event [y/n]? ";
cin >> answer;
cin.ignore();
while (answer == 'y' || answer == 'Y')
{
ev_ptr[i] = new Event;
cout << "\nEnter description: ";
cin.getline(ev_ptr[i]->desc, 80, '\n');
cout << "\nEnter date: ";
cin >> ev_ptr[i]->date.month >> slash >> ev_ptr[i]->date.day >> slash >> ev_ptr[i]->date.year;
cin.ignore();
cout << "\nEnter time: ";
cin >> ev_ptr[i]->time.hour >> slash >> ev_ptr[i]->time.minute;
cin.ignore();
i++;
cout << "\nCreate an event [y/n]? ";
cin >> answer;
cin.ignore();
}
return i;
}
如有任何帮助,我们将不胜感激
编辑:
这是我的主要函数,其中声明了 ev_ptr 数组大小:
int main()
{
Event* event_pointers[100];
int count = readEvents(event_pointers, 100), userMonth;
char userString[80];
cout << "\nEnter a search string: ";
cin.getline(userString, 80, '\n');
cin.ignore();
linsearch(event_pointers, count, userString);
cout << "\nEnter a month to list Events for: ";
cin >> userMonth;
cin.ignore();
binsearch(event_pointers, count, userMonth);
for (int j = 0; j < count; j++) //Cleanup loop
delete event_pointers[j];
cout << "\nPress any key to continue...";
(void)_getch();
return 0;
}
你为什么不使用 std::vector
和 std::unique
?
#include <vector>
#include <memory>
class Event { }
int main()
{
std::vector<std::unique_ptr<Event>> events;
readEvents(events);
}
int readEvents(std::vector<std::unique_ptr<Event>>& events, int size)
{
...
while (answer == 'y' || answer == 'Y')
{
ev_ptr[i] = std::make_unique<Event>();
...
}
}
使用new
和delete
有点老套了。作为旧的做事方式,有数十年的代码使用它。正如我在上面的评论中总结的那样,您当前声明 100
pointers-to-type Event
,然后使用 new
为每个人分配存储空间struct Event
实例。通过使用固定的指针数组——您将无法再拥有最初声明指针的事件。这是一种非常不灵活的方式。
相反,只需声明一个内存块来保存一些初始数量的事件,并为分配的元素数和填充的元素数保留一对计数器。当 filled == allocated
时,只需分配另一块内存(比如容纳两倍于当前的元素),并将数据从原始块复制到新块,删除原始块,并根据需要重复多次。 (您基本上是使用 new/delete
.
执行手动 realloc()
下面是一个简短的例子。在示例中,我使用了一个简化的 Event
结构。 (您可以进一步将日期和时间拆分为 yyyy-mm-dd 和 H:M:S)。该示例首先分配 Event
的 2 个实例,然后继续读取尽可能多的用户输入,更新分配大小并根据需要将原始内容复制到新内容。初始设置和重新分配代码如下:
#include <iostream>
#include <cstring>
#define MAXDESC 80 /* max description length */
#define MAXDTTM 32 /* max date/time lengths */
#define EVSIZE 2 /* initial number of Event elements allocated */
struct Event {
char desc[MAXDESC];
char date[MAXDTTM];
char time[MAXDTTM];
};
/** reallocate e to twice 'size' elements */
Event *reallocEVx2 (Event *e, size_t *size)
{
Event *tmp = new Event[*size * 2]; /* allocate new block 2x in size */
std::memcpy (tmp, e, *size * sizeof *e); /* copy old to new */
delete[] e; /* delete old */
*size *= 2; /* update allocated size */
return tmp; /* return pointer to new block */
}
readEvents()
函数将 address-of 作为参数,因为起始地址会在重新分配时发生变化。因此,您不只是传递一个指针,而是传递 address-of 来自调用者的指针,这样您就可以更新该地址以指向 readEvents()
中新重新分配的内存块.该更改将在调用者中看到,因为您正在对原始指针地址进行操作。如果您没有将 address-of 传递给原始指针,则必须 return 一个指向新分配块的指针并将其分配给调用者的指针.
readEvents()
的实施取消了在 std::cin
上混合 getline
和 >>
。而是简单地使用 getline
并从每一行创建一个 stringstream
以在字符串流上使用 >>
进一步将数据分离为单独的值。这消除了无效输入未能被读取并在输入流中保持未读状态的可能性,只是等待在您的下一个输入中咬住您。
对 readEvents()
的轻微重写只是循环获取输入,直到用户在提示时键入 'y'
以外的内容:
/** read events from user reallocating as required
* (note: must pass address-of-pointer, not just pointer)
*/
size_t readEvents (Event **e, size_t *nelem, size_t *size)
{
char buf[MAXDESC];
for (;;) { /* loop continually until something other than 'y' entered */
std::cout << "\nCreate event (y/n)? ";
if (!std::cin.getline (buf, sizeof buf) || *buf != 'y')
break;
if (*nelem == *size) /* check if realloc needed */
*e = reallocEVx2 (*e, size);
/* get input */
std::cout << " Enter description: ";
if (!std::cin.getline ((*e)[*nelem].desc, MAXDESC))
break;
std::cout << " Enter date: ";
if (!std::cin.getline ((*e)[*nelem].date, MAXDTTM))
break;
/* create stringstream to parse date into yyyy-mm-dd here */
std::cout << " Enter time: ";
if (!std::cin.getline ((*e)[*nelem].time, MAXDTTM))
break;
/* create stringstream to parse time into H:M:S here */
(*nelem)++; /* update no. of elements filled */
}
return *nelem; /* return no. of elements filled */
}
在 main()
中,您只需声明计数器来跟踪分配的元素数量(下面的 size
)和使用的元素数量(下面的 nelem
)并为您的Event
的初始两个实例并开始读取数据。代码通过输出内存统计信息(分配的 elements/used 元素)并输出每个存储的 Event
实例结束,例如
int main (void) {
size_t nelem = 0;
size_t size = EVSIZE;
Event *events = new Event[size]; /* allocate initial 'size' elements */
if (!readEvents (&events, &nelem, &size)) { /* read/fill events */
std::cerr << "error: no events read.\n";
return 1;
}
/* output memory useage (elements allocated/filled) */
std::cout << "\nelements allocated: " << size <<
"\nelements filled : " << nelem << "\n\n";
for (size_t i = 0; i < nelem; i++) /* output all events */
std::cout << events[i].desc << " " << events[i].date << " " <<
events[i].time << '\n';
delete[] events; /* free memory */
}
总而言之,你可以这样做:
#include <iostream>
#include <cstring>
#define MAXDESC 80 /* max description length */
#define MAXDTTM 32 /* max date/time lengths */
#define EVSIZE 2 /* initial number of Event elements allocated */
struct Event {
char desc[MAXDESC];
char date[MAXDTTM];
char time[MAXDTTM];
};
/** reallocate e to twice 'size' elements */
Event *reallocEVx2 (Event *e, size_t *size)
{
Event *tmp = new Event[*size * 2]; /* allocate new block 2x in size */
std::memcpy (tmp, e, *size * sizeof *e); /* copy old to new */
delete[] e; /* delete old */
*size *= 2; /* update allocated size */
return tmp; /* return pointer to new block */
}
/** read events from user reallocating as required
* (note: must pass address-of-pointer, not just pointer)
*/
size_t readEvents (Event **e, size_t *nelem, size_t *size)
{
char buf[MAXDESC];
for (;;) { /* loop continually until something other than 'y' entered */
std::cout << "\nCreate event (y/n)? ";
if (!std::cin.getline (buf, sizeof buf) || *buf != 'y')
break;
if (*nelem == *size) /* check if realloc needed */
*e = reallocEVx2 (*e, size);
/* get input */
std::cout << " Enter description: ";
if (!std::cin.getline ((*e)[*nelem].desc, MAXDESC))
break;
std::cout << " Enter date: ";
if (!std::cin.getline ((*e)[*nelem].date, MAXDTTM))
break;
/* create stringstream to parse date into yyyy-mm-dd here */
std::cout << " Enter time: ";
if (!std::cin.getline ((*e)[*nelem].time, MAXDTTM))
break;
/* create stringstream to parse time into H:M:S here */
(*nelem)++; /* update no. of elements filled */
}
return *nelem; /* return no. of elements filled */
}
int main (void) {
size_t nelem = 0;
size_t size = EVSIZE;
Event *events = new Event[size]; /* allocate initial 'size' elements */
if (!readEvents (&events, &nelem, &size)) { /* read/fill events */
std::cerr << "error: no events read.\n";
return 1;
}
/* output memory useage (elements allocated/filled) */
std::cout << "\nelements allocated: " << size <<
"\nelements filled : " << nelem << "\n\n";
for (size_t i = 0; i < nelem; i++) /* output all events */
std::cout << events[i].desc << " " << events[i].date << " " <<
events[i].time << '\n';
delete[] events; /* free memory */
}
例子Use/Output
$ ./bin/events_new-del
Create event (y/n)? y
Enter description: Event 1
Enter date: 11/29/19
Enter time: 12:30:31
Create event (y/n)? y
Enter description: Event 2
Enter date: 11/29/19
Enter time: 12:30:41
Create event (y/n)? y
Enter description: Event 3
Enter date: 11/29/19
Enter time: 12:30:51
Create event (y/n)? y
Enter description: Event 4
Enter date: 11/29/19
Enter time: 12:31:01
Create event (y/n)? y
Enter description: Event 5
Enter date: 11/29/19
Enter time: 12:31:11
Create event (y/n)? n
elements allocated: 8
elements filled : 5
Event 1 11/29/19 12:30:31
Event 2 11/29/19 12:30:41
Event 3 11/29/19 12:30:51
Event 4 11/29/19 12:31:01
Event 5 11/29/19 12:31:11
检查一下,如果您对这种方法有进一步的疑问,请告诉我。
我正在努力研究如何为赋值创建动态数组,但无论我做什么,我的程序在输入 3 个或更多条目后仍然挂起。
我没有收到任何错误,必须手动关闭控制台 window,但没有任何指示,我不确定我到底做错了什么。
如果我在控制台中创建 3 个以上的结构,无论我如何更改,我的程序在输入 'n' 以结束新事件的创建后都会挂起。
int readEvents(Event* ev_ptr[], int size)
{
char answer = 'y', slash;
int i = 0;
cout << "\nCreate an event [y/n]? ";
cin >> answer;
cin.ignore();
while (answer == 'y' || answer == 'Y')
{
ev_ptr[i] = new Event;
cout << "\nEnter description: ";
cin.getline(ev_ptr[i]->desc, 80, '\n');
cout << "\nEnter date: ";
cin >> ev_ptr[i]->date.month >> slash >> ev_ptr[i]->date.day >> slash >> ev_ptr[i]->date.year;
cin.ignore();
cout << "\nEnter time: ";
cin >> ev_ptr[i]->time.hour >> slash >> ev_ptr[i]->time.minute;
cin.ignore();
i++;
cout << "\nCreate an event [y/n]? ";
cin >> answer;
cin.ignore();
}
return i;
}
如有任何帮助,我们将不胜感激
编辑:
这是我的主要函数,其中声明了 ev_ptr 数组大小:
int main()
{
Event* event_pointers[100];
int count = readEvents(event_pointers, 100), userMonth;
char userString[80];
cout << "\nEnter a search string: ";
cin.getline(userString, 80, '\n');
cin.ignore();
linsearch(event_pointers, count, userString);
cout << "\nEnter a month to list Events for: ";
cin >> userMonth;
cin.ignore();
binsearch(event_pointers, count, userMonth);
for (int j = 0; j < count; j++) //Cleanup loop
delete event_pointers[j];
cout << "\nPress any key to continue...";
(void)_getch();
return 0;
}
你为什么不使用 std::vector
和 std::unique
?
#include <vector>
#include <memory>
class Event { }
int main()
{
std::vector<std::unique_ptr<Event>> events;
readEvents(events);
}
int readEvents(std::vector<std::unique_ptr<Event>>& events, int size)
{
...
while (answer == 'y' || answer == 'Y')
{
ev_ptr[i] = std::make_unique<Event>();
...
}
}
使用new
和delete
有点老套了。作为旧的做事方式,有数十年的代码使用它。正如我在上面的评论中总结的那样,您当前声明 100
pointers-to-type Event
,然后使用 new
为每个人分配存储空间struct Event
实例。通过使用固定的指针数组——您将无法再拥有最初声明指针的事件。这是一种非常不灵活的方式。
相反,只需声明一个内存块来保存一些初始数量的事件,并为分配的元素数和填充的元素数保留一对计数器。当 filled == allocated
时,只需分配另一块内存(比如容纳两倍于当前的元素),并将数据从原始块复制到新块,删除原始块,并根据需要重复多次。 (您基本上是使用 new/delete
.
realloc()
下面是一个简短的例子。在示例中,我使用了一个简化的 Event
结构。 (您可以进一步将日期和时间拆分为 yyyy-mm-dd 和 H:M:S)。该示例首先分配 Event
的 2 个实例,然后继续读取尽可能多的用户输入,更新分配大小并根据需要将原始内容复制到新内容。初始设置和重新分配代码如下:
#include <iostream>
#include <cstring>
#define MAXDESC 80 /* max description length */
#define MAXDTTM 32 /* max date/time lengths */
#define EVSIZE 2 /* initial number of Event elements allocated */
struct Event {
char desc[MAXDESC];
char date[MAXDTTM];
char time[MAXDTTM];
};
/** reallocate e to twice 'size' elements */
Event *reallocEVx2 (Event *e, size_t *size)
{
Event *tmp = new Event[*size * 2]; /* allocate new block 2x in size */
std::memcpy (tmp, e, *size * sizeof *e); /* copy old to new */
delete[] e; /* delete old */
*size *= 2; /* update allocated size */
return tmp; /* return pointer to new block */
}
readEvents()
函数将 address-of 作为参数,因为起始地址会在重新分配时发生变化。因此,您不只是传递一个指针,而是传递 address-of 来自调用者的指针,这样您就可以更新该地址以指向 readEvents()
中新重新分配的内存块.该更改将在调用者中看到,因为您正在对原始指针地址进行操作。如果您没有将 address-of 传递给原始指针,则必须 return 一个指向新分配块的指针并将其分配给调用者的指针.
readEvents()
的实施取消了在 std::cin
上混合 getline
和 >>
。而是简单地使用 getline
并从每一行创建一个 stringstream
以在字符串流上使用 >>
进一步将数据分离为单独的值。这消除了无效输入未能被读取并在输入流中保持未读状态的可能性,只是等待在您的下一个输入中咬住您。
对 readEvents()
的轻微重写只是循环获取输入,直到用户在提示时键入 'y'
以外的内容:
/** read events from user reallocating as required
* (note: must pass address-of-pointer, not just pointer)
*/
size_t readEvents (Event **e, size_t *nelem, size_t *size)
{
char buf[MAXDESC];
for (;;) { /* loop continually until something other than 'y' entered */
std::cout << "\nCreate event (y/n)? ";
if (!std::cin.getline (buf, sizeof buf) || *buf != 'y')
break;
if (*nelem == *size) /* check if realloc needed */
*e = reallocEVx2 (*e, size);
/* get input */
std::cout << " Enter description: ";
if (!std::cin.getline ((*e)[*nelem].desc, MAXDESC))
break;
std::cout << " Enter date: ";
if (!std::cin.getline ((*e)[*nelem].date, MAXDTTM))
break;
/* create stringstream to parse date into yyyy-mm-dd here */
std::cout << " Enter time: ";
if (!std::cin.getline ((*e)[*nelem].time, MAXDTTM))
break;
/* create stringstream to parse time into H:M:S here */
(*nelem)++; /* update no. of elements filled */
}
return *nelem; /* return no. of elements filled */
}
在 main()
中,您只需声明计数器来跟踪分配的元素数量(下面的 size
)和使用的元素数量(下面的 nelem
)并为您的Event
的初始两个实例并开始读取数据。代码通过输出内存统计信息(分配的 elements/used 元素)并输出每个存储的 Event
实例结束,例如
int main (void) {
size_t nelem = 0;
size_t size = EVSIZE;
Event *events = new Event[size]; /* allocate initial 'size' elements */
if (!readEvents (&events, &nelem, &size)) { /* read/fill events */
std::cerr << "error: no events read.\n";
return 1;
}
/* output memory useage (elements allocated/filled) */
std::cout << "\nelements allocated: " << size <<
"\nelements filled : " << nelem << "\n\n";
for (size_t i = 0; i < nelem; i++) /* output all events */
std::cout << events[i].desc << " " << events[i].date << " " <<
events[i].time << '\n';
delete[] events; /* free memory */
}
总而言之,你可以这样做:
#include <iostream>
#include <cstring>
#define MAXDESC 80 /* max description length */
#define MAXDTTM 32 /* max date/time lengths */
#define EVSIZE 2 /* initial number of Event elements allocated */
struct Event {
char desc[MAXDESC];
char date[MAXDTTM];
char time[MAXDTTM];
};
/** reallocate e to twice 'size' elements */
Event *reallocEVx2 (Event *e, size_t *size)
{
Event *tmp = new Event[*size * 2]; /* allocate new block 2x in size */
std::memcpy (tmp, e, *size * sizeof *e); /* copy old to new */
delete[] e; /* delete old */
*size *= 2; /* update allocated size */
return tmp; /* return pointer to new block */
}
/** read events from user reallocating as required
* (note: must pass address-of-pointer, not just pointer)
*/
size_t readEvents (Event **e, size_t *nelem, size_t *size)
{
char buf[MAXDESC];
for (;;) { /* loop continually until something other than 'y' entered */
std::cout << "\nCreate event (y/n)? ";
if (!std::cin.getline (buf, sizeof buf) || *buf != 'y')
break;
if (*nelem == *size) /* check if realloc needed */
*e = reallocEVx2 (*e, size);
/* get input */
std::cout << " Enter description: ";
if (!std::cin.getline ((*e)[*nelem].desc, MAXDESC))
break;
std::cout << " Enter date: ";
if (!std::cin.getline ((*e)[*nelem].date, MAXDTTM))
break;
/* create stringstream to parse date into yyyy-mm-dd here */
std::cout << " Enter time: ";
if (!std::cin.getline ((*e)[*nelem].time, MAXDTTM))
break;
/* create stringstream to parse time into H:M:S here */
(*nelem)++; /* update no. of elements filled */
}
return *nelem; /* return no. of elements filled */
}
int main (void) {
size_t nelem = 0;
size_t size = EVSIZE;
Event *events = new Event[size]; /* allocate initial 'size' elements */
if (!readEvents (&events, &nelem, &size)) { /* read/fill events */
std::cerr << "error: no events read.\n";
return 1;
}
/* output memory useage (elements allocated/filled) */
std::cout << "\nelements allocated: " << size <<
"\nelements filled : " << nelem << "\n\n";
for (size_t i = 0; i < nelem; i++) /* output all events */
std::cout << events[i].desc << " " << events[i].date << " " <<
events[i].time << '\n';
delete[] events; /* free memory */
}
例子Use/Output
$ ./bin/events_new-del
Create event (y/n)? y
Enter description: Event 1
Enter date: 11/29/19
Enter time: 12:30:31
Create event (y/n)? y
Enter description: Event 2
Enter date: 11/29/19
Enter time: 12:30:41
Create event (y/n)? y
Enter description: Event 3
Enter date: 11/29/19
Enter time: 12:30:51
Create event (y/n)? y
Enter description: Event 4
Enter date: 11/29/19
Enter time: 12:31:01
Create event (y/n)? y
Enter description: Event 5
Enter date: 11/29/19
Enter time: 12:31:11
Create event (y/n)? n
elements allocated: 8
elements filled : 5
Event 1 11/29/19 12:30:31
Event 2 11/29/19 12:30:41
Event 3 11/29/19 12:30:51
Event 4 11/29/19 12:31:01
Event 5 11/29/19 12:31:11
检查一下,如果您对这种方法有进一步的疑问,请告诉我。