Может ли кто-нибудь объяснить мне, как я могу получить доступ к элементу void*, который находится внутри массива void**, учитывая, что void** принадлежит структуре

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

typedef struct student{
            int grade;
            int enrollCode;
}student;

typedef struct colVoidStar{
            int capacity;
            int num_itens_curr;
            void **arr;
            int current_pos;
}colVoidStar;

colVoidStar *colCreate(int capacity){
    if(capacity > 0){
        colVoidStar *c = malloc(sizeof(colVoidStar));
        if(c != NULL){
            c->arr = (void**)malloc(sizeof(void*)*capacity);
            if( c->arr != NULL){
                c->num_itens_curr = 0;
                c->capacity = capacity;
                return c;
            }
            free(c->arr);
        }
        free(c);
    }
    return NULL;
}


int colInsert(colVoidStar *c, void *item){
    if(c != NULL){
        if(c->num_itens_curr < c->capacity){
            c->arr[c->num_itens_curr] = (student*)item;
            c->num_itens_curr++;
            return 1;
        }
    }
    return 0;
}


void *colRemove(colVoidStar *c, void *key, int compar1(void* a, void* b)){
    int(*ptrCompar)(void*, void*) = compar1;
    student* eleRemoved;
    if(c != NULL){
        if(c->num_itens_curr > 0){
            int i = 0;
            for(i; i < c->num_itens_curr; i++){
                if(ptrCompar((void*)key, (void*)c->arr[i]) == 0){
                   eleRemoved = (student*)c->arr[i];
                   for(int j = i; j < c->num_itens_curr; j++){
                        c->arr[i] = c->arr[i + 1];
                        c->arr[i + 1] = 0;
                    }
                   return (void*)eleRemoved;
                }
                return NULL;
            }
        }
    }
    return NULL;
}

int compar1(void *a, void*b){
    int key;
    student *item;
    key = *(int*)a;
    item = (student*)b;
    return (int)(key - item->enrollCode);
}


int main(){
int finishProgram = 0, choose, capacity, returnInsert, removeEnroll;
colVoidStar *c;
student *a, *studentRemoved;
while(finishProgram != 9){
    printf("-----------------panel-----------------------\n");
    printf("Type: \n");
    printf("[1] to create a collection;\n");
    printf("[2] to insert a student;\n");
    printf("[3] to remove some student of collection;\n");
    printf("--------------------------------------------------------\n");
    scanf("%d", &choose);
    switch(choose){
        case 1:
            printf("Type the maximum of students the collection will have: \n");
            scanf("%d", &capacity);
            c = (colVoidStar*)colCreate(capacity);
            if(c == NULL){
                printf("Error in create collection!\n");
            }
            break;
        case 2:
            if(c->num_itens_curr < capacity){
                a = (student*)malloc(sizeof(student));
                printf("%d student:(type the Grade and the Enroll code, back-to-back)\n", c->num_itens_curr + 1);
                scanf("%d %d", &a->grade, &a->enrollCode);
                returnInsert = colInsert(c, (void*)a);
                if(returnInsert == 1){
                    for(int i = 0; i < c->num_itens_curr; i++){
                        printf("The student added has grade = %d e enrollCode = %d \n", (((student*)c->arr[i])->grade), ((student*)c->arr[i])->enrollCode);
                    }

                }else{
                    printf("the student wasn't added in the collection\n");
                }
            }else{
                printf("it's not possible to add more students to the colletion, since the limit of elements was reached!");
            }
            break;
        case 3:
            printf("Type an enrollcode to remove the student attached to it:\n");
            scanf("%d", &removeEnroll);
            studentRemoved = (student*)colRemove(c, &removeEnroll, compar1(&removeEnroll, c->arr[0]));
            if(studentRemoved != NULL)
                printf("the student removed has grade = %d and enrollcode %d.", studentRemoved->grade, studentRemoved->enrollCode);
            else
                printf("the number typed wasn't found");
            break;

    }
}
 return 0;
}

