Как мне заполнить указатель структуры глобальной ссылкой на структуру внутри функции C? - PullRequest
1 голос
/ 16 марта 2012

Я новичок в C и не могу понять, почему my_struct_ptr (main) равно нулю в следующем примере. Как бы я назначил адрес структуры в массиве my_structs указателю my_struct_ptr в функции get_my_struct_by_name?

struct my_struct {
    char *name;
    char *descr;
    char *value;
} my_structs[3] = {
    {"a", "a description", "value 1"},
    {"b", "b description", "value 2"},
    {"c", "c description", "value 3"}
};

int get_my_struct_by_name(char *name, struct my_struct *my_struct_ptr) {

    int i;
    for (i=0; i < (sizeof(my_structs)/sizeof(struct my_struct)); i++) {
            if (strcmp(name, my_structs[i].name) == 0) {

                    my_struct_ptr = &my_structs[i];

                    printf("works: %s,%s,%s\n", my_struct_ptr->name, my_struct_ptr->descr, my_struct_ptr->value);
                    return 0;
            }
    }

    return -1;
}


int main() {
    int res = 0;
    struct my_struct *my_struct_ptr;

    if (res = get_my_struct_by_name("b", my_struct_ptr))
            return res;

    printf( "nil: %p\n", my_struct_ptr);

    printf("seg fault: %s,%s,%s\n", my_struct_ptr->name, my_struct_ptr->descr, my_struct_ptr->value);

    return res;
}

Редактировать: добавление примера вывода, чтобы, надеюсь, помочь другим. Спасибо всем, кто откликнулся. Это именно та помощь, которую я искал!

Выход:

[prompt ~]$ ./test
works: b,b description,value 2
nil: (nil)
Segmentation fault

Ответы [ 3 ]

4 голосов
/ 16 марта 2012

Вы должны передать указатель как указатель (т.е. передать его адрес):

int get_my_struct_by_name(char *name, struct my_struct **my_struct_ptr)
{                                                   // ^^^
    // ...
    *my_struct_ptr = /* ... */
}

int main()
{
    struct my_struct * my_struct_ptr;
    get_my_struct_by_name(name, &my_struct_ptr);
    // ...
}

Если вы просто передаете указатель по значению, как вы это делали, вы изменяете только локальную копию указателя, а не исходный указатель.

Мораль: если вы хотите, чтобы функция изменила переменную в вызывающей области, вам нужно где-то сказать &.

1 голос
/ 16 марта 2012

Решением является использование указателя на указатель в вашей функции get_my_struct_by_name. Обратите внимание на добавление * (звездочка) в объявлении, затем в присваивании (внутри get_my_struct_by_name) и & амперсанд при вызове (внутри main). Таким образом, вы передаете указатель на my_struct_ptr, определенный в main, и присваиваете правильное значение непосредственно вашей переменной в main.

В этом решении предполагается, что вы используете чистый C (в C ++ наличие ссылки на указатель было бы, вероятно, более удобным).

int get_my_struct_by_name(char *name, struct my_struct **my_struct_ptr)
{
    int i;
    for(i=0; i < (sizeof(my_structs)/sizeof(struct my_struct)); i++)
    {
        if(strcmp(name, my_structs[i].name) == 0)
        {
            *my_struct_ptr = &my_structs[i];
            printf("works: %s,%s,%s\n", my_struct_ptr->name, my_struct_ptr->descr,     
                   my_struct_ptr->value);
            return 0;
        }
    }

    return -1;
}


int main()
{
    int res = 0;
    struct my_struct *my_struct_ptr;

    if (res = get_my_struct_by_name("b", &my_struct_ptr))
        return res;

    printf( "nil: %p\n", my_struct_ptr);

    printf("seg fault: %s,%s,%s\n", my_struct_ptr->name, my_struct_ptr->descr, 
    my_struct_ptr->value);
    return res;
}
0 голосов
/ 16 марта 2012

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

int get_my_struct_by_name(char *name, struct my_struct **my_struct_ptr) 
{      
    int i;    
    for (i=0; i < (sizeof(my_structs)/sizeof(struct my_struct)); i++) 
    {             
        if (strcmp(name, my_structs[i].name) == 0) 
        {                      
           *my_struct_ptr = &my_structs[i];
           printf("works: %s,%s,%s\n", my_struct_ptr->name, 
                   my_struct_ptr->descr, my_struct_ptr->value);
           return 0;             
        }     
    }      
 return -1; 
}

, а затем вам нужно взять адрес указателя и передать его из основной подпрограммы.

if (res = get_my_struct_by_name("b", &my_struct_ptr))                 
   return res;

Таким образом, вы можете вернуть адрес структуры.

...