【问题标题】:Allocating dynamic memory for a variable inside a structure为结构内的变量分配动态内存
【发布时间】:2019-11-11 06:32:42
【问题描述】:

下面是一个小代码,目标是学习和练习使用结构创建学生数据库,并动态分配每个学生获得的分数。我遇到的问题是当我尝试为这里的每个学生提供分数时,

scanf("%d",((students + i)->(ptr_marks + j)));

// creating a structure with variable students and the marks they have obtained

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

#define debugging

struct Student {
    int age;
    int roll_no;
    int* ptr_marks;
};

int main (void) {

// total number of students
    int num_students;
    printf("Enter # of Students: ");
    scanf("%d",&num_students);

// structure array definition
    struct Student* students;
    students = (struct Student*) malloc (num_students * sizeof(struct Student));
    assert(students != NULL);

    int marks;

    for (int i = 0 ; i < num_students ; i ++)   {

        (students + i )->roll_no = i + 1;
        (students + i )->age = i + 10;
        printf("Enter #'s of Subjects for Student %d: ",i);
        scanf("%d", &marks);

        // allocating memory for marks obtained by each student
        (students + i)->ptr_marks = (int *) malloc (sizeof(int) * marks);
        for (int j = 0 ; j < marks ; j ++)  {

            printf("Enter Mark for Subject %d: ", j+1);
            scanf("%d",((students + i)->(ptr_marks + j)));

        }
    }

#ifdef debugging

    for (int j = 0 ; j < num_students ; j ++)   {

        printf("The roll # of student %d are %d \n", j+1, (students+j)->roll_no);

    }

#endif

    free(students);
    //TODO
            // code to free up memory for marks
    return 0;
}

【问题讨论】:

  • 请解释您遇到的实际问题。
  • (students + i)-&gt;(ptr_marks + j) 应该是 (students + i)-&gt;ptr_marks + j 或更清晰的 &amp;students[i].ptr_marks[j]

标签: c pointers structure


【解决方案1】:

您尝试使用指针表示法而不是使用数组索引表示法让事情变得更加困难。例如,您分配的students 很好,但请参阅Do I cast the result of malloc?

当您开始使用学生时,虽然 (students + i)-&gt;roll_no = i + 1; 在技术上还不错,但它的可读性更高:students[i].roll_no = i + 1;[..] 也可以作为取消引用。您对每个学生 ptr_mark 的分配将是:

    students[i].ptr_marks = malloc (sizeof(int) * marks);
    assert (students[i].ptr_marks);

注意:验证每个分配)

其余部分只是清理工作,并与在 students[]... 上使用数组索引概念保持一致,并确保您验证每个输入,例如

    for (int j = 0 ; j < marks ; j++)  {
        printf ("Enter Mark for Subject %d: ", j+1);
        if (scanf ("%d", &students[i].ptr_marks[j]) != 1)
            return 1;
    }

然后您可以通过以下方式释放所有已分配的内存块:

    for (int i = 0; i < num_students; i++)
        free (students[i].ptr_marks);      /* free storage for ptr_marks */
    free(students);                        /* free pointers */

总而言之,你可以这样做:

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

#define debugging

struct Student {
    int age;
    int roll_no;
    int* ptr_marks;
};

int main (void) {

    // total number of students
    int num_students;
    printf("Enter # of Students: ");
    if (scanf("%d",&num_students) != 1)
        return 1;

    // structure array definition
    struct Student *students;
    students = malloc (num_students * sizeof(struct Student));
    assert(students != NULL);

    int marks;

    for (int i = 0 ; i < num_students ; i ++)   {

        students[i].roll_no = i + 1;
        students[i].age = i + 10;
        printf("Enter #'s of Subjects for Student %d: ",i);
        if (scanf("%d", &marks) != 1)
            return 1;

        // allocating memory for marks obtained by each student
        students[i].ptr_marks = malloc (sizeof(int) * marks);
        assert (students[i].ptr_marks);
        for (int j = 0 ; j < marks ; j++)  {
            printf ("Enter Mark for Subject %d: ", j+1);
            if (scanf ("%d", &students[i].ptr_marks[j]) != 1)
                return 1;
        }
    }

#ifdef debugging

    for (int j = 0 ; j < num_students ; j ++)   {

        printf("The roll # of student %d are %d \n", j+1, (students+j)->roll_no);

    }

#endif

    for (int i = 0; i < num_students; i++)
        free (students[i].ptr_marks);
    free(students);

    return 0;
}

