Как правильно выделить память для указателя массива, переданного в качестве аргумента в C - PullRequest
0 голосов
/ 07 января 2020

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

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

int fillarray(/* pointer to an array */){

    // malloc the array to size n
    // fill array with n elements

return n;
}

int main(){

    int* array = NULL;
    int size = fillarray(/* pass the pointer by reference */);

    for(int i = 0; i < size; i++) printf("%d\n", array[i]);

    free(array);

return 0;
}

ОБНОВЛЕНИЕ:

Спасибо всем за ваши комментарии. Я многое узнал об указателях, решающих эту проблему. Код ниже выполняет то, что мне нужно. Спасибо, @Lundin. Ваш ответ привел меня к фактическому решению. Спасибо @ssd также. Ваша картинка помогла мне получить некоторую интуицию о том, что я смотрю в коде.

int fillarray(int** array){

    *array = (int*)malloc(2 * sizeof(int));
    (*array)[0] = 0;
    (*array)[1] = 1;

return 2;
}

int main(){

    int* array = NULL;
    int size = fillarray(&array);
    for(int i = 0; i < size; i++) printf("%d\t", array[i]);

return 0;
}

Ответы [ 2 ]

3 голосов
/ 07 января 2020

Строго говоря, в C нет «ссылок», все передается по значению. Хотя термин «передача по ссылке» относится к языку c и на самом деле означает просто передать адрес данным. (У C ++ есть концепция языка, называемая ссылками, но на самом деле это просто прославленные указатели только для чтения.)

Итак, чтобы достичь того, что вы хотите, вы должны передать адрес самого указателя. Таким образом, функция может получить доступ к указателю и установить его, чтобы он указывал на новый адрес. Таким образом, объявите функцию как int fillarray (int**), вызовите функцию как fillarray(&array). Результат mallo c должен быть назначен туда, куда указывает указатель на указатель - он указывает на адрес исходного указателя, объявленного переменной в main ().

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

1 голос
/ 07 января 2020

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

  • Первый целочисленный указатель ниже (int *a) находится по адресу памяти 4c4b40, и его значение установлено в ноль (что означает, что этот указатель a установлен в null).

  • Второй целочисленный указатель (int *b) находится по адресу памяти 4c4b48, а его значение установлено на 4c4b58 (что означает, что этот указатель указывает на адрес памяти 4c4b58 с длиной целого числа) , Если этот адрес соответствует переменной int x = 16 (шестнадцатеричный 10 равен 16), то разыменование указателя b даст целочисленное значение 16 (*b = 16, потому что x = 16).

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

Возвращаясь к ответу:

Если вы измените адрес первого указателя (a), чтобы он указывал на переменную x, тогда вызываемая функция должна получить адрес указателя (а не самого указателя); т.е. &a вместо a, что соответствует 4c4b40. Вызванная функция получит адрес 4c4b40 в качестве адреса памяти и изменит его значение с 000000 на 4c4b58. Функция украшения, конечно, будет содержать int **; для, если целочисленный указатель равен int *, указатель на указатель будет равен int **.

enter image description here

...