Может ли кто-нибудь объяснить мне, как я могу получить доступ к элементу 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 ответ
Вот проблемы, в которых я вижу:
- (На самом деле это не проблема, просто вопрос стиля) Хотя параметр функции
int compar1(void* a, void* b)
ОК, более условно использовать синтаксисint (*compar1)(void* a, void* b)
. - (На самом деле это не проблема) Наличие обоих и указание на одну и ту же функцию излишне. Наверное, лучше назвать параметр
ptrCompar
чтобы избежать путаницы читателя с функцией, определенной в другом месте кода. - Функция должна быть универсальной и не должна использоваться для
eleRemoved
Переменная. Возможно, это было просто для отладки? Так должно быть . - После того, как удаляемый элемент был найден, оставшийся код неверен:
- не был уменьшен для уменьшения количества предметов.
- Код доступа
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.
- (На самом деле это не проблема) В функции нет необходимости использовать операции приведения типов (например, приведение к
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);