Oi Ricardo,
Há várias coisas envolvidas aqui. E todos elas tem a ver com o conceito de endereço e com o fato que
quando dado img não sabemos onde está o elemento, digamos, img[3][4] da matriz na memória, então o compilador não saberá gerar o código para isto.
Entre as coisa envolvidas aqui temos que
- Em protótipos "int *v" é o mesmo "int v[]";
- Em protótipos "int *img[]" é equivalente a "int **img" (em particular "char *argv[]" é o mesmo que "char **argv");
- "int img[][]" não faz sentido, não é equivalente a int **img;
- Se declararmos no protótipo "int **img" devemos chamar a função apenas com matrizes alocadas dinamicamente ("malloc dos apontadores (int*) para as linhas e depois malloc de cada linha);
- A declaração "int img[][30]" no protótipo (Sim, a primeira dimensão é supérflua. Por que?) diz que a matriz imgtem todos os seus elementos consecutivos na memória (depois do img[0][29] vem img[1][0],. . .). Com está declaração só podemos chamar a função com matrizes alocadas estaticamente.
Para ver que as declarações "int **img" e "int img[][30]" não são equivalente vejam as ilustrações da aula 06 e o programa /programas/ponteiros/ponteiros-exemplo2.c disponibilizado junto com as notas de aula.
Declaração estática de matriz: int img[20][30];
Declaração dinâmica de matriz: int **img; junto com os malloc.