---> Как вы понимаете, то, что я пытаюсь сделать, по крайней мере на данном этапе, - это получить доступ и удалить элемент ( student* что изначально будет предполагать void* тип) студенческой коллекции ( void**arr), используя своего рода код регистрации. Однако у меня проблемы с Segmentation Fault, и я не могу понять, почему и как их решить, отсюда и мой вопрос. Отлаживая код, я обнаружил, что ошибки лежат в: if(ptrCompar((void)key, (void**)*c->arr[i]) == 0) Внутри Remove функция и return (int)(key - item->matricula) Внутри Compar1. Кроме того, если вы можете указать мне на некоторые статьи / документы / все, что поможет мне понять, как справляться с подобными проблемами, я буду очень признателен.

1 ответ

Вот проблемы, в которых я вижу:

  1. (На самом деле это не проблема, просто вопрос стиля) Хотя параметр функции int compar1(void* a, void* b) ОК, более условно использовать синтаксис int (*compar1)(void* a, void* b).
  2. (На самом деле это не проблема) Наличие обоих и указание на одну и ту же функцию излишне. Наверное, лучше назвать параметр ptrCompar чтобы избежать путаницы читателя с функцией, определенной в другом месте кода.
  3. Функция должна быть универсальной и не должна использоваться для eleRemovedПеременная. Возможно, это было просто для отладки? Так должно быть .
  4. После того, как удаляемый элемент был найден, оставшийся код неверен:
    • не был уменьшен для уменьшения количества предметов.
    • Код доступа c->arr[i] а также c->arr[i + 1] вместо c->arr[j] а также .
    • c->arr[j + 1] может иметь доступ за пределами последнего элемента, потому что условие завершения цикла отключено на 1. Это может быть потому, что c->num_itens_curr не было уменьшено.
    • Назначение c->arr[j + 1] = 0; на самом деле не требуется, потому что все элементы, кроме последнего, будут перезаписаны на следующей итерации, а значение старого последнего элемента не имеет значения, потому что количество элементов должно быть уменьшено на 1.
  5. (На самом деле это не проблема) В функции нет необходимости использовать операции приведения типов (например, приведение к void *).

Вот исправленная и, возможно, улучшенная версия функции (с меньшим количеством переменных):

      void *colRemove(colVoidStar *c, void *key, int (*ptrCompar)(void* a, void* b)){
    void* eleRemoved = NULL;
    if(c != NULL){
        int i;
        /* Look for item to be removed. */
        for(i = 0; i < c->num_itens_curr; i++){
            if(ptrCompar(key, c->arr[i]) == 0){
                /* Found it. */
                eleRemoved = c->arr[i];
                c->num_itens_curr--;    /* There is now one less item. */
                break;
            }
        }
        /* Close the gap. */
        for(; i < c->num_itens_curr; i++){
            c->arr[i] = c->arr[i + 1];
        }
    }
    return eleRemoved;
}

Кроме того, этот призыв colRemove из main это неверно:

                  studentRemoved = (student*)colRemove(c, &removeEnroll, compar1(&removeEnroll, c->arr[0]));

Последний аргумент должен быть указателем на функцию, но код фактически передает результат вызова функции типа int. Его следует изменить на это:

                  studentRemoved = (student*)colRemove(c, &removeEnroll, compar1);

или, удалив ненужное приведение типа void* к :

                  studentRemoved = colRemove(c, &removeEnroll, compar1);

В colInsert функция также должна быть универсальной, поэтому не следует использовать это несоответствующее приведение типа для student*:

                  c->arr[c->num_itens_curr] = (student*)item;

Возможно, это также было для целей отладки, но нужно просто использовать item как есть:

                  c->arr[c->num_itens_curr] = item;

Как указал @chux в комментариях к вопросу, выражение key - item->enrollCode в return заявление о compar1может переливаться. Я рекомендую изменить его на что-то вроде этого:

         return key < item->enroleCode ? -1 : key > item->enrolCode ? 1 : 0;

или изменив его, чтобы использовать этот хитрый трюк:

         return (key > item->enroleCode) - (key < item->enroleCode);
Другие вопросы по тегам