繁体   English   中英

可能的 Memory 分配问题?

[英]Possible Memory Allocation Issue?

G'day Coders,我为 Uni 编写的代码遇到了一些问题,我正在寻找一些建议。 似乎没有经过整个 for 循环就把我吐出来了,我只能到学生 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 添加到 linker 设置,但程序会在同一个地方崩溃提前谢谢!

代码 output

您想分配一个大小为nxm的二维数组。 您向用户询问尺寸。 然后分配 memory 的数量。

但不幸的是,编译器不知道这些维度和寻址,因为studentArray[i][j]将失败:第i行有多长?

在这种情况下,您必须明确地将寻址写为

studentArray[i*subjects+j]

Paul Ogilvie 的回答直接解决了核心问题——您实际上是在使用扁平化为 1D 的 2D 数组,因此您可以使用[i * w + j]对其进行索引。

但是,如果您所做的只是一次计算每个学生的总和和平均值,那么您甚至根本不需要 arrays,因为您只需将分数累加到sum中,然后除以计数。 假设您的代码的另一个版本确实需要数组,但是,这里有一个稍微更干净的代码版本,它将事物分为输入阶段和输出/计算阶段。

#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;
}

您的另一个选择是在您首先分配numberOfStudents指针的地方分配指向int的指针,然后循环并分配一个numberofSubjects int块,并依次将起始地址分配给每个分配的指针。 这是您将用于分配字符串或结构等集合的两步分配。您可以在其中模拟2D 数组。 这看起来像您前进的方向。

为此,您必须首先分配(并验证)您的指针块,为每个学生分配一个指针:

    /* 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 */
}

注意:由于这是一个 2 步分配,它需要一个 2 步free() 。当你处理完整数后,循环并free (studentArray[i]);这将释放所有 integer 存储。最后一个步骤是释放分配的指针,例如free (studentArray);

示例使用/输出

$ ./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) ,分子或分母都可以。

Memory 使用/错误检查

在您编写的任何动态分配 memory 的代码中,对于分配的 memory 的任何块,您有两个责任:(1)始终保留指向 ZCD69B4957F06CD818D7BF3D21980 块的起始地址的指针,所以它可以被释放,更需要。

您必须使用 memory 错误检查程序,以确保您不会尝试访问 memory 或写入超出/超出分配块的边界,尝试读取或基于未初始化值的条件跳转,最后确认释放所有已分配的 memory。

对于 Linux valgrind是正常的选择。 每个平台都有类似的 memory 检查器。 它们都易于使用,只需通过它运行您的程序即可。

$ 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)

始终确认您已释放所有已分配的 memory 并且没有 memory 错误。

如果您还有其他问题,请仔细查看并告诉我。

您的代码混合了一个简单的 2D 数组分配,稍后将作为arr[j + i * numberOfSubjects]访问,以及一个 2 级指针数组和数据数组。

后者的防弹方法是分配2个arrays,一个用于指针,一个用于数据,并初始化指针数组以正确使用二维数据数组:

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 *更严格的 alignment,否则这是灾难的根源,我不确定它是否真的符合标准:

int **arr = malloc(numberOfStudends * sizeof(int*)
                   + numberOfStudents * numberOfSubjects * sizeof(int))
int *data = (int *)(arr + numberOfStudents);

它曾经是一个常见的习惯用法,它是您的初始代码包含的内容,但除非您有非常充分的理由这样做,否则我建议您使用单独的分配。

为什么不使用“[]”而不是“**”;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM