Передача 1D массива, 2D массивов и массивов указателей - PullRequest
0 голосов
/ 04 июля 2018

Чтобы передать одномерный массив в функцию, мы делаем это:

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

void func(int *arr, int n)
{
    // code here

}

int main()
{
    int arr[] = {......};                   // declare array
    int n = sizeof(arr)/sizeof(arr[0]);
    func(arr);                              // calling function func

    return 0;
}

Чтобы передать двумерный массив в функцию, мы делаем это:

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

void func(int arr[][2])
{
    // code here
    }

int main()
{
    int arr[3][2];  // declare 2D array
    func(arr);      // calling function func

    return 0;
}

Итак, передавая массив указателей в функцию, можем ли мы сделать что-то подобное?

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

void func(int **arr, int n)
{
    // code here

}

int main()
{
    int *arr[] = {......};                // declare array of pointers
    int n = sizeof(arr)/sizeof(arr[0]);
    func(arr, n);                           // calling function func

    return 0;
}

Честно говоря, меня смущают указатели и массивы. Мне потребовалось много времени, чтобы понять, как передать 2D-массив. Я пытался искать другие подобные вопросы, но безрезультатно. Пожалуйста, помогите мне с: Передача массива указателей в функцию. Кроме того, любые ссылки, где я могу убрать путаницу, будут очень благодарны.

Ответы [ 3 ]

0 голосов
/ 04 июля 2018

Честно говоря, меня смущают указатели и массивы. Мне потребовалось много времени, чтобы понять, как передать двумерный массив.

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

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

  • [], оператор индексации, работает путем добавления индекса к заданному указателю и разыменования полученного указателя. Поэтому написание a[5] точно так же, как *(a+5).
  • Это работает даже в том случае, если a является фактическим массивом (а не указателем), потому что массив в большинстве случаев оценивается как указатель на первый элемент (существуют исключения, подобные sizeof оператор). * * тысяча двадцать-одна

Чтобы сделать вещи более сложными, C позволяет объявлять функции, которые выглядят так, как будто они принимают массивы, например Вы можете написать:

void foo(int bar[]);

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

void foo(int *bar);

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


С этим знанием вы можете легко составить правильные примеры для всех ваших случаев:

(1) «Нормальный» массив :

void foo(int bar[], size_t n); // with type adjustment
void foo(int *bar, size_t n);  // what it really means

// call like
int a[5];
foo(a, 5);

(2) 2D массив :

2D-массив - это массив массивов, поэтому его первый элемент сам по себе является массивом -> вы бы передали указатель на массив

void foo(int bar[][10], int n);  // with type adjustment, 2d array of n x 10
void foo(int (*bar)[10], int n); // what it really means

// call like:
int a[5][10];
foo(a, 5);

(3) Массив указателей :

Массив указателей часто используется в качестве альтернативы двумерному массиву - поскольку элементы являются просто указателями, они могут указывать на отдельные значения или массивы различной длины, но недостатком является то, что у вас нет целого данные как один блок в памяти, как в случае с реальным 2d-массивом. Поскольку это просто массив указателей, он очень похож на используемый «обычный» массив:

void foo(int *bar[], int n); // with type adjustment
void foo(int **bar, int n);  // what it really means

// call like:
int *a[5];
foo(a, 5);

Последнее замечание: Вы часто будете читать, что массивы "распадаются как указатели" в C. Это не официальная формулировка, но очень распространенная. Если вы объединяете правило, согласно которому идентификатор массива в большинстве контекстов (например, при передаче его функции) оценивает указатель , с правилом корректировки типа для параметров функции, то в результате синтаксис массива пишется везде , но получите указатели, так что это означает «разложение».

0 голосов
/ 04 июля 2018

На самом деле нет различий между 1-D массивом, 2-D массивом, массивом X-D и массивом указателей. Все они являются просто последовательной областью памяти.

1-D массив:

int arr[8];
int *addr = arr;

| arr[0] | ...*6... | arr[7] |
^                   ^
|                   |
addr                 addr+7

2-D массив:

int arr[4][2]
int *addr = arr[0];

| arr[0][0] | ...*6... | arr[3][1] |
^                      ^
|                      |
addr                   addr+7 

3-D массив:

int arr[2][2][2];
int *addr = arr[0][0];

| arr[0][0][0] | ...*6... | arr[1][1][1] |
^                         ^
|                         |
addr                      addr+7

массив указателей:

typedef pointer int*;
...

int a0[8] = {0, 1, 2, 3, 4, 5, 6, 7};
int a1[7] = {0, 1, 2, 3, 4, 5, 6};
...
int a7[1] = {0};

pointer arr[8] = {a0, a1, a2, a3, a4, a5, a6, a7};
pointer *addr = arr;

| arr[0] = a1 | ...*6... | arr[7] = a7 |
^                        ^
|                        |
addr                     addr+7

Определение массива X-D может быть реализовано следующим образом:

typedef data_type int;

typedef struct X-Array
{
    int d1;
    int d2;
    ...
    int dx;
    data_type *data;
} X-Array;

X-Array *create_X_Array(int d1, int d1, ..., int dx)
{
    X-Array *arr;
    if ((arr = malloc(sizeof(X-Array))) == NULL)
        return NULL;

    if ((arr->data = malloc(sizeof(data_type * d1 * d2 * ... * dx))) == NULL)
    {
        free(arr);
        return NULL;
    }

    arr->d1 = d1;
    arr->d2 = d2;
    ...
    arr->dx = dx;

    return arr;
}
0 голосов
/ 04 июля 2018

В последнем примере у вас есть массив указателей .

И да, это сработало бы, проверьте, например, этот пример игрушки:

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

void func(int **arr, int n) {

    // print equal to arr[0][1] 
    printf("%d %d\n", n, *arr[1]);
}

int main(void) {
    int a = 1, b = 2, c = 3;

    // set the points of a, b, and c, to arr[0][0..2];
    int *arr[] = {&a, &b, &c};
    int n = sizeof(arr)/sizeof(arr[0]);
    printf("%d %d\n", n, *arr[1]);

    func(arr, n);

    return 0;
}

Выход:

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