Как правильно распределить память для структуры в функции, чтобы вернуть ее значение для последующего использования, и как преобразовать структуру в указатель? - PullRequest
3 голосов
/ 15 августа 2010

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

Это структура, представленная для представления чисел в степени к основанию 32.

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

typedef unsigned int uint32;
typedef struct 
{
  int n;
  uint32* words;
}
foo;

Нам нужно реализовать некоторые функции, например, со следующей подписью:

foo add(foo* a, foo* b);

Как видите, функция принимает два указателя на структуру в качестве параметров и возвращает значение структуры, а не указатель на нее. Это означает, что мне нужно локально создать экземпляр foo и вернуть его.

foo add(foo* a, foo* b)
{
  foo result = {1, malloc(sizeof(uint32))};
  // do something with result
  return result;
}

1) Что-то не так в этой попытке? В моем производственном коде у меня возникают проблемы с доступом к значению возвращаемой структуры: кажется, они изменились после того, как структура была возвращена. К сожалению, я не смог воспроизвести это поведение в более простом приложении, что еще больше беспокоило меня, что я все делаю неправильно. Я также пытался выделить память с помощью malloc для переменной результата, но, похоже, это работает, только если я создаю указатель на foo, что, похоже, не вариант, потому что я не могу вернуть указатель.

2) Я ищу способ привести (возможно, не правильный термин) возвращаемый тип обратно в указатель. Скажем так, у меня есть этот код:

   foo* bar1 = malloc(sizeof(foo));
   bar1->n = 1;
   bar1->words = malloc(bar1->n * sizeof(uint32));
   bar1->words[0] = 4294967295;
   foo* bar2 = malloc(sizeof(foo));
   bar2->n = 1;
   bar2->words = malloc(bar2->n * sizeof(uint32));
   bar2->words[0] = 21;
   foo bar3 = add(bar1, bar2);

Работает нормально. Как я могу теперь использовать значение bar3 для повторного вызова функции добавления. Как это:

   foo bar4 = add(bar1, bar3);

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

Ответы [ 3 ]

4 голосов
/ 16 августа 2010

1) Для доступа к возвращенной структуре вам нужно всего лишь сделать что-то вроде:

 printf("[bar3] n %d words %d\n", bar3.n, *(bar3.words));

2) Чтобы снова передать bar3 в функцию add.Вам нужно передать адрес памяти bar3, который можно получить с помощью оператора &:

   foo bar4 = add(bar1, &bar3);

или

foo bar3_p = &bar3;
foo bar4 = add(bar1, bar3_p);

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

2 голосов
/ 16 августа 2010

Вы ищете адрес оператора, &. & foo3 вернет указатель на foo3.

1 голос
/ 16 августа 2010

Обновление Я забрал свое предыдущее объяснение.Я пропустил ваш код через valgrind, и вы действительно не производите утечек или неправильных обращений к памяти.Как у вас есть, структура возвращается по значению, поэтому она возвращается в новую структуру по возвращении.Единственное, что вам нужно будет сделать, это free() указатель words, когда вы закончите.

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

Вам необходимо вернуть указатель на foo:

foo* add (foo* a, foo* n) {
  foo result* = malloc(...);

  /* do some addition */

  return result;
}

Не забудьте free() foo структуры, полученные таким образом.

Дляпонять причину, по которой ваш путь не работает, рассмотрим время жизни переменных, объявленных в области действия add(): введено

  1. add().
  2. Новый fooСтруктура создается и присваивается переменной result.
  3. Функция add() возвращает и память для переменных в этой области освобождается .
  4. За пределами add() вызывающая сторона получает структуру, хранящуюся в ячейке памяти, которая помечена как неиспользуемая.
  5. Попытки доступа к этой структуре приводят к неопределенным результатам, поскольку память, в которой она расположена, может быть выделена для других данных.

Рассмотрим поток растворенного вещества.Приведенный мною код:

  1. add() введено.
  2. Новая память выделяется в куче, а адрес этой памяти сохраняется в result.
  3. Функция add() возвращает значение result (целое число, указывающее адрес в памяти).
  4. За пределами add() местоположение, на которое указывает result, все еще является выделенным местоположением накуча, и возвращенный указатель может быть безопасно разыменован.
  5. Когда вы закончите со структурой в этом месте, вы вызываете free(result), и это местоположение помечается как неиспользуемое.

Надеюсь, это поможет!Для получения дополнительной информации вы должны выяснить, что такое куча памяти и как работает распределение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...