Требуется помощь в понимании 2d массива и передаче его в функции - PullRequest
0 голосов
/ 18 июня 2019

Прежде всего, я прошел по этим ссылкам, чтобы лучше понять многомерные массивы и как передать их в функции
https://stackoverflow.com/a/17569578/10452758
http://c -faq.com / aryptr / pass2dary.html
https://jameshfisher.com/2016/12/08/c-array-decaying/

У меня все еще есть некоторая неясность, связанная с этими вещами, о которой я хотел бы спросить

Предположим, у нас есть двумерный массив, подобный

int mat[][COLS] = {{...}}

i) Мы знаем, что мы можем передать mat в функцию, если ее размер фиксирован, т.е. известен во время компиляции как int (*mat)[COLS] функции. Здесь mat упоминается как один указатель на целочисленный массив, т.е. он указывает на целый целочисленный массив, тогда mat в основной функции, как определено выше, будет упоминаться как тот же, то есть один указатель на целочисленный массив или это вообще не указатель ??? Но печать mat в консоли выдает адрес, так что в основном это указатель.
Как и в случае int arr[] = {}, мы говорим, что arr - это адрес первого элемента, что можно сказать о mat.

Я понимаю разницу между ч / б mat и mat[0], но почему указатель, указывающий на весь массив, и указатель, указывающий на первый элемент массива, имеют одинаковое значение. Как в случае разыменования указатель, кто-то знает, что это указатель на первый элемент или весь массив ???
Я знаю, что вопрос звучит немного расплывчато, но просто хочу знать, почему mat и mat[0] указывают на один и тот же адрес памяти, потому что, если они означают разные вещи, они не будут иметь разные значения ???

Если кто-то может поделиться тем, что он знает о том, что mat называет указателем, это будет очень полезно. Я прочитал другие ТАК вопросы по этим темам , но эти вещи до сих пор со мной не щелкнули.

ii) Мы знаем, что массивы в C в основном не являются указателями, но когда мы получаем доступ к значению массива, он уменьшается до значения типа указателя. В общем, я хотел бы спросить: не является ли указатель в int arr[] = {...}, arr указателем, и я хочу поддержать его с помощью sizeof(arr)!=size_occupied_by_pointer, в том случае, когда мы определяем mat и когда мы печатаем их в консоли, Упущенные значения указателя упоминаются. Это ответ на первый вопрос ???

iii) Другое сомнение, которое у меня есть, - передача матрицы в качестве указателя на указатель. Это код, которому я стремлюсь следовать, но это приводит к ошибке сегментации. Если кто-то может указать на ошибку -

void process_pointer_to_pointer(int **arr, size_t rows, size_t cols){
    for (size_t i = 0; i < rows; ++i){
        std::cout << i << ": ";
        for (size_t j = 0; j < cols; ++j)
            std::cout << arr[i][j] << '\t';
        std::cout << std::endl;
    }
}

