выделение в куче памяти массива указателей на структуру

Я пытаюсь создать простую базу данных, используя такую ​​структуру, как

struct Employee{
    char* name;
    int ID;
    int GPA;
    int salary;
};

я знаю, как я могу выделить один указатель типа структуры в куче, используя это

struct Employee* emp=malloc(sizeof(Employee));

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


person Omar Khaled    schedule 15.02.2015    source источник
comment
Известно ли вам количество сотрудников на момент первоначального распределения или со временем можно добавить больше сотрудников?   -  person interjay    schedule 15.02.2015
comment
как только пользователь вводит число размеров, это количество сотрудников.   -  person Omar Khaled    schedule 15.02.2015
comment
Не забывайте, что name также является указателем, и вам может потребоваться выделить (и освободить) место для него.   -  person pmg    schedule 15.02.2015


Ответы (3)


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

Вы можете сделать это, например, используя realloc при изменении размера:

yourArrayPtr=realloc(yourArrayPtr,newsize * sizeof(struct Employee));

Функция realloc в основном назначает новый объем памяти для данных, на которые указывает ее возвращаемое значение. Это удобный способ расширения или сжатия динамически выделяемого массива. newsize здесь новое количество элементов вашего массива, и оно умножается на размер одной структуры Employee, отображая общий объем пространства, необходимый для вашего нового массива. Возвращаемое значение realloc присваивается вашему указателю массива, так что он указывает конкретно на это вновь выделенное пространство. В этом случае его можно использовать следующим образом:

struct Employee* emp= NULL;

И тогда, когда вам это нужно:

int n = 8;
emp = realloc (emp, n * sizeof(struct Employee));

Имейте в виду, что вам еще нужно free эту память.

Теперь вы можете инициализировать и получить доступ к этим данным:

emp[3] = {value1, value2, value3, ...};

Что касается структур, вы также можете подумать о другой структуре данных — связанном списке, где каждая структура содержит указатель на ее преемника. Вы можете прочитать об этом здесь: http://www.cprogramming.com/tutorial/c/lesson15.html

В вашем случае это будет примерно так:

struct Employee{
    char* data;
    struct Employee* next;
};
person Michał Szydłowski    schedule 15.02.2015
comment
я не использовал realloc до того, как использовал malloc, так что не могли бы вы рассказать больше? - person Omar Khaled; 15.02.2015
comment
теперь emp указывает на 8 блоков кучи? и как я могу получить доступ к каждому из них? - person Omar Khaled; 15.02.2015
comment
realloc может вернуть NULL. Вы должны использовать другой указатель для возвращаемого значения и, если это не NULL, присвоить возвращаемое значение указателю, который фактически используется. - person ; 15.02.2015

Как уже упоминалось, вы можете использовать malloc для создания как можно большего количества записей сведений о сотрудниках в куче и сохранения их в динамическом списке (linked list). я привел пример кода, вы можете начать отсюда и расширить его, если вы хотите сохранить данные о сотруднике перед выходом, вы можете записать его в двоичный файл и прочитать его при повторном запуске программы (в зависимости от ваших потребностей ), так как после выхода из программы все данные будут потеряны.

#include <stdio.h>
#include <stdlib.h>
// Max length for employee name
const unsigned int MAX_NAME_LEN = 100;

typedef struct Employee{
    char* name;
    unsigned int ID;
    int GPA;
    float salary;
} EMPLOYEE ;


typedef struct emp_database_entry {
    EMPLOYEE data;
    struct emp_database_entry *next;
} EMPLOYEE_ENTRY;

typedef EMPLOYEE_ENTRY* EMPLOYEE_DATABASE;

// to create a new employee
EMPLOYEE_ENTRY* createEmployee() {

    EMPLOYEE_ENTRY *newEmp = (EMPLOYEE_ENTRY*)malloc(sizeof(EMPLOYEE_ENTRY));
    printf("Enter Employee Name:");
    newEmp->data.name = (char*)malloc( MAX_NAME_LEN * sizeof(char) );
    scanf("%s",newEmp->data.name);
    printf("Enter employee ID:");
    scanf("%u",&newEmp->data.ID);
    printf("Enter employee GPA:");
    scanf("%u",&newEmp->data.GPA);
    printf("Enter employee salary:");
    scanf("%f",&newEmp->data.salary);
    newEmp->next = 0;

    return (newEmp);
}

// add a new employee to database
EMPLOYEE_DATABASE addEmployee(EMPLOYEE_DATABASE db) {

    EMPLOYEE_ENTRY *newEmp = createEmployee();
    if(db == NULL) {
        // add the first entry
        db = newEmp;
    } else {
        // add it to the top
        newEmp->next = db;
        db = newEmp;
    }
    return (db);
}
// Search for Employee using ID
EMPLOYEE_ENTRY* searchEmployee(EMPLOYEE_DATABASE db, unsigned int ID) {
    EMPLOYEE_ENTRY *employee = db;
    if(employee == NULL) {
        printf("There are no Employees in the database\n");
        return (NULL);
    }
    // Search till the end, if a match is found return the
    // pointer to employee
    while( employee != NULL ) {
        if( employee->data.ID == ID )
            return (employee);
        else
            employee = employee->next;
    }
    return (NULL);
}

void printOneEmployee( EMPLOYEE_ENTRY *employee ) {
    printf("Employee Details\n");
    printf("Name  : %s\n",employee->data.name);
    printf("ID    : %u\n",employee->data.ID);
    printf("GPA   : %d\n",employee->data.GPA);
    printf("Salary: %f\n\n",employee->data.salary);
}
// Print all employee details
void printAllEmployee( EMPLOYEE_DATABASE db ) {
    EMPLOYEE_ENTRY *employee = db;
    // traverse till the end and print one by one
    while( employee != NULL ) {
        printOneEmployee(employee);
        employee = employee->next;
    }
}
// freeing allocated memory
void freeDatabase(EMPLOYEE_DATABASE db) {
    EMPLOYEE_DATABASE employee = 0;
    while( db != NULL ) {
        employee = db;
        db = employee->next;
        free(employee->data.name);
        free(employee);
    }
}

void displayOption( EMPLOYEE_DATABASE db ) {

    int option = -1;

    while( option != 5 ) {
        printf("\nEmployee DataBase\n");
        printf("1: Add a Employee\n");
        printf("2: Search Employee\n");
        printf("3: Print All Employee\n");
        printf("4: Exit\n");
        printf("Enter a number for the choice: ");
        scanf("%d",&option);

        if( option > 4 || option < 0 ) {
            option = -1;
        }

        switch( option ) {
            case 1:
                db = addEmployee(db);
                break;
            case 2:
                int ID;
                if(db != NULL){
                   printf("Enter the Employee ID: ");
                   scanf("%d",&ID);
                   printf("Search Result1: ");
                   printOneEmployee(searchEmployee(db, ID));
                }
                else
                    printf("No Employees in the database\n");
                break;
            case 3:
                printAllEmployee(db);
                break;
            case 4:
                freeDatabase(db);
                printf("DataBase Deleted\nExiting..");
                exit(0);
            default:
                printf("Invalid Option!. Try Again!.\n");

        }
    }
}
int main() {

    EMPLOYEE_DATABASE db = 0;
    displayOption(db);

    return (0);
}
person Sridhar Nagarajan    schedule 15.02.2015

Конечно, вы можете использовать массивы, если используете C99. В C99 вы можете делать такие вещи, как:

scanf("%d", &N);
struct Employee emp[N];
emp[0].ID = 123;

если вы используете gcc (или MinGW), обязательно скомпилируйте с -std=c99

С другой стороны, если вы просто хотите создать массив в куче, вы можете сделать что-то вроде:

scanf("%d", &N);
struct Employee* emp=malloc(N*sizeof(Employee));
emp[0].ID =123;
...
// do not forget to deallocate emp
free(emp);
person Diego Andres Alvarez Marin    schedule 15.02.2015
comment
я использую компилятор minGW, и я бы попробовал ваш второй код, но у меня есть вопрос struct Employee* emp=malloc(N*sizeof(Employee)); как я могу справиться с этим замедлением, поскольку это массив? - person Omar Khaled; 15.02.2015
comment
также emp должен быть указателем, должен ли я использовать синтаксис x-‹y вместо x.y? - person Omar Khaled; 15.02.2015
comment
В случае, если размер массива должен уменьшиться после создания, вы можете использовать realloc(), как предложил Михал Шидловски. - person Diego Andres Alvarez Marin; 15.02.2015
comment
Да, опечатка. Исправлено. - person Diego Andres Alvarez Marin; 15.02.2015