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

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

Итак, я пытался free конкретную ячейку, а затем сдвинуть другие ячейки, чтобы не осталось пустых ячеек. После этого я попытался «вырезать» последнюю ячейку, которая в настоящее время пуста, с realloc массивом на -1. Пожалуйста, смотрите комментарии в коде, где я описываю мою проблему.

User** deleteMale(User** pMaleArr, int *maleArrSize, User *onlineUser)
{
    int i,j;
    //for each array element check if the username matches to the 
    // connected user
    for (i = 0;i < *maleArrSize;i++)
    {
        if (strcmp(pMaleArr[i]->userName, onlineUser->userName) ==0) 
        {
            //when the user is found, free all fields of the struct
            freeUserFields(onlineUser);
            //check if it's the last array cell
            if (i != *maleArrSize - 1)
            {
                //shift cells
                for (j = i;j < *maleArrSize;j++)
                {
                    pMaleArr[j] = pMaleArr[j + 1];

                }//free the last cell
                free(pMaleArr[*maleArrSize-1]); //I'm getting a problem here because now the 2 last cells of the array have the same pointer adress.
            }
            //remove the last cell
            pMaleArr = (User **)realloc(pMaleArr, (*maleArrSize 
- 1)*sizeof(User*));
            if (pMaleArr == NULL)
            {
                if (*maleArrSize != 1)
                {
                    printf(MA_FAILED);
                    exit(1);
                }
            }
            break;
        }
    }
    *maleArrSize -= 1;
    return pMaleArr;
}

void freeUserFields(User *person)
{
    if (person != NULL)
    {
        //free all fields
        free(person->firstName);
        free(person->lastName);
        free(person->age);
        free(person->userName);
        free(person->userPassword);
        free(person->about);
        free(person->hobbies);
        //free node itself
        free(person);
    }

}

Итак, как я заметил выше, когда я пытаюсь free последнюю ячейку, чтобы впоследствии удалить ее, она также удаляет ячейку (last-1), потому что я скопировал их адреса. Я не могу найти другой способ сдвинуть клетки в этом случае. Могу ли я получить совет, как правильно с этим справиться? Спасибо!

Ответы [ 3 ]

0 голосов
/ 09 января 2019

Я добавил примечания к вашему коду, надеюсь, это поможет:

     //check if it's the last array cell
        if (i != *maleArrSize - 1)
        {
            //shift cells
            for (j = i;j < *maleArrSize-1;j++)
            {
                pMaleArr[j] = pMaleArr[j + 1];/* you need till size -1 because of[j+1]*/

            }//free the last cell
            free(pMaleArr[*maleArrSize-1]); //I'm getting a problem here because now the 2 last cells of the array have the same pointer adress.
        }
        //remove the last cell- here if the cell to remove was the last one you don't free its inner allocations.
        pMaleArr = (User **)realloc(pMaleArr, (*maleArrSize 
0 голосов
/ 09 января 2019

В этом фрагменте кода есть серьезная проблема:

    if (strcmp(pMaleArr[i]->userName, onlineUser->userName) ==0) 
    {
        //when the user is found, free all fields of the struct
        freeUserFields(onlineUser);                  // NOOO !!!

Вы освобождаете поля в структуре, которая была передана для управления именем пользователя, в то время как вы должны получать доступ только к содержимому массива *pMaleArr. Вы должны написать:

    if (strcmp(pMaleArr[i]->userName, onlineUser->userName) ==0) 
    {
        //when the user is found, free all fields of the struct
        freeUserFields(pMaleArr[i]);

И вы не должны освобождать последнюю клетку. Вы не освобождаете указатель, но где он указывает. То, на что указывает последний указатель, теперь указывается предыдущим указателем и должно быть сохранено. Так что другая часть должна быть:

        if (i != *maleArrSize - 1)
        {
            //shift cells
            for (j = i;j < *maleArrSize;j++)
            {
                pMaleArr[j] = pMaleArr[j + 1];

            }//just ignore the last cell
        }
0 голосов
/ 09 января 2019

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

Просто удалите второй бесплатный.

Кроме того, второй цикл должен доходить до j < *maleArrSize -1.

...