Как я могу выделить память и возвратить ее (через параметр указателя) к функции вызова?

Если у вас есть Nested Hash (Хэш внутри хэш-формата) в качестве элементов массива (такая структура, как следующая), и вы хотите отсортировать ее по ключу (дата здесь)

data =  [
    {
        "2018-11-13": {
            "avg_score": 4,
            "avg_duration": 29.24
        }
    },
    {
         "2017-03-13": {
            "avg_score": 4,
            "avg_duration": 40.24
        }
    },
    {
         "2018-03-13": {
            "avg_score": 4,
            "avg_duration": 39.24
        }
    }
]

Использовать метод sort_by 'Array как

data.sort_by { |element| element.keys.first }
32
задан a_m0d 9 September 2009 в 08:37
поделиться

10 ответов

Вы хотите использовать указатель на указатель:

void someFunction (int **data) {
  *data = malloc (sizeof (int));
}

void useData (int *data) {
  printf ("%p", data);
}

int main () {
  int *data = NULL;

  someFunction (&data);

  useData (data);

  return 0;
}

Почему? Итак, вы хотите изменить свой указатель data в основной функции. В C, если вы хотите изменить что-то, что передается в качестве параметра (и чтобы это изменение отображалось в версии вызывающего абонента), вы должны передать указатель на то, что вы хотите изменить. В данном случае это «что-то, что вы хотите изменить» является указателем - поэтому, чтобы иметь возможность изменить этот указатель, вы должны использовать указатель на указатель ...

Обратите внимание, что помимо вашей основной проблемы , в коде была еще одна ошибка: sizeof (data) дает вам количество байтов, необходимое для хранения указателя (4 байта в 32-битной ОС или 8 байтов в 64-битной ОС), в то время как вам действительно нужно количество байтов, необходимое для хранения того, что указывает указатель на ( int , т.е. 4 байта в большинстве операционных систем). Поскольку обычно sizeof (int *)> = sizeof (int) , это, вероятно, не вызвало бы проблемы, но об этом следует помнить. Я исправил это в приведенном выше коде.

Вот несколько полезных вопросов по указателям на указатели:

Как указатель на указатели работает в C?

Использование для нескольких уровней разыменования указателей?

]
60
ответ дан 27 November 2019 в 20:12
поделиться

Для простоты позвольте мне назвать вышеупомянутый единственный параметр указателя p и двойные стр указателя (указывающий p).

В функции, объект, на который указывает p, может быть изменен, и изменение выходит из функции. Однако, если сам p изменяется, изменение не оставляет функцию.

, К сожалению, malloc по его собственному характеру, обычно p изменений. Именно поэтому исходный код не работает. Исправление (58) использование стр указателя, указывающие p. в исправленной функции, p, изменяется, но стр не. Таким образом это работало.

0
ответ дан 27 November 2019 в 20:12
поделиться

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

int *data = NULL;
//data is passed by value here.
someFunction (data); 
//the memory allocated inside someFunction  is not available.

Указатель на указатель или возврат выделенного указателя решат проблему.

void someFunction (int **data) {
  *data = (int *) malloc (sizeof (data));
}


int*  someFunction (int *data) {
  data = (int *) malloc (sizeof (data));
return data;
}
2
ответ дан 27 November 2019 в 20:12
поделиться

Вы должны передать указатель на указатель, если хотите изменить указатель.

т.е. :

void someFunction (int **data) {
  *data = malloc (sizeof (int)*ARRAY_SIZE);
}

редактировать: Добавлен ARRAY_SIZE, в какой-то момент вам нужно знать, сколько целых чисел вы хотите выделить.

4
ответ дан 27 November 2019 в 20:12
поделиться

someFunction () принимает свой параметр как int *. Поэтому, когда вы вызываете его из main (), создается копия переданного вами значения. Все, что вы изменяете внутри функции, является этой копией, и, следовательно, изменения не будут отражены снаружи. Как предлагали другие, вы можете использовать int **, чтобы изменения отражались в данных. Другой способ сделать это - вернуть int * из someFunction ().

2
ответ дан 27 November 2019 в 20:12
поделиться

Здесь вы пытаетесь изменить указатель, т.е. с "data == Null" на "data == 0xabcd "какая-то другая память, которую вы выделили. Итак, чтобы изменить данные, вам необходимо передать адрес данных, то есть & data.

void someFunction (int **data) {
  *data = (int *) malloc (sizeof (int));
}
0
ответ дан 27 November 2019 в 20:12
поделиться

Помимо использования метода двойного указателя, если требуется только 1 возвращаемый параметр, перезапишите его следующим образом:

 int *someFunction () {
   return (int *) malloc (sizeof (int *));
 }

и используйте его:

 int *data = someFunction ();
2
ответ дан 27 November 2019 в 20:12
поделиться

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

Return void * , поэтому его можно использовать для любого типа распределения.

void *someFunction (size_t size) {
    return  malloc (size);
}

и использовать его как:

int *data = someFunction (sizeof(int));
0
ответ дан 27 November 2019 в 20:12
поделиться

Отвечая на ваш дополнительный вопрос, который вы отредактировали in:

'*' обозначает указатель на что-либо. Таким образом, '**' будет указателем на указатель на что-то, '***' указателем на указатель на указатель на что-то и т.д.

Обычная интерпретация 'int ** data' (если данные не параметр функции) будет указателем на список массивов int (например, 'int a [100] [100]').

Итак, вам нужно сначала выделить ваши массивы int (я использую прямой вызов malloc () для простоты):

data = (int**) malloc(arrayCount); //allocate a list of int pointers
for (int i = 0; i < arrayCount; i++) //assign a list of ints to each int pointer
   data [i] = (int*) malloc(arrayElemCount);
0
ответ дан 27 November 2019 в 20:12
поделиться

Вот общий шаблон для выделения памяти в функции и возврата указателя через параметр:

void myAllocator (T **p, size_t count)
{
  *p = malloc(sizeof **p * count);
}
...
void foo(void)
{
  T *p = NULL;
  myAllocator(&p, 100);
  ...
}

Другой метод - сделать указатель возвращаемое значение функции (мой предпочтительный метод):

T *myAllocator (size_t count)
{
  T *p = malloc(sizeof *p * count);
  return p;
}
...
void foo(void)
{
  T *p = myAllocator(100);
  ...
}

Некоторые примечания по управлению памятью:

  1. Лучший способ избежать проблем с управлением памятью - избегать управления памятью; не возитесь с динамической памятью, если она вам действительно не нужна.
  2. Не приводите результат malloc (), если вы не используете реализацию, предшествующую стандарту ANSI 1989 года, или если вы не собираетесь компилировать код как C ++. Если вы забыли включить stdlib.h или у вас нет прототипа для malloc () в области видимости, приведение возвращаемого значения подавит ценную диагностику компилятора.
  3. Используйте размер выделяемого объекта вместо размера типа данных (т. Е. sizeof * p вместо sizeof (T) ); это избавит вас от изжоги, если тип данных должен измениться (скажем, с int на long или float на double). Это также делает код читаемым немного лучше. IMO.
  4. Изолировать функции управления памятью за функциями выделения и освобождения более высокого уровня; они могут обрабатывать не только распределение, но также инициализацию и ошибки.
1
ответ дан 27 November 2019 в 20:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: