Матрица доступа Ansi C - PullRequest
       17

Матрица доступа Ansi C

2 голосов
/ 06 февраля 2012

Почему последний printf в основной функции не выводит на экран значение 10?Я знаю, что в ANSI C статически расположенная матрица размещается в памяти следующим образом: matrix: matrix [0] [0], matrix [0] [1], ..., matrix [0] [ColumnsDimension-1],матрица [1] [0] и т. д.

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

#define dimRighe 20
#define dimColonne 30

int main()
{
    int matrice[dimRighe][dimColonne]; 
    int i,j;
    for(i=0;i<dimRighe;i++)
        for(j=0;j<dimColonne;j++)
            matrice[i][j] = i+j; 
    matrice[0][3] = 10; 
    i = 0; j = 3;
    printf("%d",*matrice[i*dimColonne+j]); 
    return 0;
}

Ответы [ 5 ]

3 голосов
/ 07 февраля 2012

Используйте *(matrice[i * dimColonne] + j) вместо.

1 голос
/ 07 февраля 2012

Измените

printf("%d",*matrice[i*dimColonne+j]);  

на просто

printf("%d", matrice[i][j]);

, если все, что вас беспокоит, - это распечатать правильное значение.В конце концов, именно так вы его и назначили.

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

Во-первых, кроме случаев, когда это операнд sizeof или унарные & операторы, или строковый литерал, используемый для инициализации другого массива в объявлении, выражение типа «массив N-элементов из T» будет заменено («decay to») выражениемвведите «указатель на T», и его значением будет адрес первого элемента массива.Выражение matrice является выражением массива типа "20-элементный массив из 30-элементного массива int";в большинстве случаев он будет преобразован в выражение типа «указатель на массив из 30 элементов int» или int (*)[30].Аналогично, выражение matrice[i] является выражением типа «массив из 30 элементов int», и в большинстве случаев оно будет преобразовано в выражение типа «указатель на int» или int *.

Вот удобная таблица, чтобы запомнить все это:

Declaration: T a[N];

Expression              Type              Decays to
----------              ----              ---------        
         a              T [N]             T *
        &a              T (*)[N]
        *a              T 
      a[i]              T

Declaration: T a[M][N];

Expression              Type              Decays to
----------              ----              ---------
         a              T [M][N]          T (*)[N]
        &a              T (*)[M][N]    
        *a              T [N]             T *
      a[i]              T [N]             T *
     &a[i]              T (*)[N]         
     *a[i]              T
   a[i][j]              T

Во-вторых, операция подписки a[i] определяется как *(a + i);то есть вы вычисляете адрес на основе i количества элементов ( NOT BYTES ) из базового адреса вашего массива и разыменовываете результат.Например, если a является массивом int, то *(a + i) даст вам значение i 'th integer после a.Если an является массивом struct foo, то *(a + i) даст вам значение i 'th struct после a.Арифметика указателя всегда учитывает размер базового типа, поэтому вам не нужно беспокоиться о количестве байтов в смещении.

Та же логика применима к многомерным массивам, вы просто применяете правило рекурсивно для каждого измерения:

    a[i][j] ==   *(a[i] + j) ==    *(*(a + i) + j)
 a[i][j][k] == *(a[i][j]+ k) == *(*(a[i] + j) + k) == *(*(*(a + i) + j) + k)  

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

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

a[i*rows + j] = val;

, но я бы не стал (типы выражений несовпадать чисто).Обратите внимание, что вы умножаете i на количество строк , а не столбцов.

1 голос
/ 07 февраля 2012

В вашем коде у вас есть:

matrice[i*dimColonne+j]

Так как i равно 0, это оценивается как

matrice[j]

Поскольку j равно 3, это означает

matrice[3]

Когда вы печатаете *matrice[3], это эквивалентно печати matrice[3][0], потому что matrice[3] - это массив. И массив распадается на указатель на свой первый элемент.

Но вы вовсе не хотите делать это таким образом. Вы должны просто написать matrice[i][j] и позволить компилятору сделать всю работу.

1 голос
/ 07 февраля 2012

Почему последний printf в основной функции не выводит на экран значение 10?

Потому что matrice - это массив массивов ...
иmatrice[whatever] - это массив (который в большинстве случаев «разлагается» на указатель на его первый элемент)

и *matrice[whatever] - это содержимое первого элемента массива matrice[whatever].

0 голосов
/ 07 февраля 2012

Вы также можете напечатать это так:

char *matrixAsByteArray = (char *) matrice;
char *startIntAddr = matrixAsByteArray + i * dimColonne * sizeof(int) + j * sizeof(int);

int outInt = *startIntAddr | *(startIntAddr + 1) << 8 | *(startIntAddr + 2) << 16 | *(startIntAddr + 3) << 24;
printf("%d", outInt);

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

Это немного излишне, но забавное решение проблемы.

...