-4

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?

Quackers
  • 127
  • 7
  • It's how Java works (for arrays). Two different languages. To mitigate the ambiguity, better put `int *x;` and `int y;` on 2 different lines, if that pleases you. – Déjà vu Aug 05 '22 at 23:12
  • 1
    If you think it's not a duplicate, then why does it have the **almost the exact title**? Either it's a duplicate, or you need to edit your title to ask a different question., – Ken White Aug 05 '22 at 23:15
  • 2
    I morbidly sense a long period of hiding pointer types in typedef aliases on the road ahead. I just pray you figure out sooner rather than later what a dreadful idea it is. – WhozCraig Aug 05 '22 at 23:19
  • 1
    It's designed that way because the syntax appealed to Dennis Ritchie. We may never know why, unless his acquaintances from Bell Labs recall. – StoryTeller - Unslander Monica Aug 05 '22 at 23:30
  • 1
    Consider `int *(*p)(int,int)`... p is a variable name. Oh! p is a pointer!... Oh! p is a pointer to a function (taking two args). Oh, p is a pointer to a function (taking two args) that returns a pointer... and that pointer points to an int. If you go with `int *p;`, the rest becomes much simpler... – Fe2O3 Aug 05 '22 at 23:36
  • 1
    @StoryTeller-UnslanderMonica https://www.bell-labs.com/usr/dmr/www/chist.html gives some insight into the reasoning. *the declaration of a variable resembles its usage in an expression whose type is the one named at the head of the declaration.* – Shawn Aug 05 '22 at 23:51

1 Answers1

3

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, and they can all be declared (in a general and open-ended way) using the same sort of concise, punctuation-rich, unwordy syntax that C is famous for

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. (Part of the problem is that pointers do not necessarily make good "opaque" types. If you're dealing with a pointer, you often need to know that you're dealing with a pointer, so hiding it behind a typedef doesn't help.)

Steve Summit
  • 45,437
  • 7
  • 70
  • 103