Why is the asterisk used before the each variable name instead of after the type?

This is not a duplicate of this question

I understand why it is better to declare variables like this:

int *var;

instead of

int* var

I understand that this avoids the ambiguous case of
int* var1, var2 where it would seem that var1 and var2 are both pointers to integers, but var2 is actually just a regular integer.

My question is why int* var1, var2 doesn’t declare both variables as pointers to integers. Intuitively, I would think that int* would act like any other data type, where you would just have to use int* var1, var2 to declare both variables of type int*. In other words, why is C designed so that each variable needs an asterisk before it?

>Solution :

Intuitively, I would think that int* would act like any other data type

If you want to become comfortable with C, you may need to adjust your intuition! Types are at least a little bit complicated; in fact the type system is a lot like a little programming language of its own! int is a type, but "pointer" is a meta-type. You can have pointers to anything, even pointers to pointers.

In other words, why is C designed so that each [pointer] variable needs an asterisk before it?

Because, as explained in several of the answers to that other question, the scheme is that a declaration contains a "base type" and then some "declarators". In the case of arrays, pointers, and functions, the "declarator" is a little sample of whatever thing is going to have the base type. If I say

int i;

the declarator is just i, so I’m saying that i is going to be an int. No mystery there. But if I say

int a[10];

I’m saying that one element of the array I’m declaring — that is, when I later use the array by saying something like a[i] — is going to be an int. If I say

int f();

I’m saying that calling the function is going to return an int.
Finally, if I say

int *ip;

I’m saying that when I take the contents of this pointer, using the expression *ip, then what *ip is going to be is an int.

And of course I can string these together on the same line:

int i, a[10], f(), *ip;

Now, perhaps I’m just rehashing the answers at the other question, and not explaining why things were set up this way. The reason is that it makes it possible to declare arbitrarily-complicated derived types. We can have arrays, and pointers, and functions, and arrays of arrays, and pointers to arrays, and functions returning pointers, and pointers to functions, and arrays of pointers to functions, and functions returning pointers to functions, and types even more numerous and complicated than those.

I don’t think it would have been possible to design a type system that could have expressed the concept of "array of pointers to functions" on the left, leaving you to just put the variable name on the right. Or, if you could design such a system, it would have been complicated and confusing and cumbersome to use, even more complicated and confusing than C’s present scheme seems to you, with its odd combination of type names on the left, and declarators — with their mixture of names, asterisks, and other punctuation — on the right.

See also Question 1.21 in the C FAQ list.


Or, perhaps I lied. I just said, "I don’t think it would have been possible to design a type system that could have expressed [complicated things] on the left, leaving you to just put the variable name on the right." But, in fact, C’s typedef facility lets you do precisely that, if you want to build up a complex type in stages.

For example, if you say

typedef int *pointer_to_int;

you have arranged that the identifier pointer_to_int is not an actual variable of type int *, but rather, a synonym for the type int *. Having done that, you can declare several integer pointers at once, without having to re-type those pesky asterisks:

pointer_to_int p1, p2, p3;    /* just like int *p1, *p2, *p3; */

And it works for more complicated types, too. I can say

typedef int *(*pointer_to_function_returning_pointer_to_int)();

and then do

 pointer_to_function_returning_pointer_to_int x1, x2, x3;

at which point x1, x2, and x3 are all pointers to functions returning pointers to int, just as if I’d said

int *(*x1)(), *(*x2)(), *(*x3)();

In fact, the CS50 course introduces a "handy" typedef

typedef char *string;

which makes the identifier string be an alias for the type "pointer to char", which allegedly makes it easier for beginners to declare lots of strings. Unfortunately, char * isn’t really C’s One True String type, so the string typedef probably causes as much confusion as it attempts to resolve.

Leave a Reply