Extracting a 3x3 excerpt from a 10x10 array and passing it to a function has some complications. The first is that in arrays, all elements are stored in memory sequentially. That is, in a 10x10 matrix we have the 100 elements in sequence. In a 3x3 matrix, we will have the 9 elements in sequence. However, in a 3x3 matrix within a 10x10, the 9 desired elements of the 3x3 will not be in sequence, and therefore can not simply be represented in the form of a simple pointer, which requires a more elaborate technique.
In addition, there are still some problems concerning the processing of one submatrix may end up interfering with the processing of another submatrix when the array elements are changed. For example, imagine that you have the following matrix (I'll use 5x5 to make it easier to understand):
A B C D E
F G H I J
K L M N O
P Q R S T
U V W X Y
If you process sub-matrix ABC-FGH-KLM, you replace G with a Z, the subsequent sub-matrix will be BCD- Z HI-LMN instead of BCD- G HI-LMN.
There are several possible workarounds for this problem. I think the simplest solution to this problem would be:
-
Represent the sub-matrix as indexes of the main matrix.
-
Use two different arrays, one for reading data and one for writing. At the end, the sketch matrix can be copied over the original and then discarded, or else the original can be discarded and the resultant remain.
If I get it right, you want a function that gets another function as a parameter in order to apply it over the entire array. In object-oriented programming languages with generic types such as C ++ and Java, this is much easier to do. This is also possible in C, but with a frightening syntax. Here's the result:
#include <stdio.h>
void conv(int largura, int altura, int linha, int coluna, int original[altura][largura], int resultante[altura][largura]) {
int i, j;
if (linha >= altura - 2 || coluna >= largura - 2) return;
for (i = linha; i < linha + 3; i++) {
for (j = coluna; j < coluna + 3; j++) {
resultante[i][j] = original[i][j] * original[i][j];
}
}
}
void operar(int largura, int altura, int original[altura][largura], int resultante[altura][largura], void (*op)(int largura, int altura, int linha, int coluna, int original[largura][altura], int resultante[altura][largura])) {
int i, j;
for (i = 0; i < altura; i++) {
for (j = 0; j < largura; j++) {
op(largura, altura, i, j, original, resultante);
}
}
}
void imprimir(int largura, int altura, int original[altura][largura]) {
int i, j;
for (i = 0; i < altura; i++) {
for (j = 0; j < largura; j++) {
printf("%5d ", original[i][j]);
}
printf("\n");
}
}
int main() {
int entrada[5][5] = {{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {11, 12, 13, 14, 15}, {16, 17, 18, 19, 20}, {21, 22, 23, 24, 25}};
int saida[5][5];
operar(5, 5, entrada, saida, conv);
imprimir(5, 5, entrada);
printf("\n");
imprimir(5, 5, saida);
}
See here working on ideone. Here is the output generated:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
1 4 9 16 25
36 49 64 81 100
121 144 169 196 225
256 289 324 361 400
441 484 529 576 625
Note that the conv
function is almost the same as you gave it. The difference is that the width and height of the matrix are explained in the function parameters as well as the row and column of the 3x3 block to be operated. There are also two arrays, one to be read and one to write.
The operar
function is the most frightening and has a horrendously long and complicated signature. In particular, the void (*op)(int largura, int altura, int linha, int coluna, int original[largura][altura], int resultante[altura][largura])
is a function pointer. void
is the return type of the function. The (*op)
indicates that this is a function pointer named op
, and the contents thereafter correspond to the parameter types of that function. The code inside the operar
function is very simple, however, it only traverses the arrays by calling the op
function in all positions.
Finally, in the function main
we have this:
operar(5, 5, entrada, saida, conv);
This means that the conv
function must be executed for each position of the arrays 5x5 entrada
and saida
. In this way, you can code other functions similar to the conv
, as long as they have the same parameters and the void
return and use it in the operar
function in the same way.
Oh, and one important note. This only makes sense if you really need submatrices in your conv
or similar function. If you are working element by element without processing one element to interfere in the other, all this would be much simpler. At the moment, its conv
function could be rewritten like this:
void conv(int largura, int altura, int linha, int coluna, int original[altura][largura], int resultante[altura][largura]) {
resultante[linha][coluna] = original[linha][coluna] * original[linha][coluna];
}