Выделение памяти для структурированного указателя - PullRequest
2 голосов
/ 22 апреля 2020

Недавно обрабатывал это упражнение:

Подсчет размера каждого элемента в массиве. Создайте функцию my_count_on_it, которая получает массив строк в качестве параметра и возвращает массив с длиной каждой строки.

Структуры:

typedef struct s_string_array {
    int size;
    char **array;
} string_array;

typedef struct s_integer_array {
    int size;
    int *array;
} integer_array;

Итак, правильный ответ было:

#include <string.h>

integer_array *my_count_on_it(string_array *a) {
    integer_array *ptr;

    ptr = (integer_array *)malloc(sizeof(integer_array));
    ptr->size = a->size;
    ptr->array = (int*)malloc(ptr->size * sizeof(int));

    for (int i = 0; i < a->size; i++) {
        ptr->array[i] = strlen(a->array[I]);
    }

    return ptr;
}

Я знаю, что указатель хранит адрес некоторой переменной, но я не могу понять, почему в этом случае я не могу создать тип переменной integer_array и выполнять все операции (в l oop) с ним, и только потом хранить его адрес в integer_array * ptr? и еще один вопрос, если так, почему мы создаем указатель sizeof(integer_array)?

Например:

int variable = 5;
int *ptr = &variable;

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

1 Ответ

3 голосов
/ 22 апреля 2020

, почему в этом случае я не могу создать тип переменной integer_array и выполнить все операции (в l oop) с ним, и только затем сохранить его адрес в integer_array * ptr?

Это было бы неверно. Если вы создаете локальную переменную , например, так:

integer_array* my_count_on_it(string_array* a) {
    integer_array local_arr;

    // ...

    return &local_arr;
}

Тогда вы не сможете вернуть указатель на нее, потому что эта переменная действительна только до тех пор, пока не вернется функция, в которой она была определена. Он находится в стеке функции, и стек функции становится недействительным, когда функция возвращается. Поэтому возвращать что-то вроде &local_arr неверно, поскольку это относится к некоторой памяти, которую не следует использовать после возврата из функции (это также неопределенное поведение). Правильный способ сделать это - использовать malloc(), который выделяет память в куче, которая может использоваться в любом другом месте программы и не освобождается автоматически (вы должны сделать это вручную, используя free()).

если так, почему мы создаем указатель sizeof(integer_array)?

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

Запутанная вещь в первом коде - мне кажется, что мы создаем только указатель, который не указывает на какой-либо адрес.

Первоначально, когда объявлено, указатель не указывает на что-то допустимое. Затем, после того, как вы сделаете это:

ptr = malloc(sizeof(integer_array));

Указатель теперь указывает на некоторый адрес в куче, который является действительным. По этому адресу malloc() зарезервировал достаточно места для хранения переменной размера вашей integer_array структуры.

=== Before malloc(): =========================

ptr = ????? -------> INVALID

=== After malloc(): ==========================

                      Memory
                      |   ...         | ...
ptr = 0x120 ------->  +---------------+ 0x120
                      | space for     | 
                      | integer_array |
                      +---------------+ 0x128
                      |   ...         | ...

Еще одна вещь: приведение возвращаемого значения malloc() не нужно и неправильно, см. здесь для объяснения.

...