2015-06-13 13 views
1

Я знаю, что двухмерный массив хранится в памяти как одномерный массив. Итак, следуя той же логике, я пытаюсь передать массив по ссылке с помощью одного указателя, как это делается для 1-мерного массива. Ниже мой код:Как ссылаться на двумерный массив?

#include<stdio.h> 
void display(int *s) 
{ 
    int i,j; 
    for(i=0;i<3;i++) 
    { 
     for(j=0;j<4;j++) 
     { 
      printf("%d ",s[i][j]); 
     } 
     printf("\n"); 
    } 
} 
int main() 
{ 
    int s[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; 
    printf("address of the array is %p\n",s); 
    printf("value is %p\n",*s); 
    int i; 
    printf("address of the repective array is\n"); 
    for(i=0;i<3;i++) 
    { 
     printf("address of the array is %p\n",s[i]); 
    } 
    display(s); 
    return 0; 
} 

Когда я пытаюсь скомпилировать это получить следующее сообщение:

twodarray.c: In function ‘main’: 
twodarray.c:25:2: warning: passing argument 1 of ‘display’ from incompatible pointer type [enabled by default] 
    display(s); 
^
twodarray.c:2:6: note: expected ‘int **’ but argument is of type ‘int (*)[4]’ 
void display(int *s[3]) 
    ^

Когда я запускаю приведенный выше код я получаю сообщение об ошибке ошибки сегментации.

+0

Похоже, что вы инициализировали 2D-массив, но пытались передать его функциям в виде массива 1D. Я мог ошибаться, но –

+0

Да, это 2D-массив, но не является ли 2D-массив таким же, как 1D-массив в памяти? – user2738777

+1

'void display (int * s)' change to 'void display (int s [3] [4])' если вы хотите 'printf ("% d ", s [i] [j]);' – BLUEPIXY

ответ

6

Параметр функция объявлена ​​как имеющая тип int *

void display(int *s) 

в то время как исходный массив передается функции в качестве аргумента имеет тип

int [3][4] 

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

int (*)[4] 

Как вы можете ee int * и int (*)[4] - это два разных типа, и нет никакого неявного преобразования из одного типа в другой.

Кроме того, поскольку параметр функции имеет тип int *, вы не можете писать в функциональном выражении s[i][j]. потому что если применить индексный оператор к этому указателю, как, например, s[i], то это выражение является скалярным объектом типа int. Это не указатель. Таким образом, вы не можете применять индексный оператор во второй раз.

Вы должны явно указать аргумент в тип параметра в вызове функции. Например

display((int *)s); 

Что вы хотите следующий вывод

#include <stdio.h> 

void display(int *a, size_t m, size_t n) 
{ 
    for (size_t i = 0; i < m; i++) 
    { 
     for (size_t j = 0; j < n; j++) 
     { 
      printf("%2d ", a[i * n + j]); 
     } 
     printf("\n"); 
    } 
} 

int main(void) 
{ 
    int a[3][4] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }; 

    printf("The address of the array is %p\n", (void *)a); 

    printf("The address of the first row is %p\n", (void *)*a); 

    printf("The address of the respective array rows are\n"); 
    for (size_t i = 0; i < 3; i++) 
    { 
     printf("address of row %zu is %p\n", i, (void *)a[i]); 
    } 

    display((int *)a, 3, 4); 

    return 0; 
} 

Программа может выглядеть следующим образом

The address of the array is 0xbf85d2dc 
The address of the first row is 0xbf85d2dc 
The address of the respective array rows are 
address of row 0 is 0xbf85d2dc 
address of row 1 is 0xbf85d2ec 
address of row 2 is 0xbf85d2fc 
1 2 3 4 
5 6 7 8 
9 10 11 12 

Хотя было бы лучше, чтобы объявить функцию следующим образом, что во избежание ненужного литья и выполнения сложной функции

void display(int (*a)[4], size_t m); 
2

Массив типа int[3][4] не подлежит преобразованию в указатель типа int** или int *[] или int*.

Проблема заключается в том, что

int s[3][4]; 

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

Таким образом, вы должны изменить свою функцию:

void display(int (*s)[4]) 

или использовать более гибкий метод (Passing multidimensional arrays as function arguments in C).

+0

Итак, в этом случае s будет указывать на первый вспомогательный массив, правильно? – user2738777

+0

Правильно, указатель на первую строку. Для получения дополнительной информации вы можете посмотреть http://stackoverflow.com/q/13554244/3235496. 'int (* ptr) [4] = s' первая строка (адрес' s [0] [0] '). '++ ptr' вторая строка (адрес' s [1] [0] '). – manlio

2

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

Вы можете технически вызвать функцию display(), нажимая указатель на int*. Это не сильно поможет, поскольку внутри функции она индексируется в двух измерениях, а компилятор понятия не имеет, что такое размеры.

Подумайте об этом так: если вы выделили линейный блок памяти 100 ints, значит ли это массив размером 10x10, 2x50 или 4x25? Невозможно узнать, поэтому вы не можете индексировать его как двумерный массив. Более того, даже не может быть известно, насколько большой блок памяти.

Вы можете, однако, проиндексировать его как одномерный массив и умножить индекс вручную на s[i*4+j]. Это работает, потому что, как сказано, статический массив хранится линейно в памяти, и вы вручную рассказываете, как его читать.

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

-1

2 мерных массива хранятся в строке памяти. Итак, сначала будет сохранен элемент массива s [0] [0], затем s [0] [1], s [0] [2], s [0] [3], s [1] [0]. Аналогичным образом.

Вы приняли указатель на одномерный массив в вызываемой функции в качестве аргумента. Все, что вы можете сделать, это изменить printf ("% d", s [i] [j]); заявление на printf ("% d", * (s + i + j)); это будет работать.

Последняя инструкция printf должна быть отредактирована для printf ("% d", * (s + 4 * i + j)); как это было предложено ниже.

+1

Этого не будет, 's + i + j' не хватает множителя для одного из индексов. –

+0

Pls видит циклы for, которые реализуются в коде, вы узнаете, как это будет работать. –

+0

Да, петли идут как 0..2 и 0..3, поэтому, если вы просто добавите их, вы получите 0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4 , 5 ... (а не мой нисходящий ответ, просто хочу сказать) –

Смежные вопросы