É ruim fazer referência aos elementos da matriz de acesso via aritmética do ponteiro, em vez do operador []?

12

Eu apenas comecei a aprender a programar em C e, para melhorar minha compreensão de ponteiros e matrizes, tentei me referir aos elementos de uma matriz sem criar nenhum ponteiro:

for(k1 = 0; k1 < ROW; k1++){
    for(k2 = 0; k2 < COLUMN; k2++){

        array[k1][k2] = k1*COLUMN + k2 + 1;

        printf("[%d][%d] = %d\n", k1, k2, *(array[k1] + k2));

    }
}

Todo o código compila e executa na perfeição.

Eu imagino que ter que criar um ponteiro para cada matriz em um grande código-fonte parece ser altamente ineficiente.

Portanto, em vez de ter o endereço de uma matriz armazenado e recuperado usando um ponteiro, é uma prática ruim de programação usar o endereço da matriz diretamente, como mostrado acima?

Niko Gambt
fonte
O uso printf "[%d][%d] = %d\n", k1, k2, array[k1] [k2]));evitaria o ponteiro aritmico e é mais fácil de entender.
Kasper van den Berg,
1
Haha, você me pegou. Fiz isso apenas como um experimento para entender melhor como os ponteiros e matrizes funcionam.
Niko Gambt
A aritmética dos ponteiros é na verdade cerca de 30% mais rápida que o uso de índices de matriz.
Andy Andy

Respostas:

16

É "ruim" apenas na medida em que é menos legível. a[x]é a mesma coisa que *(a+x), portanto, não há diferença em eficiência ou comportamento (de fato, x[a]também funcionará). É que a[x]geralmente é muito mais intuitivo para nós, humanos.

Mas isso não quer dizer que a legibilidade não seja um grande problema. Para ver o tamanho, pense em como você "leria" essas duas expressões se as visse no código:

  • *(a+x)= "A coisa apontada pela soma do ponteiro ae número inteiro x"
  • a[x]= "O xmembro th da matriz a"

Da mesma forma, quando você precisa se referir ao endereço de um elemento da matriz:

  • (a+x)= "A soma do ponteiro ae número inteiro x"
  • &a[x]= "O endereço do xmembro th da matriz a"

Na maioria das vezes, as []versões são mais fáceis de entender quando você está vendo código não trivial operando em várias matrizes diferentes (especialmente matrizes de matrizes). É por isso que o []operador existe em primeiro lugar.

PS: Fazer esse tipo de coisa estritamente como exercício de aprendizado é uma ideia muito boa. É importante entender que matrizes são realmente apenas indicadores e compensações.

Ixrec
fonte
Este. Obrigado. Acabei de perceber, no fundo, o que realmente quero saber é se, ou não, quando é necessário fazer referência ao endereço de qualquer elemento da matriz e depois ao endereço de outro elemento e depois outro, ainda é ruim NÃO use um ponteiro e, em vez disso, use a matriz diretamente da maneira que eu fiz? Essa questão minha tem sido realmente difícil de apontar, por isso não a digitei no OP. De qualquer forma, desde que eu não perguntei, sua resposta é satisfatória.
Niko Gambt
1
@NikoGambt Você sempre pode fazer outra pergunta =)
Ixrec
1
O que você quer dizer apenas na medida em que ...? O objetivo das linguagens de programação é tornar o código mais fácil para os humanos lerem. Se não nos importássemos com isso, todos estaríamos escrevendo códigos op em hexadecimal.
Solomon Slow
2
Matrizes não são ponteiros, apenas a deterioração dos ponteiros implicitamente.
CodesInChaos
4

Sim, é uma prática ruim, mas não por razões de ineficiência.

O operador de matriz usa o ponteiro aritmético sob o capô, para que sejam igualmente eficientes.

O problema da aritmética dos ponteiros é que é muito propenso a erros e mais difícil de ler.

Regra prática: não use ponteiros aritméticos, a menos que seja necessário.

user694733
fonte
1
Como ele usa a aritmética dos ponteiros de qualquer maneira, isso não significa que os ponteiros também são igualmente propensos a erros e difíceis de ler?
Niko Gambt
1
Os compiladores @NikoGambt são muito bons em fazer apontamentos aritmicos sob o capô e raramente cometem 'erros'; são os programadores que cometerão erros com erros desagradáveis ​​como consequência.
Kasper van den Berg,
@KaspervandenBerg Sim, eu concordo. No entanto, estou interessado em erros cometidos por programadores e não tenho muita certeza se é uma má prática de programação fazer o que fiz lá acima, nos casos em que é necessário consultar o endereço de uma matriz , se esses casos existirem.
Niko Gambt
1
@NikoGambt Escrever algo que é menos legível para fins de desempenho é quase sempre uma prática ruim, mas escrever algo que é menos legível para nenhum ganho é uma prática inequivocamente ruim.
Neil
@ Neil Meu pequeno experimento não é inútil. Ao fazer isso, aprendi que o compilador parece fazer uma matriz de ponteiros para se referir a uma matriz multidimensional. No entanto, como você disse que a legibilidade é mais importante que o desempenho, acho que ainda é uma má prática de programação.
Niko Gambt
0

Esfrie seu aprendizado c, você acabou de descobrir um dos travaquinhos da língua. Você não está fazendo aritmética de ponteiros em uma matriz, mas em uma matriz de ponteiros. Não é possível fazer aritmética de ponteiro em matrizes. Uma matriz decai para um ponteiro, mas não é um tipo de ponteiro. O que você tem (veja o comentário do cmaster) é

int *array[]; //This is a array to pointers of type *int. 

array[k1] + k2; //This is pointer arithmetic on one pointer stored in the array  

A desreferenciação desse ponteiro fornece o valor que seu ponteiro recém-calculado aponta para. Geralmente não faz sentido fazer o que você está fazendo. Mas você pode linearizar a matriz e, em seguida, dar um passo nela, assim.

int array[y_dim*x_dim]; 
int index = x_dim*y + x; 
array[index]; //Gives you the element in x, y!

Passo ela é x_dim. Espero que minha resposta seja esclarecedora!

fhtuft
fonte
Não está claro pelo OP se ele usa um int* array[ROW];an int array[ROW][COLUMN];ou an int (*array)[COLUMN];. Qualquer uma dessas três definições pode ser usada com o código no OP.
cmaster - restabelecer monica
Sim, estou ciente disso, minha resposta é um pouco desajeitada nesse ponto. Eu corrijo, obrigado!
precisa saber é