使用newanddelete在某种程度上是旧的做事方式。作为旧的做事方式,有数十年的代码使用它。正如我在上面的评论中总结的那样,您当前声明100 了 pointers-to-type Event,然后用于new为每个单独的struct Event实例分配存储空间。通过使用一个固定的指针数组——你被锁定在没有你最初声明指针的事件中。这是一种非常不灵活的方式。
相反,只需声明一块内存来保存一些初始事件数,并为分配的元素数和填充的元素数保留一对计数器。当 时filled == allocated,只需分配另一块内存(比如保存两倍于当前元素的元素),然后将数据从原始块复制到新块,删除原始块,并根据需要重复多次。(您基本上是在realloc()使用new/delete.
下面是一个简短的例子。在示例中,我使用了简化的Event结构。(您可以将日期和时间进一步拆分为yyyy-mm-dd和H:M:S)。该示例首先分配 2 个实例,Event然后继续读取与用户一样多的输入,更新分配大小并根据需要将原始复制到新的。初始设置和重新分配代码如下:
#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()函数将原始指针的地址作为参数,因为开始地址会在重新分配时发生变化。因此,您可以从调用者那里传递指针的地址,而不是仅仅传递一个指针,这样您就可以更新该地址以指向新重新分配的内存块readEvents()。由于您正在对原始指针地址进行操作,因此将在调用者中看到该更改。如果您没有传递原始指针的地址,则必须返回一个指向新分配块的指针,并将其分配给调用者中的指针。
for 的实现readEvents()取消了混合getline和>>on std::cin。取而代之的是简单地使用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并开始读取数据。代码通过输出内存统计信息(分配的元素/使用的元素)完成并输出每个存储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 */
}
示例使用/输出
$ ./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
如果您对这种方法还有其他问题,请仔细查看并告诉我。