int main(int argc, char const *argv[]){
    const int m=4, n=4;

    int mat[][n]= {
        {1, 3, 1, 5},
        {2, 2, 4, 1},
        {5, 0, 2, 3},
        {0, 6, 1, 2}
    };
        int *ip = &mat[0][0];
    process_pointer_to_pointer(&ip, m, n);

Я знаю более простой способ сделать то же самое, используя массив указателей и заполнив их mat[i], но я следовал ограничению в следовании этому методу и попробовал этот подход отсюда
http://c -faq.com / aryptr / pass2dary.html
но не получил желаемого результата ...

PS: Вопрос может быть совершенно повсеместным, поэтому, если вы не в состоянии понять что-то конкретное, пожалуйста, спросите меня. Я более чем счастлив идти в режиме дебатов. Кроме того, я новичок в кодировании, поэтому, пожалуйста, немного ослабьте меня. : Р

Ответы [ 2 ]

0 голосов
/ 18 июня 2019

Позволяет поэкспериментировать с некоторыми небольшими программами:

#include <stdio.h>
#include <stdint.h>
int a1[3];
int a2[3][3];
int a3[3][3][3];

void showptr(void *a, void *b) {
    printf("%p, %p, %zd\n", a, b, (intptr_t)b - (intptr_t)a);
}

int main() {
        showptr(a1, a1+1);
        showptr(a2, a2+1);
        showptr(a2[0], a2[0]+1);
        showptr(a3, a3+1);
        showptr(a3[0], a3[0]+1);
        showptr(a3[0][0], a3[0][0]+1);
        return 0;
}

Приведенное выше определяет три массива при увеличении количества измерений и выводит некоторые значения о них. Первый, (a1, a1 + 1), показывает, что добавление единицы к «a1» увеличивает адрес на 4, что является размером с int. Следующие два делают то же самое для a2 и a2 [0]. A2, получается увеличение на 12 (3 дюйма), что является строкой массива. A2 [0], увеличивается на 4 (1 int). Когда мы добираемся до a3, он увеличивается на 36 (3 строки), a3 [0] увеличивается на 12 (3 дюйма, строка) и a3 [0] [0] увеличивается на 4.

Теперь давайте добавим еще несколько в конце основного:

... int * t; t = a1; showptr (т, т + 1); t = a2; showptr (т, т + 1); t = a2 [0]; showptr (т, т + 1); t = a3; showptr (т, т + 1); t = a3 [0]; showptr (т, т + 1); t = a3 [0] [0]; showptr (т, т + 1); ...

Что здесь происходит, интересно, компилятор жалуется на:

a.c:20:4: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]

и это повторяется для строк 22 и 23:

t = a2;
t = a3;
t = a3[0];

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

0 голосов
/ 18 июня 2019

У вас есть пара вариантов.Фактически создайте массив указателей, которые указывают на каждую строку, или вычислите смещение в матрице и обработайте его как одномерный массив целых чисел.Первый способ, которым это было сделано более 30 лет назад, когда умножение было медленнее, чем дополнительный доступ к памяти.Это должно быть сделано, если вы объявляете arr как int **arr

#include <iostream>
using std::cout;

void process_pointer_to_pointer(int** arr, size_t rows, size_t cols) {
    for (size_t i = 0; i < rows; ++i) {
        std::cout << i << ": ";
        for (size_t j = 0; j < cols; ++j)
            std::cout << arr[i][j] << '\t';
        std::cout << std::endl;
    }
}

int main(int argc, char const* argv[]) {
    const int m = 4, n = 4;

    int mat[][n] = {
        {1, 3, 1, 5},
        {2, 2, 4, 1},
        {5, 0, 2, 3},
        {0, 6, 1, 2}
    };

    int* pRows[m];
    for (int i = 0; i < m; i++)
        pRows[i] = mat[i];

    // pRows decays to a pointer to a pointer to an int
    process_pointer_to_pointer(pRows, m, n);
}

. Что теперь обычно делается с массивами переменных размеров, так это вычисление смещения в линейный массив, обычно создаваемый как vector, ноздесь мы используем вашу базу.

#include <iostream>
using std::cout;

void process_pointer_to_pointer(int* arr, size_t rows, size_t cols) {
    for (size_t i = 0; i < rows; ++i) {
        std::cout << i << ": ";
        for (size_t j = 0; j < cols; ++j)
            std::cout << arr[i*cols+j] << '\t';
        std::cout << std::endl;
    }
}

int main(int argc, char const* argv[]) {
    const int m = 4, n = 4;

    int mat[][n] = {
        {1, 3, 1, 5},
        {2, 2, 4, 1},
        {5, 0, 2, 3},
        {0, 6, 1, 2}
    };
    // mat[0] decays to a pointer to int and points to the first int in mat
    process_pointer_to_pointer(mat[0], m, n);
}

Для двумерных массивов, которые имеют постоянные строки / столбцы, предпочтительным подходом является использование std::array.Например:

std::array<std::array<int,4>,4> mat;
mat[2][3]=42;

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

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

Статически объявленный двумерный массив C ++ в качестве члена данных класса

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