2015-04-07 2 views
2

Осмотревшись я построил функцию, которая принимает матрицу и выполняет все, что мне нужно на него следующим образом:Переходя матрица к функции, C

float energycalc(float J, int **m, int row, int col){ 
... 
} 

В основной размер массива определен и заполнен, однако я не могу это проходит мимо самой функции:

int matrix[row][col]; 
... 
E=energycalc(J, matrix, row, col); 

Это приводит предупреждение во время компиляции

"project.c:149: warning: passing argument 2 of ‘energycalc’ from incompatible pointer type project.c:53: note: expected ‘int **’ but argument is of type ‘int (*)[(long unsigned int)(col + -0x00000000000000001)]’

и приводит к ошибке сегментации.

Любая помощь очень ценится, спасибо.

+0

'поплавка energycalc (поплавок J, Int строку, Int COL, Int M [строка] [столбец]) {' – BLUEPIXY

+2

Массив массивов не то же самое, как указатель на указатель, смотри, например, [этот старый мой ответ] (http://stackoverflow.com/a/18440456/440558), чтобы понять, почему. Вы могли бы пройти с указателем на массивы (например, 'int (* m) []'). –

+0

@ legendends2k Вопрос был отмечен только 'C' ... Я узнал, как тяжело, когда Cool Guy жаловался на мой ответ. –

ответ

2

Передача двумерного массива функции в C часто путают для новичков.
Причина в том, что они предполагают, что массивы являются указателями и не имеют понимания того, как массивы распадаются на указатель.
Всегда помните, что при передаче аргументов массивы преобразовывались в указатель на его первый элемент.
В вызове функции

E = energycalc(J, matrix, row, col); 

matrix преобразуется в указатель на его первый элемент, который является matrix[0]. Это означает, что прохождение matrix эквивалентно прохождению &matrix[0]. Обратите внимание, что тип &matrix[0] равен int(*)[col] (указатель на массив col int) и, следовательно, имеет значение matrix. Это предполагает, что второй параметр функции energycalc должен иметь тип int(*)[col]. Измените объявление функции для

float energycalc(int col, int (*m)[col], int row, float J); 

и позвонить функцию

E = energycalc(col, matrix, row, J); 
+1

Или просто объявите параметр указателя как 'int m [row] [col]', что более читаемо. – Lundin

+0

@ Lundin; или 'int m [] [col]'. – haccks

+0

Любая причина, по которой вы хотели бы опустить один из размеров? – Lundin

3

Если массив объявлен как

int matrix[row][col]; 

измените объявление функции на

float energycalc(float J, int m[][col], int row, int col){ 

Название двухмерного массива типа T не распадаться на T**.

Если col является локальной переменной, вам необходимо вызвать функцию с параметром col до matrix. Это делается так, что в функции видна col.

+0

@BLUEPIXY, Извините, я не понял –

+2

см. [DEMO] (http://ideone.com/QarBmz) 'error: 'col' undeclared здесь (не в функции)' – BLUEPIXY

+1

@CoolGuy; С объявлением 'float energycalc (float J, int m [] [col], int row, int col)' компилятор не имеет понятия о 'col', и это приведет к ошибке. Вам необходимо разместить 'col' перед тем, как использовать его в' int m [] [col] '. – haccks

3

Функция должна быть объявлена ​​как

float energycalc(float J, int row, int col, int (*m)[col]); 

если ваш компилятор поддерживает массивы переменной длины.

В противном случае, если в объявлении

int matrix[row][col]; 

col некоторая постоянная, то функция может быть объявлена ​​следующим образом

float energycalc(float J, int m[][col], int row); 

при условии, что постоянное col определяется перед функцией.

Ваше объявление функции

float energycalc(float J, int **m, int row, int col); 

подходит, если у вас есть массив, объявленный как

int * matrix[row]; 

и каждый элемент массива выделяется динамически, как, например,

for (int i = 0; i < row; i++) matrix[i] = malloc(col * sizeof(int)); 
0

I подумайте, что вы можете сделать что-то подобное в C

float function_name(int mat_width, int mat_height, float matrix[mat_width][mat_height]) { 
    ... function body... 
} 
+0

Вы можете, если 'mat_width' и' mat_heigth' являются константами времени компиляции. И если они есть, они должны быть написаны в верхнем регистре (из-за соглашения), а затем это лучший способ сделать это, потому что он четко и недвусмысленно документирует тот факт, что функция ожидает указатель на матрицу N на M , а не просто указатель на случайный тип, не зная, является ли это массивом и каким размером. – Bregalad

+0

@Bregalad Это неправда ... Вы можете mat_width и mat_height быть переменными, и каждый раз вы можете отправлять разные значения ... Я думаю, что это не стандарт C, а расширение. –

+1

@Bregalad Это массивы переменной длины (VLA). Возможно, вы захотите обновить свои знания C до C99, который был выпущен 16 лет назад. – Lundin

0

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

(Путаница, вероятно, исходит от полчищ путаных потенциальных учителей/авторов программирования, говорящих всем, что они должны использовать указатель на указатель при распределении динамических 2D-массивов. Это просто плохие советы, поскольку он не будет выделять реальный массив, выделенный в соседних ячейках памяти, а скорее фрагментированная таблица поиска, разобранная в кусках по всей куче. See this для справки о том, как на самом деле выделять такие массивы.)

Предполагая, что ваш компилятор не является полностью древним , просто используйте массив переменной длины (VLA), который является функцией, введенной на языке C со стандартом C99.

#include <stdio.h> 

void print_matrix (size_t row, size_t col, int matrix[row][col]); 


int main (void) 
{ 
    int matrix[2][3] = 
    { 
    {1,2,3}, 
    {4,5,6} 
    }; 

    print_matrix(2, 3, matrix); 

    return 0; 
} 

void print_matrix (size_t row, size_t col, int matrix[row][col]) 
{ 
    for(size_t r=0; r<row; r++) 
    { 
    for(size_t c=0; c<col; c++) 
    { 
     printf("%d ", matrix[r][c]); 
    } 
    printf("\n"); 
    } 
} 
Смежные вопросы