Est-il mauvais de se référer aux éléments du tableau d'accès via l'arithmétique du pointeur au lieu de l'opérateur []?

12

Je viens de commencer à apprendre à programmer en C, et pour améliorer ma compréhension des pointeurs et des tableaux, j'ai essayé de faire référence aux éléments d'un tableau sans créer de pointeur du tout:

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));

    }
}

Le code entier se compile et fonctionne parfaitement.

J'imagine avoir à créer un pointeur pour chaque tableau unique dans un gros code source semble être très inefficace.

Donc, plutôt que d'avoir l'adresse d'un tableau stockée et récupérée à l'aide d'un pointeur, est-ce une mauvaise pratique de programmation d'utiliser directement l'adresse du tableau, comme indiqué ci-dessus?

Niko Gambt
la source
L'utilisation printf "[%d][%d] = %d\n", k1, k2, array[k1] [k2]));éviterait l'arithmique du pointeur et est plus facile à comprendre.
Kasper van den Berg du
1
Haha, tu m'as eu. Je l'ai fait uniquement à titre d'expérience pour mieux comprendre le fonctionnement des pointeurs et des tableaux.
Niko Gambt
L'arithmétique du pointeur est en fait environ 30% plus rapide que l'utilisation des index de tableau.
Andy

Réponses:

16

C'est "mauvais" seulement dans la mesure où c'est moins lisible. a[x]est la même chose que *(a+x), donc il n'y a pas de différence d'efficacité ou de comportement (en fait, ça x[a]marche aussi). C'est juste que a[x]c'est généralement beaucoup plus intuitif pour nous les humains.

Mais cela ne veut pas dire que la lisibilité n'est pas un gros problème. Pour voir leur taille, pensez à la façon dont vous "liriez" ces deux expressions si vous les voyiez dans le code:

  • *(a+x)= "Le machin pointé par la somme du pointeur aet de l'entier x"
  • a[x]= "Le xe membre du tableau a"

De même, lorsque vous devez vous référer à l'adresse d'un élément de tableau:

  • (a+x)= "La somme du pointeur aet de l'entier x"
  • &a[x]= "L'adresse du xe membre du tableau a"

La plupart du temps, les []versions sont simplement plus faciles à comprendre lorsque vous regardez du code non trivial fonctionnant sur plusieurs tableaux différents (en particulier des tableaux de tableaux). C'est pourquoi l' []opérateur existe en premier lieu.

PS Faire ce genre de chose strictement comme un exercice d'apprentissage est une très bonne idée. Il est important de comprendre que les tableaux ne sont en réalité que des pointeurs et des décalages.

Ixrec
la source
Cette. Je vous remercie. Je viens de réaliser au fond ce que je veux vraiment savoir, c'est si oui ou non, quand il faut se référer à l'adresse de n'importe quel élément du tableau, puis se référer à l'adresse d'un autre élément, et puis un autre, est-ce toujours mauvais NE PAS utiliser un pointeur et, à la place, utiliser le tableau directement comme je l'ai fait? Cette question a été très difficile à cerner, c'est pourquoi je ne l'ai pas saisie dans l'OP. Quoi qu'il en soit, puisque je ne l'ai pas posée, votre réponse est satisfaisante.
Niko Gambt
1
@NikoGambt Vous pouvez toujours poser une autre question =)
Ixrec
1
Que voulez-vous dire seulement dans la mesure où ...? L'intérêt des langages de programmation est de faciliter la lecture du code pour les humains. Si cela ne nous importait pas, nous écririons tous des codes op en hexadécimal.
Solomon Slow
2
Les tableaux ne sont pas des pointeurs, la décroissance juste des pointeurs implicitement.
CodesInChaos
4

Oui, c'est une mauvaise pratique, mais pas pour des raisons d'inefficacité.

L'opérateur de tableau utilise un pointeur arithmétique sous le capot, ils sont donc tout aussi efficaces.

Le problème avec l'arithmétique du pointeur est qu'il est très sujet aux erreurs et plus difficile à lire.

Règle générale: n'utilisez pas l'arithmétique de pointeur sauf si vous le devez.

user694733
la source
1
Puisqu'il utilise de toute façon l'arithmétique des pointeurs, cela ne signifie-t-il pas que les pointeurs sont également tout aussi sujets aux erreurs et difficiles à lire?
Niko Gambt
1
Les compilateurs @NikoGambt sont assez bons pour faire du pointeur arithmique sous le capot et feront rarement des «erreurs»; ce sont les programmeurs qui commettront des erreurs avec des bugs désagréables.
Kasper van den Berg du
@KaspervandenBerg Oui, je suis d'accord. Cependant, je suis intéressé par les erreurs faites par les programmeurs, et je ne suis tout simplement pas sûr que ce soit une mauvaise pratique de programmation de faire ce que j'ai fait ci-dessus, dans les cas où il est nécessaire de se référer à l'adresse d'un tableau , si de tels cas existent.
Niko Gambt du
1
@NikoGambt Écrire quelque chose qui est moins lisible à des fins de performance est presque toujours une mauvaise pratique, mais écrire quelque chose qui est moins lisible sans gain est une mauvaise pratique sans équivoque .
Neil
@Neil Ma petite expérience n'est pas inutile. Ce faisant, j'ai appris que le compilateur semble créer un tableau de pointeurs pour faire référence à un tableau multidimensionnel. Cependant, comme vous avez dit que la lisibilité est plus importante que les performances, je suppose que c'est toujours une mauvaise pratique de programmation.
Niko Gambt
0

Cool votre apprentissage c, vous venez de découvrir l'un des petits virelangues c. Vous ne faites pas de l'arithmétique des pointeurs sur un tableau, mais un tableau de pointeurs. Il n'est pas possible d'effectuer l'arithmétique du pointeur sur les tableaux. Un tableau se désintègre en un pointeur mais n'est pas un type de pointeur lui-même. Ce que vous avez (voir le commentaire de cmaster) est

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  

Le déréférencement de ce pointeur donne la valeur vers laquelle votre pointeur vient d'être calculé. Il est généralement inutile de faire ce que vous faites. Mais vous pouvez linéariser le tableau puis une foulée, comme ceci.

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

La fouler est x_dim. J'espère que ma réponse clarifie!

fhtuft
la source
Le PO ne précise pas s'il utilise un int* array[ROW];an int array[ROW][COLUMN];ou un int (*array)[COLUMN];. L'une ou l'autre de ces trois définitions peut être utilisée avec le code dans l'OP.
cmaster - réintègre monica le
oui j'en suis conscient, ma réponse est un peu maladroite sur ce point. Je le corrige, merci!
fhtuft