可能的内存分配问题?
Possible Memory Allocation Issue?
编码员们好,
我在为 Uni 编写的代码中遇到了一些问题,我正在寻找一些建议。好像没经过整个for循环就把我吐出来了,只能到student 3了。如有帮助,将不胜感激。
#include<stdio.h>
#include <stdlib.h>//for the malloc function
int main()
{
int num;//user input of number of students
printf("enter the number of students: ");
scanf("%d",&num);
//user input of number of subjects
int subjects;
printf("enter the number of subjects: ");
scanf("%d",&subjects);
int *ptr, **arr;
//making 2d dynamic array of size nX subjects with the help of malloc
int len = sizeof(int *) * num + sizeof(int) * subjects * num;
arr = (int **)malloc(len);//will allocate the memory of size len dynamically
ptr = (int *)(arr + num);
int sum=0;//total sum of marks of a student
float average;//average of marks
//iterating for each student
for(int i=0;i<num;i++)
{
//user input the marks of each subject from a user
printf("enter the marks of student %d: ",i+1);
for(int j=0;j<subjects;j++)
scanf("%d",&arr[i][j]);
//summing up the total marks of the student
for(int j=0;j<subjects;j++)//iterating for each subject
sum+=arr[i][j];
printf("the total marks of student %d is %d \n",i+1,sum);//printing the total marks
//average of the marks of the student
average=(float)sum/(float)subjects;//average is equal to total sum divided by the total subjects
printf("and the average is %0.2f \n",average);
//making sum and average again 0 for the next student
sum=0;
average=0;
}
return 0;
}
尝试将 gcc -Wl,--stack=268435456 -Wl,--heap=268435456 添加到链接器设置,但程序会在同一位置崩溃在此先感谢!
code output
您想分配一个大小为 nxm
的二维数组。您向用户询问尺寸。然后你分配内存量。
但不幸的是,编译器不知道这些维度,并且寻址为 studentArray[i][j]
将失败:行 i
有多长?
在这种情况下,您必须将寻址明确写为
studentArray[i*subjects+j]
Paul Ogilvie 的回答直接解决了核心问题——您实际上是在使用扁平化为一维的二维数组,因此您使用 [i * w + j]
.
对其进行索引
然而,如果你所做的只是一次计算每个学生的总和和平均值,你甚至根本不需要数组,因为你可以将分数累加到 sum
,然后除以伯爵。假设你的代码的另一个版本确实需要数组,不过,这里有一个稍微更干净的代码版本,它将东西分为输入阶段和 output/computation 阶段。
#include <stdio.h>
#include <stdlib.h>
int main() {
int students, subjects;
printf("enter the number of students: ");
scanf("%d", &students);
printf("enter the number of subjects: ");
scanf("%d", &subjects);
// TODO: add bounds checks for students / subjects
// Allocate memory for students X subjects integers;
// calloc ensures the memory is zeroed too.
int *marks = calloc(students * subjects, sizeof(int));
// TODO: check the marks allocation succeeded
for (int i = 0; i < students; i++) {
printf("enter the marks of student %d: ", i + 1);
for (int j = 0; j < subjects; j++) {
scanf("%d", &marks[i * subjects + j]);
}
}
for (int i = 0; i < students; i++) {
int sum = 0;
printf("Student %d: ", i + 1);
for (int j = 0; j < subjects; j++) {
int mark = marks[i * subjects + j];
printf("%d ", mark);
sum += mark;
}
printf(" - ");
float average = sum / subjects;
printf("Total: %d, average: %.2f\n", sum, average);
}
return 0;
}
你的另一个选择是为你的pointer-to-pointer-toint
分配你首先分配numberOfStudents
pointers 然后循环并分配一个 numberofSubjects
int
的块并将起始地址依次分配给每个分配的指针。这是您将用于分配字符串集合或结构等的两步分配。您可以在其中 Simulate 二维数组。这看起来像你要去的方向。
为此,您必须首先分配(并验证)您的指针块,为每个学生分配一个指针:
/* allocate numberOfStudents pointers */
studentArray = malloc (numberOfStudents * sizeof *studentArray);
if (studentArray == NULL) { //check if memory allocated successfully
perror ("malloc-studentArray pointers");
return 1;
}
接下来,在收集数据的循环中,分配一个 numberofSubjects
整数块并将起始地址分配给下一个开放指针,例如
for (i = 0; i < numberOfStudents; i++) {
studentArray[i] = malloc (numberofSubjects * sizeof *studentArray[i]);
if (!studentArray[i]) {
perror ("malloc-studentArray[i]");
return 1;
}
printf ("enter the marks of student %d: ", i + 1);
for (j = 0; j < numberofSubjects; j++) {
scanf ("%d", &studentArray[i][j]);
sum += studentArray[i][j];
totalMarks += studentArray[i][j];
}
总而言之,您将拥有:
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
int numberOfStudents, numberofSubjects, sum = 0, i, j, totalMarks = 0;
int **studentArray;
printf ("Enter the Number of Students and Number of Subjects: ");
scanf ("%d%d", &numberOfStudents, &numberofSubjects);
/* allocate numberOfStudents pointers */
studentArray = malloc (numberOfStudents * sizeof *studentArray);
if (studentArray == NULL) { //check if memory allocated successfully
perror ("malloc-studentArray pointers");
return 1;
}
for (i = 0; i < numberOfStudents; i++) {
studentArray[i] = malloc (numberofSubjects * sizeof *studentArray[i]);
if (!studentArray[i]) {
perror ("malloc-studentArray[i]");
return 1;
}
printf ("enter the marks of student %d: ", i + 1);
for (j = 0; j < numberofSubjects; j++) {
scanf ("%d", &studentArray[i][j]);
sum += studentArray[i][j];
totalMarks += studentArray[i][j];
}
float average = (float)sum / numberofSubjects;
printf ("The average for student %d is %0.2f \n", j + 1, average);
average = 0;
sum = 0;
}
printf ("The Total Marks of Students is %d \n", totalMarks);
for (i = 0; i < numberOfStudents; i++)
free (studentArray[i]); /* free block of integers */
free (studentArray); /* free pointers */
}
(注意: 因为这是一个两步分配,它需要一个两步 free()
。当你完成你的整数时,你循环并free (studentArray[i]);
这将释放所有整数存储。最后一步是释放分配的指针,例如 free (studentArray);
例子Use/Output
$ ./bin/ptrissue
Enter the Number of Students and Number of Subjects: 3 4
enter the marks of student 1: 91 82 81 78
The average for student 5 is 83.00
enter the marks of student 2: 94 92 96 88
The average for student 5 is 92.50
enter the marks of student 3: 81 79 73 84
The average for student 5 is 79.25
The Total Marks of Students is 1019
请注意,您只需将除法的一部分转换为(float)
,分子或分母都可以。
内存Use/Error检查
在您编写的任何动态分配内存的代码中,您对分配的任何内存块负有 2 责任:(1) 始终保留指向内存块的起始地址 因此,(2) 当不再需要它时可以释放。
您必须使用内存错误检查程序来确保您不会尝试访问内存或写入 beyond/outside 您分配的块的边界,尝试读取或基于未初始化的条件跳转值,最后,确认您释放了所有已分配的内存。
对于Linux valgrind
是正常的选择。每个平台都有类似的内存检查器。它们都很简单易用,只需运行你的程序就可以了。
$ valgrind ./bin/ptrissue
==14645== Memcheck, a memory error detector
==14645== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==14645== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==14645== Command: ./bin/ptrissue
==14645==
Enter the Number of Students and Number of Subjects: 3 4
enter the marks of student 1: 91 82 81 78
The average for student 5 is 83.00
enter the marks of student 2: 94 92 96 88
The average for student 5 is 92.50
enter the marks of student 3: 81 79 73 84
The average for student 5 is 79.25
The Total Marks of Students is 1019
==14645==
==14645== HEAP SUMMARY:
==14645== in use at exit: 0 bytes in 0 blocks
==14645== total heap usage: 6 allocs, 6 frees, 2,120 bytes allocated
==14645==
==14645== All heap blocks were freed -- no leaks are possible
==14645==
==14645== For counts of detected and suppressed errors, rerun with: -v
==14645== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认您已释放所有分配的内存并且没有内存错误。
检查一下,如果您还有其他问题,请告诉我。
您的代码混合了一个简单的二维数组分配,稍后将作为 arr[j + i * numberOfSubjects]
访问,以及一个 2 级指针数组和数据数组。
后者的防弹方法是分配2个数组,一个用于指针,一个用于数据,并初始化指针数组以正确使用二维数据数组:
int **arr = malloc(numberOfStudends * sizeof(int*));
int *data = malloc(numberOfStudents * numberOfSubjects * sizeof(int));
for(i=0; i<numberOfStudents; i++) {
arr[i] = data + i * numberOfSubjects;
}
您现在可以安全地使用 arr[i][j]
...
一种相当高级(但不太健壮)的方法是在一次传递中分配两个数组。问题是,除非您确定 int
的实现没有比 int *
更严格的对齐方式,否则这是灾难的根源,而且我不确定它是否真的符合标准:
int **arr = malloc(numberOfStudends * sizeof(int*)
+ numberOfStudents * numberOfSubjects * sizeof(int))
int *data = (int *)(arr + numberOfStudents);
它曾经是一个常见的习惯用法,它是您初始代码中包含的内容,但除非您有非常充分的理由这样做,否则我建议您使用单独的分配。
编码员们好, 我在为 Uni 编写的代码中遇到了一些问题,我正在寻找一些建议。好像没经过整个for循环就把我吐出来了,只能到student 3了。如有帮助,将不胜感激。
#include<stdio.h>
#include <stdlib.h>//for the malloc function
int main()
{
int num;//user input of number of students
printf("enter the number of students: ");
scanf("%d",&num);
//user input of number of subjects
int subjects;
printf("enter the number of subjects: ");
scanf("%d",&subjects);
int *ptr, **arr;
//making 2d dynamic array of size nX subjects with the help of malloc
int len = sizeof(int *) * num + sizeof(int) * subjects * num;
arr = (int **)malloc(len);//will allocate the memory of size len dynamically
ptr = (int *)(arr + num);
int sum=0;//total sum of marks of a student
float average;//average of marks
//iterating for each student
for(int i=0;i<num;i++)
{
//user input the marks of each subject from a user
printf("enter the marks of student %d: ",i+1);
for(int j=0;j<subjects;j++)
scanf("%d",&arr[i][j]);
//summing up the total marks of the student
for(int j=0;j<subjects;j++)//iterating for each subject
sum+=arr[i][j];
printf("the total marks of student %d is %d \n",i+1,sum);//printing the total marks
//average of the marks of the student
average=(float)sum/(float)subjects;//average is equal to total sum divided by the total subjects
printf("and the average is %0.2f \n",average);
//making sum and average again 0 for the next student
sum=0;
average=0;
}
return 0;
}
尝试将 gcc -Wl,--stack=268435456 -Wl,--heap=268435456 添加到链接器设置,但程序会在同一位置崩溃在此先感谢!
code output
您想分配一个大小为 nxm
的二维数组。您向用户询问尺寸。然后你分配内存量。
但不幸的是,编译器不知道这些维度,并且寻址为 studentArray[i][j]
将失败:行 i
有多长?
在这种情况下,您必须将寻址明确写为
studentArray[i*subjects+j]
Paul Ogilvie 的回答直接解决了核心问题——您实际上是在使用扁平化为一维的二维数组,因此您使用 [i * w + j]
.
然而,如果你所做的只是一次计算每个学生的总和和平均值,你甚至根本不需要数组,因为你可以将分数累加到 sum
,然后除以伯爵。假设你的代码的另一个版本确实需要数组,不过,这里有一个稍微更干净的代码版本,它将东西分为输入阶段和 output/computation 阶段。
#include <stdio.h>
#include <stdlib.h>
int main() {
int students, subjects;
printf("enter the number of students: ");
scanf("%d", &students);
printf("enter the number of subjects: ");
scanf("%d", &subjects);
// TODO: add bounds checks for students / subjects
// Allocate memory for students X subjects integers;
// calloc ensures the memory is zeroed too.
int *marks = calloc(students * subjects, sizeof(int));
// TODO: check the marks allocation succeeded
for (int i = 0; i < students; i++) {
printf("enter the marks of student %d: ", i + 1);
for (int j = 0; j < subjects; j++) {
scanf("%d", &marks[i * subjects + j]);
}
}
for (int i = 0; i < students; i++) {
int sum = 0;
printf("Student %d: ", i + 1);
for (int j = 0; j < subjects; j++) {
int mark = marks[i * subjects + j];
printf("%d ", mark);
sum += mark;
}
printf(" - ");
float average = sum / subjects;
printf("Total: %d, average: %.2f\n", sum, average);
}
return 0;
}
你的另一个选择是为你的pointer-to-pointer-toint
分配你首先分配numberOfStudents
pointers 然后循环并分配一个 numberofSubjects
int
的块并将起始地址依次分配给每个分配的指针。这是您将用于分配字符串集合或结构等的两步分配。您可以在其中 Simulate 二维数组。这看起来像你要去的方向。
为此,您必须首先分配(并验证)您的指针块,为每个学生分配一个指针:
/* allocate numberOfStudents pointers */
studentArray = malloc (numberOfStudents * sizeof *studentArray);
if (studentArray == NULL) { //check if memory allocated successfully
perror ("malloc-studentArray pointers");
return 1;
}
接下来,在收集数据的循环中,分配一个 numberofSubjects
整数块并将起始地址分配给下一个开放指针,例如
for (i = 0; i < numberOfStudents; i++) {
studentArray[i] = malloc (numberofSubjects * sizeof *studentArray[i]);
if (!studentArray[i]) {
perror ("malloc-studentArray[i]");
return 1;
}
printf ("enter the marks of student %d: ", i + 1);
for (j = 0; j < numberofSubjects; j++) {
scanf ("%d", &studentArray[i][j]);
sum += studentArray[i][j];
totalMarks += studentArray[i][j];
}
总而言之,您将拥有:
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
int numberOfStudents, numberofSubjects, sum = 0, i, j, totalMarks = 0;
int **studentArray;
printf ("Enter the Number of Students and Number of Subjects: ");
scanf ("%d%d", &numberOfStudents, &numberofSubjects);
/* allocate numberOfStudents pointers */
studentArray = malloc (numberOfStudents * sizeof *studentArray);
if (studentArray == NULL) { //check if memory allocated successfully
perror ("malloc-studentArray pointers");
return 1;
}
for (i = 0; i < numberOfStudents; i++) {
studentArray[i] = malloc (numberofSubjects * sizeof *studentArray[i]);
if (!studentArray[i]) {
perror ("malloc-studentArray[i]");
return 1;
}
printf ("enter the marks of student %d: ", i + 1);
for (j = 0; j < numberofSubjects; j++) {
scanf ("%d", &studentArray[i][j]);
sum += studentArray[i][j];
totalMarks += studentArray[i][j];
}
float average = (float)sum / numberofSubjects;
printf ("The average for student %d is %0.2f \n", j + 1, average);
average = 0;
sum = 0;
}
printf ("The Total Marks of Students is %d \n", totalMarks);
for (i = 0; i < numberOfStudents; i++)
free (studentArray[i]); /* free block of integers */
free (studentArray); /* free pointers */
}
(注意: 因为这是一个两步分配,它需要一个两步 free()
。当你完成你的整数时,你循环并free (studentArray[i]);
这将释放所有整数存储。最后一步是释放分配的指针,例如 free (studentArray);
例子Use/Output
$ ./bin/ptrissue
Enter the Number of Students and Number of Subjects: 3 4
enter the marks of student 1: 91 82 81 78
The average for student 5 is 83.00
enter the marks of student 2: 94 92 96 88
The average for student 5 is 92.50
enter the marks of student 3: 81 79 73 84
The average for student 5 is 79.25
The Total Marks of Students is 1019
请注意,您只需将除法的一部分转换为(float)
,分子或分母都可以。
内存Use/Error检查
在您编写的任何动态分配内存的代码中,您对分配的任何内存块负有 2 责任:(1) 始终保留指向内存块的起始地址 因此,(2) 当不再需要它时可以释放。
您必须使用内存错误检查程序来确保您不会尝试访问内存或写入 beyond/outside 您分配的块的边界,尝试读取或基于未初始化的条件跳转值,最后,确认您释放了所有已分配的内存。
对于Linux valgrind
是正常的选择。每个平台都有类似的内存检查器。它们都很简单易用,只需运行你的程序就可以了。
$ valgrind ./bin/ptrissue
==14645== Memcheck, a memory error detector
==14645== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==14645== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==14645== Command: ./bin/ptrissue
==14645==
Enter the Number of Students and Number of Subjects: 3 4
enter the marks of student 1: 91 82 81 78
The average for student 5 is 83.00
enter the marks of student 2: 94 92 96 88
The average for student 5 is 92.50
enter the marks of student 3: 81 79 73 84
The average for student 5 is 79.25
The Total Marks of Students is 1019
==14645==
==14645== HEAP SUMMARY:
==14645== in use at exit: 0 bytes in 0 blocks
==14645== total heap usage: 6 allocs, 6 frees, 2,120 bytes allocated
==14645==
==14645== All heap blocks were freed -- no leaks are possible
==14645==
==14645== For counts of detected and suppressed errors, rerun with: -v
==14645== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认您已释放所有分配的内存并且没有内存错误。
检查一下,如果您还有其他问题,请告诉我。
您的代码混合了一个简单的二维数组分配,稍后将作为 arr[j + i * numberOfSubjects]
访问,以及一个 2 级指针数组和数据数组。
后者的防弹方法是分配2个数组,一个用于指针,一个用于数据,并初始化指针数组以正确使用二维数据数组:
int **arr = malloc(numberOfStudends * sizeof(int*));
int *data = malloc(numberOfStudents * numberOfSubjects * sizeof(int));
for(i=0; i<numberOfStudents; i++) {
arr[i] = data + i * numberOfSubjects;
}
您现在可以安全地使用 arr[i][j]
...
一种相当高级(但不太健壮)的方法是在一次传递中分配两个数组。问题是,除非您确定 int
的实现没有比 int *
更严格的对齐方式,否则这是灾难的根源,而且我不确定它是否真的符合标准:
int **arr = malloc(numberOfStudends * sizeof(int*)
+ numberOfStudents * numberOfSubjects * sizeof(int))
int *data = (int *)(arr + numberOfStudents);
它曾经是一个常见的习惯用法,它是您初始代码中包含的内容,但除非您有非常充分的理由这样做,否则我建议您使用单独的分配。