c - 递归地创建和显示人的金字塔 - C
问题描述
问题:我正在尝试获取两个数组,并将它们传递给一个函数,我应该在该函数中递归地显示字母“人”的列表,并将它们放置在金字塔中,在那里我显示膝盖上的重量最底层的人,就是上面那个人的一半重量,加上他们自己的重量。所以最上面的人靠自己的重量,而金字塔边的人只承受 1 人的一半,其他人都承受 2。将处理此问题的递归调用。
我创建了两个函数,一个在用户输入底行有多少人后生成列表中有多少人;下一个函数只是根据整个金字塔中有多少人给每个人一个字母。
我已经将两个数组(权重和字母字符)以及总人数传递给了函数。
如何创建一种基于膝盖重量递归生成金字塔的方法?
例子:
How many people are on the bottom row? 4
Each person's own weight:
51.18
55.90 131.25
69.05 133.66 132.82
53.43 139.61 134.06 121.63
Weight on each person's knees:
51.18
81.49 156.84
109.80 252.82 211.24
108.32 320.92 366.09 227.25
理想情况下,我想将他们各自的字母附加到值上,但这不是必需的。
甚至不确定我的函数是否有足够的值,或者我是否应该创建二维数组而不是单个数组。无法解决整个问题。
代码: 最终函数有错误,无法确定要发送什么以递归调用正确的输出。
int bottomRow(int userNum);
float weightedKness(float arr[], int totalpeople, char letters[]);
int main() {
int bottomrow, total_people, k = 1, j = 1;
char letterPerson;
printf("How many people on the bottom row?\n");
//if 7 is entered, the letter assignment will go out of alphabet's range
scanf("%d", &bottomrow);
//recursively finding the total number of people in the pyramid
//printf("Total people in pyramid is: %d\n", bottomRow(bottomrow));
total_people = bottomRow(bottomrow);//total_people is an integer of all people
//populating array
float people[total_people];
for (; j <= total_people; ++j) {
//insert randomized weight here between 250 and 50 (child - hopefully they aren't on the bottom)
people[j] = 50;
//printf("Weight of person %d is %.2flbs\n", j, people[j]);
}
//printf("Total people is %d\n", total_people);
//populating an array of chars to align to the array of weights
char assignedLetter[total_people];
letterPerson = 'A';
for (; k <= total_people; ++k) {
assignedLetter[k] = letterPerson++;
//printf("%d is now %c\n", k, array[k]);
}
for (int i = 1; i <= total_people; ++i) {
// printf("Weight of person %c is %.2flbs\n", assignedLetter[i], people[i]);
}
//weightedKness(people, total_people);
/* char letterPerson = {'@'};//holds an array of letters based on the amount of people
//starting the ascii value to 1 before capital A
for (; i <= total_people; ++i) {
++letterPerson;
printf("Weight of person %c is %.2flbs\n", letterPerson, people[i]);
//send through corresponding letter and weight based on i
}
*/
return 0;
}
int bottomRow(int userNum) {
if (userNum == 1) {
return 1;
}
//printf("Num is %d\n", userNum);
//finding total of people in pyramid based on the given bottom
return bottomRow(userNum - 1) + userNum;
}
float weightedKness(float arr[], int totalpeople, char letters[]) {
int list_start = totalpeople;
if (totalpeople < 0) {
return 0;
}
if (arr[1] && letters[1] ) {
return 0;
}
return weightedKness(arr[totalpeople-1],totalpeople-1, letters[totalpeople-1] + )
}
感谢您的任何指导,您可以发送我的方式!
解决方案
递归函数需要 (1) 将停止递归的递归测试条件,以及 (2) 函数内的递归调用。
注意...避免在简单的程序方法可行的情况下使用递归。每个递归调用本身就是一个单独的函数调用,需要单独的函数堆栈、局部变量等......如果您的递归需要太多递归调用,您可以很容易地耗尽可用内存。在选择递归解决方案之前,请确保您了解可以调用函数的次数。
也就是说,存在一些问题,递归提供了一种非常优雅的解决方案,而不会导致内存耗尽。排列、阶乘等......就是很好的例子。递归函数也提出了很好的家庭作业问题,因为它是编程的必要领域,它要求您仔细考虑在进行递归调用时会发生什么 - 以及在满足递归测试条件后会发生什么(并且您当每个递归调用返回时,必须从递归中“放松”。
在您的情况下,您将获得包含每个人的权重的数组,并将其与一个相同大小的单独数组一起传递,以计算金字塔中每个点的人金字塔的权重。您必须输出金字塔中每个点的人员数组和权重数组。
您的递归测试条件相当简单,您将进行递归调用以覆盖people
数组中的每一行以计算权重。您将当前行作为函数参数传递,因此您的递归测试只是您的行数是否达到了金字塔的大小(数组的大小)。
在初始和每次递归调用中,您需要 (1) 打印人员数组并 (2) 根据上述人员计算权重,然后在函数中进行递归调用。然后在进行递归调用之后,您将需要打印您计算的权重 - 但要小心,当您从每个递归调用返回并“展开”递归时,您使用的行计数器将从其限制开始并返回零. 在递归调用之后,这将需要一些计划来处理您的数组索引。
例如,设置你的递归函数,你可以这样想:
#include <stdio.h>
#define SIZEP 4 /* constant for rows/cols - otherwise VLA or allocate */
void pyramid (double (*people)[SIZEP], double (*weight)[SIZEP], int row)
{
if (row < SIZEP) { /* recursive test condition */
/* handle all computations/print people here */
pyramid (people, weight, row + 1); /* recursive call */
/* print your weights here (but reverse the indexes) */
}
}
现在你已经有了一个大纲,但是如何处理编写函数与编写任何函数没有什么不同。您考虑必须满足的任何特殊条件(例如,第一行,顶部没有重量,只有要计算的人,金字塔边缘的数组的第一个和最后一个元素仅承载上面单个人的重量,等等。)因此,只需将您的特殊条件合并到递归函数的流程中 - 但请记住,您只有一个递归函数,因此函数本身必须在每次调用时处理这些特殊条件中的每一个 -它们是否适用于当前行数。
这里的方法非常简单,你想检查你是否在金字塔的第一行,然后将权重复制到weight
数组中。对于所有其他行,您将需要三个条件 (1) 处理第一个元素(左边缘)计算;(2) 处理金字塔中的所有内部位置(如果有),以及 (3) 处理行中的最后一个元素(右边缘)。在进行递归调用之前,您将以相同的方式打印和计算权重,例如
if (row < SIZEP) { /* recursive test condition */
/* recursion */
if (row == 0) { /* print people, set weight */
printf ("%6.2lf\n", people[row][0]);
weight[row][0] = people[row][0];
}
else {
/* print 1st person, set 1st weight */
printf ("%6.2lf", people[row][0]);
weight[row][0] = people[row][0] + weight[row-1][0] / 2.0;
/* print inner people, set innter weights */
for (int i = 1; i < row; i++) {
printf (" %6.2lf", people[row][i]);
weight[row][i] = people[row][i] +
(weight[row-1][i-1] + weight[row-1][i]) / 2.0;
}
/* print last person, set last weight */
printf (" %6.2lf\n", people[row][row]);
weight[row][row] = people[row][row] + weight[row-1][row-1] / 2.0;
}
pyramid (people, weight, row + 1); /* recursive call */
...
现在会发生什么row == SIZEP
??您的递归函数开始从递归调用返回。因此,如果您在传递row + 1
和的地方进行最后一次递归调用row == SIZEP
,则返回和展开将在您的递归调用之后立即开始。这里的价值是row
什么?(如果您通过递归调用row + 1
并且它在您的测试条件下返回,那么row
没有改变它仍然是最后一行(例如3
在您的情况下)。
在最后的递归调用中发生的所有事情是:
void pyramid (double (*people)[SIZEP], double (*weight)[SIZEP], int row)
{
if (row < SIZEP) { /* recursive test condition -- FAILED */
}
}
现在您又回到了上一次调用中,准备开始返回和展开,row
将索引保持在数组中的最后一行。递归调用下面发生的只是weight
数组的打印。但是,您不想将其颠倒打印,因此您需要处理 的值row
以将展开索引映射到相同的索引0-3
而不是3-0
.
使用一个简单的变量来反转行(比如revrow
——我不喜欢打字)并使用减去当前row
值(+1
)SIZEP
并将其用作您的索引来打印weights
,例如
...
pyramid (people, weight, row + 1); /* recursive call */
/* return from recursion */
int revrow = SIZEP - (row + 1); /* print weights in reverse order */
if (revrow == 0) /* same logic as computing weights applies */
printf ("\n%6.2lf\n", weight[revrow][0]);
else {
printf ("%6.2lf", weight[revrow][0]);
for (int i = 1; i < revrow; i++)
printf (" %6.2lf", weight[revrow][i]);
printf (" %6.2lf\n", weight[revrow][revrow]);
}
}
}
您不必担心传递任何东西,因为您的递归调用展开,row
每个返回的值将是它在进行递归调用之前在该函数中具有的值。
将其放在一个简短的示例中,您将拥有以下内容:
#include <stdio.h>
#define SIZEP 4 /* constant for rows/cols - otherwise VLA or allocate */
void pyramid (double (*people)[SIZEP], double (*weight)[SIZEP], int row)
{
if (row < SIZEP) { /* recursive test condition */
/* recursion */
if (row == 0) { /* print people, set weight */
printf ("%6.2lf\n", people[row][0]);
weight[row][0] = people[row][0];
}
else {
/* print 1st person, set 1st weight */
printf ("%6.2lf", people[row][0]);
weight[row][0] = people[row][0] + weight[row-1][0] / 2.0;
/* print inner people, set innter weights */
for (int i = 1; i < row; i++) {
printf (" %6.2lf", people[row][i]);
weight[row][i] = people[row][i] +
(weight[row-1][i-1] + weight[row-1][i]) / 2.0;
}
/* print last person, set last weight */
printf (" %6.2lf\n", people[row][row]);
weight[row][row] = people[row][row] + weight[row-1][row-1] / 2.0;
}
pyramid (people, weight, row + 1); /* recursive call */
/* return from recursion */
int revrow = SIZEP - (row + 1); /* print weights in reverse order */
if (revrow == 0) /* same logic as computing weights applies */
printf ("\n%6.2lf\n", weight[revrow][0]);
else {
printf ("%6.2lf", weight[revrow][0]);
for (int i = 1; i < revrow; i++)
printf (" %6.2lf", weight[revrow][i]);
printf (" %6.2lf\n", weight[revrow][revrow]);
}
}
}
int main (void) {
double people[SIZEP][SIZEP] = {{ 51.18 },
{ 55.90, 131.25 },
{ 69.05, 133.66, 132.82 },
{ 53.43, 139.61, 134.06, 121.63 }},
weight[SIZEP][SIZEP] = {{ 0 }};
pyramid (people, weight, 0);
return 0;
}
示例使用/输出
$ ./bin/pyramidrecurse
51.18
55.90 131.25
69.05 133.66 132.82
53.43 139.61 134.06 121.63
51.18
81.49 156.84
109.79 252.82 211.24
108.33 320.92 366.09 227.25
考虑一下。递归函数需要稍微不同的思维方式才能使它们有意义。但是,当你意识到你只是在途中重复调用同一个函数,然后在你的递归展开时处理每个调用的返回 - 它会开始下沉。
使用带有 C99+ 的 VLA
与其声明一个整数常量SIZEP
来声明两者people
,而且声明为具有自动存储类型weight
的数组,您还有另外两个选项可以让您根据用户输入来调整两个数组的大小。第一个,如果你有 C99+ 编译,是使用可变长度数组。虽然具有自动存储持续时间的数组需要一个整数常量作为数组声明的大小,但 VLA 允许使用一个变量来调整数组的大小。(需要注意的是,VLA 不能使用正常的初始化程序来初始化,例如,等等,相反,您必须使用或循环手动初始化 VLA){{0}}
memset
此外,如注释中所述,当将 VLA 作为参数传递时,您必须在数组之前将大小作为参数传递,以便知道数组的大小,例如function (int size, vla1[size], vla2[size])
. 如果size
未在数组之前传递,则在等size
中将不知道。vla1[size]
使用 VLA 或使用 动态分配等之间的主要区别在于malloc
,对于 VLA,您仍然必须在声明数组之前获取数组大小的输入。VLA 无法调整大小。malloc
并realloc
提供动态增加阵列存储量的能力,而无需事先知道行数或元素数。您只需分配一些合理预期的大小,如果在您完成读取所有输入之前达到大小,您可以调用realloc
该内存块并即时分配更多(但它确实需要更多几行代码。这不再困难,只需要更多的变量来跟踪您分配了多少内存,您使用了多少,以及何时used == allocated
,您realloc
,用新的分配大小更新变量,然后继续。
在下面的示例中,size
被读取为第一个输入(来自下面的文件,但它可以很容易地在 上输入stdin
),VLA 是使用 创建size
的,VLA 设置为全零,memset
然后传递给递归pyramid
函数. 另请注意,递归函数已被拆分为三个函数,以简化对实际递归pyramid
函数的理解,同时将计算和打印移至递归前调用compute
函数和函数中的递归后展开unwind
。
(它在功能上没有区别,但是将您的代码“分解”成简单易懂的代码可以帮助保持直截了当)
#include <stdio.h>
#include <string.h>
void compute (int size, double (*people)[size], double (*weight)[size], int row)
{
if (row == 0) { /* print people, set weight */
printf ("%6.2lf\n", people[row][0]);
weight[row][0] = people[row][0];
}
else {
/* print 1st person, set 1st weight */
printf ("%6.2lf", people[row][0]);
weight[row][0] = people[row][0] + weight[row-1][0] / 2.0;
/* print inner people, set inner weights */
for (int i = 1; i < row; i++) {
printf (" %6.2lf", people[row][i]);
weight[row][i] = people[row][i] +
(weight[row-1][i-1] + weight[row-1][i]) / 2.0;
}
/* print last person, set last weight */
printf (" %6.2lf\n", people[row][row]);
weight[row][row] = people[row][row] + weight[row-1][row-1] / 2.0;
}
}
void unwind (int size, double (*weight)[size], int row)
{
int revrow = size - (row + 1); /* print weights in reverse order */
if (revrow == 0) /* same logic as computing weights applies */
printf ("\n%6.2lf\n", weight[revrow][0]);
else {
printf ("%6.2lf", weight[revrow][0]);
for (int i = 1; i < revrow; i++)
printf (" %6.2lf", weight[revrow][i]);
printf (" %6.2lf\n", weight[revrow][revrow]);
}
}
void pyramid (int size, double (*people)[size], double (*weight)[size], int row)
{
if (row < size) { /* recursive test condition */
/* computations before recursive call */
compute (size, people, weight, row);
/* recursive call */
pyramid (size, people, weight, row + 1);
/* return from recursion */
unwind (size, weight, row);
}
}
int main (int argc, char **argv) {
int size; /* read from user or file */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
if (fscanf (fp, "%d", &size) != 1) { /* read size */
fprintf (stderr, "error: invalid format '%s'\n", argv[1]);
return 1;
}
double people[size][size], /* declare VLAs, but you */
weight[size][size]; /* can't initialize VLAs */
memset (people, 0, size * sizeof *people); /* zero both arrays */
memset (weight, 0, size * sizeof *weight);
for (int i = 0; i < size; i++)
for (int j = 0; j <= i; j++)
if (fscanf (fp, "%lf", &people[i][j]) != 1) {
fprintf (stderr, "error: reading people[%d][%d]\n", i, j);
return 1;
}
fclose (fp); /* close file */
pyramid (size, people, weight, 0); /* compute/print arrays */
return 0;
}
示例输入文件
$ cat dat/pyramidweight.txt
4
51.18
55.90 131.25
69.05 133.66 132.82
53.43 139.61 134.06 121.63
示例使用/输出
$ ./bin/pyramidrecursefnvla dat/pyramidweight.txt
51.18
55.90 131.25
69.05 133.66 132.82
53.43 139.61 134.06 121.63
51.18
81.49 156.84
109.79 252.82 211.24
108.33 320.92 366.09 227.25
malloc
和calloc
- 完成存储拼图
如上所述,使用malloc, calloc, realloc
动态分配存储的主要优点是无需size
事先知道。这意味着,如果用户(或您的文件)不包含size
,您可以简单地动态分配一些合理数量的指针并为每个指针分配一些double
值的存储空间并开始读取您的数据。
没有要求分配用于保存行值的每个块与double
之前或之后的行分配的值数量相同。(您可以通过存储在第一行数据中读取的值的数量来强制执行此要求,并将其与读取的每一行进行比较,例如,如果您正在读取一个方矩阵的数据)。但是在这里,由于您有size
输入,使用它,它通过消除“最初分配多少指针?”的猜测工作简化了过程。(我们知道,size
其中)
在进一步讨论之前,我们在关于动态分配的讨论中使用了“指针”这个词,而在其他两个案例中我们使用了“数组” 。这是一个重要的区别。数组不是指针,指针也不是数组,但要明白数组在访问时会转换为指针。具体来说:C11 标准 - 6.3.2.1 其他操作数 - 左值、数组和函数指示符 (p3)
(p3) 除非它是运算
sizeof
符、 运算符_Alignof
或一元'&'
运算符的操作数,或者是用于初始化数组 的字符串字面量,否则类型为"array of type"的表达式将转换为类型为"的表达式指向类型的指针”,它指向数组对象的初始元素并且不是左值。
由于您传递的是指向指针的指针 ,因此double
您的函数参数需要从指向数组的指针更改为指向指针的指针,例如people
weight
double
double
void pyramid (int size, double **people, double **weight, int row)
如果您分配...您必须验证!
动态分配时,malloc, calloc & realloc
可以并且确实会因内存耗尽而失败。当它们失败时,它们各自返回NULL
指示失败。否则,它们返回您分配给指针的已分配内存块的起始地址,然后可以使用数组表示法- 或指针表示法(例如people[2]
,数组表示法等同*(people + 2)
于指针表示法 - 并且因为数组转换为访问指针,您也可以将任一表示法与数组一起使用)
有什么变化main()
?您的声明people
和weight
开始,例如
double **people = NULL, /* pointer to pointer to double */
**weight = NULL;
作为输入后size
,分配你的指针(size
每个),例如
/* first allocate size pointers to each people and weight */
people = malloc (size * sizeof *people);
if (people == NULL) { /* validate every allocation */
perror ("malloc-people");
exit (EXIT_FAILURE);
}
weight = malloc (size * sizeof *weight);
if (!weight) { /* validate every allocation */
perror ("malloc-weight");
exit (EXIT_FAILURE);
}
(注意:在分配存储时,您需要size
乘以sizeof
您分配的任何内容。虽然您可以使用类型,例如sizeof (double*)
,使用取消引用的变量本身来调整类型的大小总是更好。例如,如果您分配的people
是double**
,如果你使用sizeof *people
, 那么*people
就是double*
. 这将确保你永远不会弄错类型大小. 对于复杂类型的错误很可能和常见的猜测类型是, 例如,指向数组的指针或指向 的指针数组, 等等... )
此时,您有size
每个分配的指针。虽然您可以猜测值的数量,但分配该数量的双打,并且realloc
如果您达到 aljust 定位的限制 - (但这需要重新读取从 value-at-a-time 到一次一行然后解析——如果你好奇,我留给你),但是在这里,因为我们知道我们正在建模array[size][size]
并且我们array[size]
分配了指针,剩下的就是size
为每个指针分配双精度,例如
/* now allocate a block of size double for each pointer,
* let's use calloc here to both allocate and set all bytes zero.
*/
for (int i = 0; i < size; i++) { /* loop over pointers */
people[i] = calloc (size, sizeof *people[i]); /* allocate doubles */
if (!people[i]) { /* validate every allocation */
perror ("calloc-people[i]");
exit (EXIT_FAILURE);
}
weight[i] = calloc (size, sizeof *weight[i]); /* allocate doubles */
if (!weight[i]) { /* validate every allocation */
perror ("calloc-weight[i]");
exit (EXIT_FAILURE);
}
}
(用and再次注意字体大小)sizeof *people[i]
sizeof *weight[i]
总而言之,你最终得到:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void compute (double **people, double **weight, int row)
{
if (row == 0) { /* print people, set weight */
printf ("%6.2lf\n", people[row][0]);
weight[row][0] = people[row][0];
}
else {
/* print 1st person, set 1st weight */
printf ("%6.2lf", people[row][0]);
weight[row][0] = people[row][0] + weight[row-1][0] / 2.0;
/* print inner people, set inner weights */
for (int i = 1; i < row; i++) {
printf (" %6.2lf", people[row][i]);
weight[row][i] = people[row][i] +
(weight[row-1][i-1] + weight[row-1][i]) / 2.0;
}
/* print last person, set last weight */
printf (" %6.2lf\n", people[row][row]);
weight[row][row] = people[row][row] + weight[row-1][row-1] / 2.0;
}
}
void unwind (int size, double **weight, int row)
{
int revrow = size - (row + 1); /* print weights in reverse order */
if (revrow == 0) /* same logic as computing weights applies */
printf ("\n%6.2lf\n", weight[revrow][0]);
else {
printf ("%6.2lf", weight[revrow][0]);
for (int i = 1; i < revrow; i++)
printf (" %6.2lf", weight[revrow][i]);
printf (" %6.2lf\n", weight[revrow][revrow]);
}
}
void pyramid (int size, double **people, double **weight, int row)
{
if (row < size) { /* recursive test condition */
/* computations before recursive call */
compute (people, weight, row);
/* recursive call */
pyramid (size, people, weight, row + 1);
/* return from recursion */
unwind (size, weight, row);
}
}
int main (int argc, char **argv) {
int size; /* read from user or file */
double **people = NULL, /* pointer to pointer to double */
**weight = NULL;
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
exit (EXIT_FAILURE);
}
if (fscanf (fp, "%d", &size) != 1) { /* read size */
fprintf (stderr, "error: invalid format '%s'\n", argv[1]);
exit (EXIT_FAILURE);
}
/* first allocate size pointers to each people and weight */
people = malloc (size * sizeof *people);
if (people == NULL) { /* validate every allocation */
perror ("malloc-people");
exit (EXIT_FAILURE);
}
weight = malloc (size * sizeof *weight);
if (!weight) { /* validate every allocation */
perror ("malloc-weight");
exit (EXIT_FAILURE);
}
/* now allocate a block of size double for each pointer,
* let's use calloc here to both allocate and set all bytes zero.
*/
for (int i = 0; i < size; i++) { /* loop over pointers */
people[i] = calloc (size, sizeof *people[i]); /* allocate doubles */
if (!people[i]) { /* validate every allocation */
perror ("calloc-people[i]");
exit (EXIT_FAILURE);
}
weight[i] = calloc (size, sizeof *weight[i]); /* allocate doubles */
if (!weight[i]) { /* validate every allocation */
perror ("calloc-weight[i]");
exit (EXIT_FAILURE);
}
}
/* the rest is the same - except for parameter types for pyramid */
for (int i = 0; i < size; i++) /* read people values from file */
for (int j = 0; j <= i; j++)
if (fscanf (fp, "%lf", &people[i][j]) != 1) {
fprintf (stderr, "error: reading people[%d][%d]\n", i, j);
return 1;
}
fclose (fp); /* close file */
pyramid (size, people, weight, 0); /* compute/print arrays */
for (int i = 0; i < size; i++) {
free (people[i]);
free (weight[i]);
}
free (people);
free (weight);
return 0;
}
示例输入和使用/输出
输入和输出是一样的。
内存使用/错误检查
在您编写的任何动态分配内存的代码中,对于分配的任何内存块,您有两个责任:(1)始终保留指向内存块起始地址的指针,(2)它可以在没有时被释放更需要。
您必须使用内存错误检查程序来确保您不会尝试访问内存或写入超出/超出分配块的范围,尝试读取或基于未初始化值的条件跳转,最后确认释放所有分配的内存。
对于 Linuxvalgrind
是正常的选择。每个平台都有类似的内存检查器。它们都易于使用,只需通过它运行您的程序即可。
$ valgrind ./bin/pyramidrecursemalloc dat/pyramidweight.txt
==1851== Memcheck, a memory error detector
==1851== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==1851== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==1851== Command: ./bin/pyramidrecursemalloc dat/pyramidweight.txt
==1851==
51.18
55.90 131.25
69.05 133.66 132.82
53.43 139.61 134.06 121.63
51.18
81.49 156.84
109.79 252.82 211.24
108.33 320.92 366.09 227.25
==1851==
==1851== HEAP SUMMARY:
==1851== in use at exit: 0 bytes in 0 blocks
==1851== total heap usage: 11 allocs, 11 frees, 872 bytes allocated
==1851==
==1851== All heap blocks were freed -- no leaks are possible
==1851==
==1851== For counts of detected and suppressed errors, rerun with: -v
==1851== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认您已释放所有已分配的内存并且没有内存错误。
如果您还有其他问题,请仔细查看并告诉我。
推荐阅读
- php - 我想在处理时等待 php 函数(来自另一个调用)
- excel - 创建报告模板表并根据日期和时间填充数据
- xml - Android底部导航栏图标变形
- swift - 如果每个用户旁边都有一个赞按钮,为什么滚动触发随机用户的赞按钮被突出显示?
- javascript - 用于姓名检查的多语言字母
- javascript - 更改一个按钮的背景颜色 onClick 并将先前单击的按钮恢复为默认背景(8个按钮)
- c# - 有没有办法对android服务代码进行截图?
- c# - ASP.NET Core - 从类库中查看
- python - 使用工作表[#][#] 查找单元格值时收到单元格未找到错误
- python - Python从(多个)文件中删除行(S)