передача указателя двумерного массива в функцию в C - PullRequest
0 голосов
/ 24 октября 2018

Я пытаюсь передать адрес двумерного массива в функцию в C. Я инициализирую двумерный массив как:

const int N = 3;
char t[N][N];

Я пытаюсь преобразовать это в символ ***:

char*** t_ptr = &t;

Но происходит сбой с:

warning: initialization from incompatible pointer type

Функция, которую я хочу получить, имеет прототип, такой как:

void f(char*** t, int N) { ... };

Что я делаюнеправильно?Спасибо.

Ответы [ 3 ]

0 голосов
/ 24 октября 2018
char t[N][N];

фактически совпадает с

char t[N * N];

в памяти.Указатель на такой массив в обоих случаях будет иметь тип char *.

char *** - указатель на указатель, то есть указатель на символ, тогда как char * - указатель наchar и вот как вы передаете ссылки на массивы в C: вы передаете их как указатель на первый элемент этого массива, и этот первый элемент является char.

C не может сохранить точный тип или структуру массива каккак только вы передадите его функциям.В памяти массив символов - это просто набор памяти, заполненный символами, и все, что вы можете передать, - это указатель на эту память.Если эта память char [] или char [][] или даже char [][][] не играет никакой роли, в памяти все три представляют собой блок, полный символов, и функция должна была бы явно знать структуру в памяти, в противном случае все массивы символов всегда будутchar [] для функции.

Я настоятельно рекомендую новичкам в C использовать многомерные массивы.Вместо

char t[N][N];
char c = t[y1][x1];
t[y2][x2] = 'X';

используйте

char t[N];
char c = t[y1 * N + x1];
t[y2 * N + x2] = 'X';

Так как это в основном то, что компилятор все равно будет делать внутри.

Обратите внимание, что многомерные массивы в C не xy, а yxпервое значение - это строка, второе - в столбце. см. этот урок .

Кто не поверит тому, что я только что сказал, попробуйте этот код:

int main ( ) {
    char a[5][5];
    for (int y = 0; y < 5; y++) {
        for (int x = 0; x < 5; x++) {
            a[y][x] = x + 10 * y;
        }
    }

    for (int y = 0; y < 5; y++) {
        for (int x = 0; x < 5; x++) {
            printf("%02d ", a[y][x]);
        }
        printf("\n");
    }

    printf("------\n");

    char * a2 = (char *)a;
    for (int y = 0; y < 5; y++) {
        for (int x = 0; x < 5; x++) {
            printf("%02d ", a2[y * 5 + x]);
        }
        printf("\n");
    }
}

Вы можете запустить его онлайн , если хотите, вывод идентичен.Также взгляните на ассемблерный код, сгенерированный компилятором для любого цикла (например, gcc -S), и вы увидите, что он почти идентичен, поскольку даже в первом случае компилятор использует инструкции add и mul для доступа к правильномуячейка памяти в массиве.

0 голосов
/ 24 октября 2018

Для чтения объявлений c вы можете посетить: https://cdecl.org/

Теперь, используя пример массива @ Achal:


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

int main()
{
    // t is a 2D array (not a VLA)

    char t[3][3] =
    {
        {'a', 'b', '\0'},
        {'d', 'e', '\0'},
        {'g', 'h', '\0'}
    };
    printf("t is composed of 3 arrays of 3 characters each,\n");
    printf("with the following addresses (on my machine):\n");
    printf("--------------------------------------------------\n");
    printf("%p, %p, %p\n", t[0], t[1], t[2]);


// ------------------------------------------------
    // p is an array of 3 char pointers or char*
    // Notice initialization
    char* p[3] = {t[0], t[1], t[2]};
    // following line of code will break, if no '\0' is encountered
    // since %s requires a char* and a null terminator

    printf("\nPrint strings using p:\n");
    printf("------------------------\n");
    printf("%s, %s, %s\n", *p, *(p + 1), *(p + 2));

// ------------------------------------------------
    // q is a pointer to a char* or q has type char**
    // Notice initialization of q (q points to p)

    char** q = p;
    printf("\nUsing q:\n");
    printf("-----------\n");
    printf("%s, %s, %s\n", *q, *(q + 1), *(q + 2));

// ---------------- printing characters individually
    printf("\nIndividually:\n");
    printf("---------------\n");
    for(int i = 0; i < 2; i++)
    {
        for(int j = 0; j < 2; j++)
        {
            printf("%c ",
                  *(*(q + i) + j)
                   );
        }
        printf("\n");
    }
// -----------------------------------------------
    // r is a pointer to an array of size 3 containing char
    // r advances three char at a time (r doesn't know the size of t)

    char (*r)[3] = t;   // this is the type of t
    printf("\nUsing r:\n");
    printf("---------------\n");
    printf("%p, %p, %p\n", *r, *(r + 1), *(r + 2));

    // to extract chars
    printf("%c, %c", *(*(r + 0) + 0), *(*(r + 2) + 1));
// -----------------------------------------------

    return EXIT_SUCCESS;
}

Вывод:

t is composed of 3 arrays of 3 characters each,
with the following addresses (on my machine):
--------------------------------------------------
000000000022FE2F, 000000000022FE32, 000000000022FE35

Print strings using p:
------------------------
ab, de, gh

Using q:
-----------
ab, de, gh

Individually:
---------------
a b
d e

Using r:
---------------
000000000022FE2F, 000000000022FE32, 000000000022FE35
a, h
Process returned 0 (0x0)   execution time : -0.000 s
Press any key to continue.

0 голосов
/ 24 октября 2018

Это

char*** t_ptr = &t;

неправильно, как указал компилятор, потому что t - это двумерный массив, а не тройной указатель, такой как char***, используйте указатель на массив , чтобы указать наЭто.Например,

char t[3][3] = { "ab","de","gh"}; /* total 3 1D array & each 1D array has 3 elements */
char (*t_ptr)[3] = t; /* t_ptr is a pointer to an array, pointing to 3 elements at a time */

И вы можете напечатать t_ptr как

for(int index = 0; index < 3 ; index++) {
        printf("%s\n",t_ptr[index]);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...