#c #pointers #struct
Вопрос:
У меня есть структура, определенная следующим образом
typedef struct{
int id;
char* name;
float percentage;
}student_t;
И есть функция, которая должна печатать элемент структуры в этом формате
"id, name, percentagen"
Но функция учитывает void* val_ref //struct ptr, void* fp
Как мне заставить это работать? Функция выглядит следующим образом (заданные параметры не могут быть изменены)
void printStudentInfo(void* val_ref, void* fp)
{
if (val_ref != NULL)
{
fprintf(fp, "%d,%s,%.2f", val_ref->id, val_ref->name, val_ref->percentage);
}
}
Но я не могу скомпилировать, в нем написано предупреждение: задержка недействительна*
ошибка указателя: запрос элемента «идентификатор» в чем-то, что не является структурой или объединением
ошибка: запрос элемента «имя» в чем-то, что не является структурой или объединением
ошибка: запрос элемента «процент» в чем-то, что не является структурой или объединением
Нужно ли мне приводить тип для параметра val_ref?
Комментарии:
1. Да, вы должны напечатать указатель на пустоту обратно. Или просто измените прототип функции, чтобы
student_t*
FILE*
вместо 2 параметров принимать a и avoid*
. Почему для начала требуются указатели на пустоту? Является ли это заданной функцией?2. @LouisCloete да, это заданная функция , я не могу изменять параметры, Но также, когда я делаю типизацию
student_t* val_ref
, компилятор сказал бы мне, чтоredeclare as a different kind of symbol and previous defined in function parameter
3. Здесь бессмысленно использовать указатели void, просто используйте соответствующие типы указателей.
4.
val_ref->id, val_ref->name, val_ref->percentage
->((student_t*)val_ref)->id, ((student_t*)val_ref)->name, ((student_t*)val_ref)->percentage
5. Я согласен с @Jabberwocky. В чем был вопрос? Единственный способ, которым указатели на пустоту имеют смысл, — это если они должны быть «универсальными», имея возможность использовать более одного типа структуры и более одного типа дескриптора вывода и выводить универсальную структуру в общий дескриптор вывода.
Ответ №1:
fprintf(fp, "%d,%s,%.2f", val_ref->id, val_ref->name, val_ref->percentage);
Здесь вам нужно привести val_ref
к типу указателя, которым он на самом деле является: (student_t *)val_ref
а затем выбрать элемент структуры, например ((student_t*)val_ref)->id
.
Когда у вас есть a void*
, ваша программа не знает фактического типа данных, на который вы указываете. Следовательно, незаконно пытаться привлечь участника. При использовании приведения вы явно говорите, что val_ref
это указывает на a student_t
, и вы знаете, что делаете, когда просите конкретного участника.
Тем не менее, нет необходимости приводить fp
, потому что функция fprintf
имеет первый аргумент, как FILE *
и в ее сигнатуре:
int fprintf(FILE *stream, const char *format, ...);
Таким образом, даже если вы передадите a void *
в качестве первого параметра, локальная переменная stream
будет определена как a FILE *
, и именно с этим работает функция.
Комментарии:
1. Спасибо за ваш ответ, нужно ли мне вводить текст в
if
заявлении?2. @AlexHu Нет. Сравнение a
void *
сNULL
хорошо определено.3. Благодарен за ответ