40 votes

Pourquoi cette arithmétique de pointeur n'est-elle pas autorisée en C?

 char arr[] = "Hello";
arr = arr + 1;  // error occurs
 

Pour autant que je sache, une expression de type tableau est convertie en type de pointeur qui pointe vers l'élément initial du tableau. Par conséquent, je pensais que arr = arr + 1 (le pointeur sur le premier élément (arr) du tableau deviendrait le pointeur sur le deuxième élément du tableau) pour fonctionner. Pourquoi ça ne marche pas en C?

55voto

AndreyT Points 139512

arr + 1 est en fait un pointeur vers le deuxième élément de la matrice (c - &arr[1]).

Toutefois, cela ne signifie pas que vous pouvez en quelque sorte écrire que la valeur du pointeur de retour en arr. Vous ne pouvez pas le faire pour au moins deux raisons.

Tout d'abord, arr est un tableau de char éléments, et non pas un pointeur. Il y a une évidente incompatibilité de type ici.

Deuxièmement, étant un tableau, arr d'un non-modifiable lvalue. Vous ne pouvez pas modifier arr lui-même, vous pouvez uniquement modifier ses éléments (cette distinction est quelque peu difficile à saisir, mais il est là).

Enfin, si l'on ignore le plus profond de subtilités et de se concentrer sur ce qui formellement se passe au niveau supérieur, en raison de la matrice de décomposition de type de votre expression est équivalente à

(char *) arr = (char *) arr + 1;

La mission est impossible, puisque la gauche est un résultat de [implicite] conversion de type. En C les conversions de type produisent toujours rvalues. Vous ne pouvez pas affecter de rvalues.

En d'autres termes, il n'est pas de l'arithmétique des pointeurs" qui a refusé ici. L'arithmétique des pointeurs est très bien. C'est ce que vous faites avec le résultat que l'arithmétique des pointeurs qui provoque l'erreur.

23voto

haccks Points 33022

Les tableaux sont non modifiables, lvalues. Ils ne peuvent pas être l'opérande de gauche d'un opérateur d'affectation.

C11-§6.3.2.1:

Une modifiables lvalue est une lvalue que n'a pas de type tableau, ne dispose pas d'un type incomplète, [...]

§6.5.16/2:

Un opérateur d'affectation doit avoir une modifiables lvalue que son opérande de gauche.

Dans la déclaration

arr = arr + 1; 

arr est l'opérande gauche de l' = de l'opérateur et de l'est de type tableau. Il ne peut pas être modifié.
Donc, ce n'est pas l'arithmétique des pointeurs, mais la contrainte par la langue de l'opérateur d'affectation qui est la raison de l'erreur de syntaxe.


Notez que dans certains contextes, les tableaux se désintègrent en un pointeur sur son premier élément, bien que les pointeurs et les tableaux sont de différents types. Les tableaux ne sont pas des pointeurs. C'est seulement l'arithmétique des pointeurs et tableau d'indexation qui sont équivalents. Par exemple

char *ptr = &arr[0] + 1 => &(*(arr + 0)) + 1 => &(*arr) + 1 => arr + 1 // * and & nullify each other 

10voto

Natesh Raina Points 137

C'est parce que les tableaux sont similaires à des pointeurs à l'exception qu'ils ne peuvent pas être modifiés. Cependant, vous pouvez modifier un pointeur qui pointe vers un tableau. Pour l'exemple ci-dessus, vous pouvez faire comme ceci:

char arr[]="Hello";
char *ptr=arr;
ptr=ptr+1;

D'abord le pointeur ptr sera pointant vers le premier caractère du tableau c'est à dire 'H' et après la modification de la valeur du point pour le deuxième caractère, c'est à dire 'e'. Vous pouvez également effectuer les opérations suivantes:

char arr[]="Hello";
char *ptr=arr;
ptr=arr+1;

Les deux produisent le même effet, ce qui montre que arr+1 est en effet l'arithmétique des pointeurs. Cependant, vous ne pouvez pas modifier la valeur de arr , car son type est celui d'un tableau de caractères et pas de pointeur vers un tableau de caractères.

8voto

R Sahu Points 24027

Autant que je sache, une expression de type tableau est converti en type pointeur qui pointe vers le premier élément du tableau.

C'est vrai dans la plupart des contextes. Il n'est pas vrai dans les contextes suivants:

  1. Lors de l'utilisation de l'opérateur addressof (&arr). Le type d' &arr est char (*)[6]. Il n'est pas char**.

  2. Lors de l'utilisation de l' sizeof de l'opérateur. sizeof(arr) est 6. S'il avait été un pointeur, il serait de la taille d'un pointeur (4 ou 8 dans la plupart des plates-formes communes).

  3. Lorsqu'il est utilisé comme le membre de GAUCHE d'un opérateur d'affectation. Une variable de type tableau n'est pas modifiable.

Donc, je m'attendais arr = arr + 1 (pointeur vers le premier élément(arr) de la matrice devient le pointeur vers le deuxième élément de la matrice)pour travailler. Pourquoi se complique pas ce travail en C?

Le membre de droite de l'expression renvoie un pointeur vers le deuxième élément de l' arr. Cependant, cette ligne ne fonctionne pas en raison de (3) ci-dessus. arr n'est pas modifiable valeur. Il ne peut pas être utilisé comme de GAUCHE d'un opérateur d'affectation.

4voto

Inline Points 597

char[] n'est pas un pointeur, alors que char* est un pointeur. Cela fonctionne, mais c'est une mauvaise solution:

 int main()
{
    char *arr = "Hello";
    arr = arr + 1;  // Wrong!
    printf("%s\n", arr); // Output: ello
}
 

Si arr est alloué au tas avec malloc vous pouvez obtenir une fuite de mémoire si free mémoire démarrant arr+1 non arr .

Mais vous pouvez faire quelque chose comme ça:

 int main()
{
    char arr[] = "Hello";
    char *wordFromSecondLetter = &arr[0] + 1;
    printf("%s\n", wordFromSecondLetter); // Output: ello
}
 

Ou comme ça

 int main()
{
    char arr[] = "Hello";
    printf("%s\n", &arr[1]); // Output: ello
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X