Как изменить значение указателей в функции в C - PullRequest
0 голосов
/ 23 февраля 2012

код:

     int main(int argc, const char* argv[] )
     {
        struct node * initialpointer=NULL;
        insert("asd", initialpointer, 1);
        if(initialpointer!=NULL)
            printf("isnotnull");
        if (initialpointer==NULL)
            printf("isnull");
     }
     insert(char* x,struct node * initialpointer, int numberofelements){
        struct node B;
        B.word = x;
        B.parent = NULL;
        B.leftchild = NULL;
        B.rightchild = NULL;
        printf("%d", 12);
        if ( initialpointer == NULL){
           initialpointer = &B;
           B.parent = NULL;
        }
     }

Итак, в конце я хочу, чтобы initialpointer указывал, где находится nde B, но в основном методе он печатает, что он равен нулю. Так как же я могу навсегда изменить initialpointer в функции вставки?

Ответы [ 5 ]

4 голосов
/ 23 февраля 2012

Не возвращайте указатель на локальную переменную, это приведет к зависанию указателя:

struct node B;
...
initialpointer = &B;

Вам нужно передать указатель на указатель с struct node на insert() и malloc() новый struct node внутри insert():

insert(char* x,struct node ** initialpointer, int numberofelements)
{
    if (NULL == *initialpointer)
    {
        *initialpointer = malloc(sizeof(struct node));
        if (*initialpointer)
        {
            /* Note: you should probably make a copy of 'x',
               using 'strdup()' or similar, otherwise there
               is requiremenet that 'x' exist for the lifetime
               of '*initialpointer': which would be error prone. */
            (*initialpointer)->word       = x;
            (*initialpointer)->parent     = NULL;
            (*initialpointer)->leftchild  = NULL;
            (*initialpointer)->rightchild = NULL;
        }
    }
}

При этом сохраняется логика оригинала insert(), поскольку node должен быть создан и назначен только initialpointer, если initialpointerэто NULL.

И вызвать его:

struct node * initialpointer=NULL;
insert("asd", &initialpointer, 1);

Запоминание free(), когда оно больше не требуется:

free(initialpointer);
0 голосов
/ 23 февраля 2012

Это проблематично по двум причинам.

Прежде всего, вы изменяете переменную локальной области видимости, поскольку initialpointer является параметром вашей функции.Это означает, что независимо от его типа, то, что вы пишете в саму переменную, видимо только внутри вашей insert функции.Если бы вы писали в *initialpointer, это была бы совсем другая история.

Теперь, что еще более проблематично, это то, что B является локальной переменной, которая находится в стеке внутри вашей функции.Как только эта функция будет оставлена, место хранения B будет недействительным.Следовательно, если вы вернете указатель на B, доступ к этому объекту за пределами insert вызовет неопределенное поведение и, скорее всего, не сработает (у вас есть небольшой шанс, что это конкретное местоположение не было изменено, но это просто удача).

То, что вы, вероятно, хотите вместо

initialpointer = &B;

, таково:

*initialpointer = B;

Это скопирует объект B вместо хранения, на которое ссылается переменная указателя.Теперь можно B выйти из области видимости, потому что вы скопировали все в переменную initialpointer, которая находится внутри main .

Обратите внимание, что переменная initialpointer внутриmain - это совсем не то, что в insert!


И последнее: указание имен переменных, начинающихся с заглавных букв, недопустимо в любой схеме именования.Я до сих пор сталкивался.

0 голосов
/ 23 февраля 2012

Есть пара проблем с вашим кодом.

Во-первых, это ваша проблема. Указатель, который вы передаете insert, передается копией; функция получает копию и main не видит ваших изменений. Решением этой проблемы является передача указателя на указатель. См. Функцию POSIX strtol для примера стандартной библиотеки того, как это выглядит.

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

Итак, исправление:

 int main(int argc, const char* argv[] )
 {
    struct node * initialpointer=NULL;
    insert("asd", &initialpointer, 1);
    if(initialpointer!=NULL)
        printf("isnotnull");
    if (initialpointer==NULL)
        printf("isnull");
 }
 insert(char* x,struct node ** initialpointer, int numberofelements){
    struct node *B;
    B = (struct node*)malloc(sizeof(struct node));
    B->word = x;
    B->parent = NULL;
    B->leftchild = NULL;
    B->rightchild = NULL;
    printf("%d", 12);
    if ( *initialpointer == NULL){
       *initialpointer = B;
       B->parent = NULL;
    }
 }
0 голосов
/ 23 февраля 2012

Отредактировано за комментарий @Paul Mitchell.

 int main(int argc, const char* argv[] )
 {
    struct node* initialpointer = insert("asd");
    if ( initialpointer == NULL )
       /* handle the error */

    /* remember to free() all the allocated nodes */
 }


 struct node* insert(char* x)
 {
    struct node* initialpointer = (struct node*)malloc(sizeof(struct node));
    if ( initialpointer == NULL)
        return NULL;  

    initialpointer.word = x;
    initialpointer.parent = NULL;
    initialpointer.leftchild = NULL;
    initialpointer.rightchild = NULL;
    return initialpointer;
 }

Это позволит выделить один узел (я удалил параметр numberofelements).

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

0 голосов
/ 23 февраля 2012
struct node * initialpointer=NULL;
insert("asd", &initialpointer, 1);
...
void insert(char* x,struct node ** initialpointer, int numberofelements){
...
if ( *initialpointer == NULL){
    *initialpointer = &B;

Но имейте в виду, что это также не будет работать с вашей текущей B как автоматической (локальной) переменной.

Вы должны malloc() B.

И в вашем выражении if отсутствует ветвь else.

...