Вызов указателя функции

Это продолжение того, как создать указатель функции для добавления метода print, Добавление указателя функции в структуру для печати. Скажем, я создал это следующим образом:

typedef struct Book {
    char* title;
    unsigned int year;
    void (*print)(struct Book *book);
} Book;

void print(Book *book)
{
    printf("{\n\ttitle: \"%s\",\n\tyear: %d\n}\n", book->title, book->year);
}

int main(int argc, char * argv[])
{

    Book book  = {
        .title="Jaws",
        .year=2000
    };
    print(&book);      // this works
    book.print(&book); // this seg faults

}

Как правильно сделать вызов book.print()?


c
person carl.hiass    schedule 01.11.2020    source источник
comment
При объявлении Book book (или после его объявления) вам также необходимо инициализировать book.print, если вы собираетесь его использовать.   -  person goodvibration    schedule 01.11.2020
comment
@goodvibration - понятно, поэтому добавление .print=print к объявлению структуры?   -  person carl.hiass    schedule 01.11.2020
comment
Я бы предложил переименовать атрибут print в структуре Book, чтобы (вас) не спутать его с функцией с именем print.   -  person goodvibration    schedule 01.11.2020
comment
Да на ваш вопрос выше, но см. мой дополнительный комментарий под ним.   -  person goodvibration    schedule 01.11.2020
comment
вы не установили book.print, вот и все. Одной из особенностей языка c, которой нет, является привязка функций к структурам.   -  person Daniel Farrell    schedule 01.11.2020
comment
Путаница в .print=print происходит из-за того, что это на 100% нормально, нет конфликта пространств имен, поскольку имена элементов структуры и имена функций занимают разные пространства имен. (хотя это никак не решает путаницы, создаваемой человеческим мозгом при взгляде на него)   -  person David C. Rankin    schedule 01.11.2020


Ответы (1)


Это segfaults, потому что вы не назначили указатель print. Попробуйте это вместо этого:

int main(int argc, char * argv[])
{

    Book book  = {
        .title="Jaws",
        .year=2000,
        .print=print
    };
    print(&book);      // this works
    book.print(&book); // this no longer seg faults
}
person Ken Wayne VanderLinde    schedule 01.11.2020
comment
В коде нет указателя книги (если вы не имеете в виду &book, но его не нужно назначать, так как он указывает на локальный объект Book). - person goodvibration; 01.11.2020
comment
@ Кен - спасибо, это работает. Какой «тип» представляет собой функция (или метка функции?), считается ли она указателем на адрес памяти, с которого начинается эта функция? - person carl.hiass; 01.11.2020
comment
@carl.hiass - да, указатель функции - это просто адрес самой функции. Вы сопоставляете тип с объявлением функции, как вы сделали в своей структуре. (Кстати, Челюсти были 1975 :) - person David C. Rankin; 01.11.2020
comment
@KenWayneVanderLinde может захотеть обновить // this seg faults до // this works now too :) И я бы изменил int argc, char *argv[] на void, чтобы избежать предупреждений компилятора о неиспользуемых переменных... (обе просто гниды) - person David C. Rankin; 01.11.2020
comment
@DavidC.Rankin Копируйте макароны снова! Спасибо, что указали на это. Я решил оставить сигнатуру функции как есть, поскольку она взята непосредственно из вопроса. - person Ken Wayne VanderLinde; 02.11.2020
comment
Да, это все хорошо. Я всегда немного посмеиваюсь, когда в ответе все еще есть эти segfaults (я сам виноват ...) Спасибо за хороший ответ. - person David C. Rankin; 02.11.2020