Выделение динамической памяти для переменной внутри структуры - PullRequest
0 голосов
/ 11 ноября 2019

Ниже приведен небольшой код, и цель состоит в том, чтобы научиться и практиковаться в создании базы данных учащихся с использованием структуры с динамическим распределением оценок, полученных каждым студентом. Проблема, с которой я сталкиваюсь, заключается в том, что, когда я пытаюсь выставить оценки для каждого студента,

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

Ответы [ 2 ]

2 голосов
/ 11 ноября 2019

Вы усложняете себе задачу, пытаясь использовать нотацию указателя, а не нотацию индекса массива. Например, ваше распределение students в порядке, но смотрите Разыгрывает ли я результат malloc? .

Когда вы начинаете использовать студентов, тогда как (students + i)->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)

Всегда подтверждайте, что вы освободили всю выделенную память и что ошибок памяти нет.

Посмотрите вещии дайте мне знать, если у вас есть дополнительные вопросы.

0 голосов
/ 11 ноября 2019

Хотите ли вы динамически размещать как структуру, так и данные, использовать массив нулевой (или переменной) длины в структуре вместо указателя.

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...