Этот вопрос основан на моем предыдущем вопросе.

Вот такая у меня конструкция. Он использует SDL2:

void init_window(SDL_Window *window)
{
    window = SDL_CreateWindow(…);
}

int main(void)
{ 
    SDL_Window  *window;
    init_window(window);
}

Это не сработало. Предлагаемый ответ: я использовал *&window в качестве параметра функции, и он отлично работал. Я переписал *&window на **window следующим образом:

void init_window(SDL_Window **window)
{
    *window = SDL_CreateWindow(…);
}

int main(void)
{ 
    SDL_Window  *window;
    init_window(&window);
}

И это тоже работает. Но я до сих пор не понимаю, почему первая версия не работает. Я просмотрел детали реализации SDL_Window, и это просто нормальный typedef структуры, чтобы поместить ее в обычное пространство имен. SDL_CreateWindow возвращает SDL_Surface *.

Чтобы представить себе свою дилемму, я написал эту простую программу:

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

typedef struct Person
{
    char *name;
    int age;
} Person;

Person *person_create(char *name, int age)
{
    Person *who = malloc(sizeof(Person));
    who->name   = strdup(name);
    who->age    = age;

    return who;
}

void person_get_old(Person *who)
{
    who->age += 30;
}

int main(void)
{
    Person *susan = person_create("Susan", 23);
    person_get_old(susan);
    printf("%i\n", susan->age);
}

Это напечатает 53, как и ожидалось, без использования указателя на семантику указателя. В чем разница между моей реализацией и SDL2 . Это не вопрос SDL2, поскольку тот, кто ответил на мой предыдущий вопрос, мог бы ответить на него без каких-либо знаний о SDL2, поэтому, похоже, есть некоторые детали реализации, которые я пропустил. Надеюсь, кто-нибудь сможет меня просветить.

4
hgiesel 21 Фев 2016 в 08:51

2 ответа

Лучший ответ

Вот более простой пример для иллюстрации:

void foo(int p) //create new copy of int
{
    p = 0; //modify copy, original is unchanged
}
void bar(int* p) //create new copy of pointer
{
    *p = 0; //modify object pointer is set to
}

В вашем примере SDL вы пытались выполнить foo. Целью было установить указатель на новое значение. Однако вы только скопировали указатель, и все изменения были внесены в копию.

В вашем примере Person вы выполняли bar. У вас был объект, на который указывали, и вы хотели его изменить. Правильный способ сделать это - передать его по указателю (или ссылке).

Поскольку у вас есть объект, который вы хотите изменить, вам необходимо передать его указателем (или ссылкой). Поскольку этот объект сам является указателем, он будет указателем на указатель.

3
Weak to Enuma Elish 21 Фев 2016 в 06:02

Разница между вашей реализацией и SDL2 заключается в том, что в вашей реализации возвращается указатель, а вызывающий код присваивает его переменной.

В реализации SDL2 вызываемая функция хочет сохранить указатель, и вы хотите, чтобы он сохранялся в существующем указателе, определяемом вызывающим кодом. Ему нужно знать, где хранить указатель, поэтому ему нужен указатель на указатель.

3
Michael Greene 21 Фев 2016 в 05:58