Вопрос

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

Это какой-то выборки (очень упрощенный):

...
some_struct s;
printf("Before: %d\n", &s);
allocate(&s);
printf("After: %d\n", &s);
...

/* The allocation function */
int allocate(some_struct *arg) {

arg = malloc(sizeof(some_struct));
printf("In function: %d\n", &arg);

return 0;
}

Это дает мне тот же адрес до и после распределения-звонка:

Before: -1079752900
In function: -1079752928
After: -1079752900

Я знаю, что это, вероятно, потому что это делает копию в функции, но я не знаю, как на самом деле работать над указателем, который я дал в качестве аргумента. Я попытался определить quote_struct * s вместо quey_struct s, но не повезло. Я пытался с:

int allocate(some_struct **arg)

который работает просто отлично (также необходимо изменить функцию выделения), но в соответствии с заданием, я могу не изменить декларацию, и это должно быть * arg .. и было бы наиболее правильно, если бы я просто должен объявить quey_struct s .. не какие-то_struct * s. Цель функции распределения состоит в том, чтобы инициализировать структуру (a a avere_struct), который также включает в себя выделение его.

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

Это было полезно?

Решение

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

   int allocate(some_struct *arg) 
   /* we're actually going to pass in a some_struct ** instead. 
      Our caller knows this, and allocate knows this.  */
   { 
      void *intermediate = arg;  /* strip away type information */
      some_struct **real_deal = intermediate;  /* the real type */
      *real_deal = malloc(sizeof *real_deal); /* store malloc's return in the 
                                                 object pointed to by real_deal */
      return *real_deal != 0;  /* return something more useful than always 0 */
   }

Тогда ваш абонент делает то же самое:

   {
      some_struct *s; 
      void *address_of_s = &s; 
      int success = allocate(address_of_s); 
      /* what malloc returned should now be what s points to */
      /* check whether success is non-zero before trying to use it */
   }

Это зависит от правила в C, которое говорит, что любой указатель на объект может быть неявно преобразован в пустотный указатель, и наоборот, без потерь.

Обратите внимание, что формально это не определено, но все это, но наверняка работать. Хотя любое значение указателя объекта требуется, чтобы иметь возможность преобразовать в A void* и обратно без потерь, на языке нет ничего, что гарантирует, что some_struct* может хранить A. some_struct** без потери. Но это имеет очень высокую вероятность работы просто в порядке.

Ваш учитель не дал вам вариант, а писать формально нелегальный код. Я не вижу, что у вас есть другой вариант, помимо «обмана», как это.

Другие советы

Как правило, я бы вернул указатель от allocate:

void * allocate()
{
    void * retval = malloc(sizeof(some_struct));
    /* initialize *retval */
    return retval;
}

Если вы хотите вернуть его в параметр, вы должны пройти указатель на параметр. Поскольку это указатель на aw_truct, вы должны пройти указатель на указатель:

void allocate (some_struct ** ret)
{
    *ret = malloc(sizeof(some_struct));
    /* initialization of **ret */
    return;
}

быть вызванным как

some_struct *s;
allocate(&s);
int func(some_struct *arg) {
    arg = malloc(sizeof(some_struct));
    ... 
}

Здесь вы просто назначаете результат malloc к локальному arg Переменная. Указатели передаются по значению в C, копия указателя передается на функцию. Вы не можете изменить указатель абонента таким образом. Имейте в виду разницу у указателя и что он указывает.

У вас есть различные варианты:

Верните указатель из функции:

 some_struct *func(void) {
    arg = malloc(sizeof(some_struct));
    ...
    return arg;
}
...
some_struct *a = func();

Выделить структуру в звоняще:

 int func(some_struct *arg) {
    ...
    arg->something = foo;

}
... 
some_struct a;
func(&a);

Или динамически распределять это

some_struct *a = malloc(sizeof *a);
func(a);

Используя указатель на указатель звонящих:

 int func(some_struct **arg) {
    *arg = malloc(sizeof **arg);

}
... 
some_struct *a;
func(&a);

Используйте глобальную переменную (уродливый ..)

 some_struct *global;
 int func(void) {
    global = malloc(sizeof *global);

}
 ... 
some_struct *a;
func();
a = global;

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

some_struct *s;
printf("Before: %d\n", s");
allocate(&s);
printf("After: %d\n", s");
...

/* The allocation function */
int allocate(some_struct **arg) {

*arg = malloc(sizeof(some_struct));
printf("In function: %d\n", *arg");

return 0;
}

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

Ну, C использует Pass-by-value, что означает, что функции получают копии их аргументов, и любые изменения, внесенные в эти копии, не влияют на оригинал в вызывающем абонете.

/* The allocation function */
int allocate(some_struct *arg) {

arg = malloc(sizeof(some_struct));
printf("In function: %d\n", &arg");

return 0;
}

Здесь вы проходите по адресу вашего quote_struct s. Затем вы отказываетесь от этого адреса и замените его тем, что было возвращено MALLOC. Тогда вы возвращаетесь, и возвращаемое значение malloc теряется навсегда, и вы просочивали память. И ваш quey_struct s не был изменен. У него все еще есть какое-либо случайное число, на которое он был инициализирован, который вы напечатали.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top