C – quand utiliser l’arithmétique de pointeur, quand utiliser l’indexation de tableau?

En C, quand est-il préférable d’utiliser l’un par rapport à l’autre?

Cela dépend généralement de la situation. Je ne pense pas qu’il y ait une règle de base.

Dans certains cas, les index de tableau sont meilleurs. Par exemple, lorsque vous avez alloué un tableau

char* ptr = malloc(SIZE); 

et vous avez besoin de la valeur de ptr pour ne pas changer, car vous voulez la libérer plus tard, vous pouvez alors utiliser des index.

Ou si vous obtenez un pointeur comme argument de fonction

 void func(char* ptr) 

et vous devez exécuter le tableau, vous pouvez alors incrémenter le pointeur lui-même et vous n’avez pas besoin de créer une nouvelle variable à utiliser comme index.

Dans la plupart des cas cependant, cela dépend de vos propres préférences.

C’est vraiment une question de style et de conventions de codage, puisque dans C p[i] est défini comme étant le même que *(p+i)p est un pointeur et i un index intégral. Autant que je sache, vous pouvez même écrire i[p] mais c’est moche.

Ce n’est pas toujours vrai en C ++ (ce qui vous donne le pouvoir de définir l’ operator [] etc …).

Personnellement, je n’aime pas le codage manuel &p[i] et préfère p+i dans ce cas.

“Indexation de tableau” est simplement un sucre syntaxique qui englobe “l’arithmétique de pointeur”. C’est purement esthétique, juste une autre notation, ce qui signifie que l’utilisation de l’une ou de l’autre serait une question de préférence personnelle.

La vraie question qui se cache habituellement derrière ce que vous avez demandé est de savoir quand utiliser l’access aléatoire et quand utiliser l’access séquentiel (avec “arithmétique de pointeur” impliquant l’incrément / décrément séquentiel d’un pointeur d’au plus 1). La réponse est: préférez utiliser un access séquentiel lorsque vous le pouvez, utilisez uniquement un access aléatoire lorsque vous le devez.

Tant que les performances ne pâtissent pas, il est toujours préférable d’implémenter des algorithmes en s’appuyant sur un ensemble minimal d’exigences. L’access aléatoire est une exigence plus forte que l’access séquentiel, ce qui signifie que le premier doit être évité lorsque cela est raisonnablement possible.

En termes de performances, il peut être préférable d’utiliser l’arithmétique de pointeur (du moins avec l’optimisation du compilateur désactivée), car lorsqu’il parcourt un tableau, il n’est pas nécessaire d’incrémenter une variable distincte. Voir aussi K & R page 97 (deuxième édition).

Sinon, c’est simplement une question de style de codage.

Les pointeurs sont utiles lorsque la taille de la structure de données n’est pas connue au moment de la compilation. Par exemple, lorsque vous ne savez pas quelle est la longueur d’une chaîne, ou combien d’entiers vous attendez et ainsi de suite. Dans de telles situations, les pointeurs peuvent être alloués de manière dynamic en fonction des besoins.

Les tableaux d’autre part, réduisent la flexibilité.

Cependant, il y a beaucoup plus que cette différence.

conformément à MISRA C ++ 2008 (règle 5-0-15): l’indexation sur tableau doit être la seule forme d’arithmétique de pointeur.

mais cette règle a une exception:

Les opérateurs d’incrémentation / décrémentation peuvent être utilisés sur des iterators implémentés par des pointeurs vers un tableau

 template < typename IterType > uint8_t sum_values ( IterType iter, IterType end ) { uint8_t result = 0; while ( iter != end ) { result += *iter; ++iter; // Compliant by exception } return result; } void my_fn ( uint8_t * p1, uint8_t p2[ ] ) { uint8_t index = 0; uint8_t * p3; uint8_t * p4; *p1 = 0; ++index; index = index + 5; p1 = p1 + 5; // Non-compliant – pointer increment p1[ 5 ] = 0; // Non-compliant – p1 was not declared as array p3 = &p1[ 5 ]; // Non-compliant – p1 was not declared as array p2[ 0 ] = 0; p2[ index ] = 0; // Compliant p4 = &p2[ 5 ]; // Compliant } uint8_t a1[ 16 ]; uint8_t a2[ 16 ]; my_fn ( a1, a2 ); my_fn ( &a1[ 4 ], &a2[ 4 ] ); uint8_t a[ 10 ]; uint8_t * p; p = a; *( p + 5 ) = 0; // Non-compliant p[ 5 ] = 0; // Compliant sum_values ( &a1[ 0 ], &a1[ 16 ] );