使用/输出示例

使用其他输入进行锻炼会导致:

$ ./bin/struct_ptr_alloc
Enter # of Students: 2
Enter #'s of Subjects for Student 0: 3
Enter Mark for Subject 1: 90
Enter Mark for Subject 2: 91
Enter Mark for Subject 3: 94
Enter #'s of Subjects for Student 1: 3
Enter Mark for Subject 1: 87
Enter Mark for Subject 2: 72
Enter Mark for Subject 3: 93
The roll # of student 1 are 1
The roll # of student 2 are 2

内存使用/错误检查

在您编写的任何动态分配内存的代码中,对于分配的任何内存块,您都有 2 个职责:(1)始终保留指向起始地址的指针内存块,因此 (2) 当不再需要它时可以释放

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

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

$ valgrind ./bin/struct_ptr_alloc
==5051== Memcheck, a memory error detector
==5051== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5051== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5051== Command: ./bin/struct_ptr_alloc
==5051==
Enter # of Students: 2
Enter #'s of Subjects for Student 0: 2
Enter Mark for Subject 1: 99
Enter Mark for Subject 2: 100
Enter #'s of Subjects for Student 1: 2
Enter Mark for Subject 1: 89
Enter Mark for Subject 2: 92
The roll # of student 1 are 1
The roll # of student 2 are 2
==5051==
==5051== HEAP SUMMARY:
==5051==     in use at exit: 0 bytes in 0 blocks
==5051==   total heap usage: 5 allocs, 5 frees, 2,096 bytes allocated
==5051==
==5051== All heap blocks were freed -- no leaks are possible
==5051==
==5051== For counts of detected and suppressed errors, rerun with: -v
==5051== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

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

查看一下,如果您还有其他问题,请告诉我。

【讨论】:

  • 嗨,David,感谢您的回复,我了解使用数组可以使实现易于理解和实现。我也忘记了在编译后使用 valgrind 处理内存泄漏,所以这是一个很好的提醒。如果我使用指针路由你会怎么做,因为数组实现很简单。
  • 如果你走指针路线,你只需要记住students[i] == *(students + i) 关键是跟踪你什么时候有一个指针,什么时候有一个结构。您对(students + i)-&gt;... 的使用是正确的,但是当您到达(students + i)-&gt;ptr_marks + j 时——看起来就像是火车残骸。您的选择,但&amp;students[i].ptr_marks[j] 可读性更强:)
  • 知道了,这些天我正在研究我的 C,所以我可以从硬件工程潜入固件工程 :)
  • 祝你好运。我玩过一些 TI 的微控制器,玩得很开心。这是将编码应用于硬件的整个附加层。当您深入到引脚比较器级别并在上升/下降沿或调制的上升/下降沿捕获数据时,您真的很欣赏在 x86 上为分离编程的硬件/软件方面所做的工作。
  • 有什么好的链接可以推荐,有好的问题需要解决吗?
【解决方案2】:

您是否要动态分配结构和数据在结构中使用零(或可变)长度数组而不是指针。

typedef struct {
    int age;
    int roll_no;
    int ptr_marks[0]; // or int ptr_marks[0] 
 } student;

然后你可以动态分配和重新分配整个对象。

student *allocstudent(student *st, size_t nmarks)
{
     student *tmp = realloc(st, sizeof *st + nmarks * sizeof(st-> marks[0]));
    return tmp;
}

【讨论】:

    猜你喜欢
    • 2020-11-18
    • 2012-03-12
    • 2015-05-17
    • 2014-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-27
    相关资源
    最近更新 更多