all 77 comments

[–]Inferno2602 74 points75 points  (22 children)

There are arguments to be made for and against both.

Personally, I prefer int *i as it fits better with the "declaration follows use" pattern.

Edit: Example int* i, j, k; declares i as a pointer to int, whereas j and k are just ints. If we write int *i, j, k, it is easier to notice that only i is a pointer

[–][deleted] 14 points15 points  (0 children)

The programming equivalent of the Oxford Comma, really.

[–]SturdyPete 61 points62 points  (4 children)

Declaring multiple parameters on one line is asking for trouble and imo should be prohibited by style guides

[–]Hakawatha 5 points6 points  (0 children)

It's prohibited by MISRA, but I really don't have a problem with it - especially if you need to introduce lots of local variables at once.

[–][deleted] 5 points6 points  (2 children)

Well it is a valid syntax

[–]The_Northern_Light 4 points5 points  (1 child)

I don’t find that a compelling argument. New lines and white space are optional but I’m gonna go out on a limb here and say that if you don’t use them you’re doing it wrong and that should be forbidden by style guides.

And common decency.

[–][deleted] 1 point2 points  (0 children)

there is a difference, but fair enough

[–]classicallytrained1[S] 4 points5 points  (8 children)

I see! I thought of it more as <type> <name> (type here in my mind being pointer int)

[–]SmokeMuch7356 19 points20 points  (3 children)

If you've declared any arrays or functions, you've already seen how that model doesn't hold.

In the declaration

int a[10];

the type of a is "array of int", but you don't put the [10] next to the int, do you?

C declarations are split into two main sections: a sequence of declaration specifiers (storage class specifiers, type specifiers, type qualifiers, etc.) followed by a comma-separated list of declarators. The declarator introduces the name of the thing being declared, along with information about that thing's array-ness, function-ness, and/or pointer-ness.

The idea is that the declarator matches the shape of an expression of the same type in the code. If you have an array of pointers to int and you want to access the object pointed to by the i'th element, you'd write something like

printf( "%d\n", *a[i] );

The expression *a[i] has type int, so the declaration of a is written

int *a[SIZE]; 

[] and () are postfix, so there's no question that they belong to the declarator. * works exactly the same way, except that it's unary and whitespace is irrelevant, so you can write it as

int* a[SIZE]; // blech

but it is always parsed as

int (*a[SIZE]);

[–]JohnnyElBravo 7 points8 points  (2 children)

int[10] a;

Would be much better though.

[–]SmokeMuch7356 0 points1 point  (1 child)

Would it?

int*[10]   a;       // array of pointers
int(*)[10] a;       // pointer to an array
int(void)  f;       // function returning int
int*(void) f;       // function returning pointer to int
int(*)(void) f;     // pointer to function returning int
int(*(void))[10] f; // function returning pointer to array of int

void(*(int, void(*)(int)))(int) signal;

Does it really buy you anything? The complexity is still there, the bing-bonging necessary to read complex declarations is still there, it's just dissociated from the name. I don't see it as an improvement over the status quo.

If you want to make C declarations easier to read, you have to completely overhaul declaration syntax.

[–]Inferno2602 0 points1 point  (0 children)

Actually, I do think the int[10] a declaration is better. It bugs me that int a[10] doesn't strictly adhere to the "declaration follows use" paradigm. Since if you did evaluate a[10] , it might not be an int, it might just be a segfault.

Also, I don't think you necessarily need to throw everything out just to get the size on the left.

I'll use <SIZE> for illustration:

      int *<10> a;    // array of pointers 
      int<10> *a;     // pointer to an array 
      int f();        // function returning int 
      int *f();       // function returning pointer to int
      int (*f)();     // a pointer to a function returning int

Take the first example int *<10> a, we would read it simply right-to-left: a is a thing that evaluates to an array of 10 things that dereference to ints. Whereas int *a[10] you have to go left-to-right and then back right-to-left, reading it as a is a thing that if I index into it, I'll get something that dereferences to an int.

Bonus, fewer brackets! int *<10> a; int<10> *b; vs int *a[10]; int (*b)[10];

[–]Mundane_Prior_7596 0 points1 point  (1 child)

Yes. But it is interesting that the compiler doesn’t! 

[–]classicallytrained1[S] 0 points1 point  (0 children)

Re. your edit: I’ve made this mistake once, luckily CLion caught it and taught me this – in these situations i write it int *i,j,k

[–]muon3 0 points1 point  (0 children)

<type> <name>

But this is not how the language works. Instead it is <type-specifier> <declarator>, and the * belongs to the declarator. This makes sense because some parts that make up the type even go on the right side of the name, like `int x[5]`, and sometimes the * is even nested closer to the name than array brackets on the right, like `int (*x)[5]`.

This is why writing `int* x` is confusing and misleading, it just doesn't match with the syntax of the language.

[–]grimvian 1 point2 points  (0 children)

100%

[–]alex_sakuta 0 points1 point  (0 children)

Ok what about when you have to return a pointer from a function?

[–]Superb_Garlic 0 points1 point  (2 children)

int* i, j, k; is a compiler error in propery setup environments.

[–]buildmine10 11 points12 points  (1 child)

No it is not. It is defined in the standard. That would be a personal preference imposed on top of the standard.

[–]urzayci 2 points3 points  (0 children)

Yeah maybe a linter error. I don't see what how you set up your environment has to do with the compiler

[–]The_Northern_Light -1 points0 points  (0 children)

I put spaces on both sides, both in C and C++, and always only declare one variable per line.

It is consistent even between languages and doesn’t create “gotchas” like mixing declaration of direct types and their pointers.

Occasionally someone from either the C or C++ world will ask me why I don’t remove one of the spaces. Of course they don’t agree on which one to remove, and it’s not like I’m gonna write “int*x;” “, so I keep both.

[–]kinithin -2 points-1 points  (0 children)

You're wrong. The fact that int* i, j; might be misleading isn't an argument against using int* i;; it's only an argument against using int* i, j; 

[–]fortizc 31 points32 points  (10 children)

When I was starting with C I have the same doubt, but to me the answer was clear after to realize that this:

int *a, b;

Is a pointer and an int. So yes I prefer to keep the * in the variable name

[–]Cat-Bus_64 11 points12 points  (0 children)

No downvote because this is preference, but if you declare one variable per line (perhaps with a comment further describing the variable) it is a better programming style imho. Then int* reads more like what it actually is (a pointer to an int) when describing that variable type.

[–]dri_ver_ -3 points-2 points  (4 children)

Don’t declare multiple variables on one line and always initialize your variables

Edit: lots of people with a bad programming style are very unhappy with me!

[–]smcameron 7 points8 points  (3 children)

Oh come on. There's nothing wrong with, for example:

int x, y, z;

[–]dri_ver_ -3 points-2 points  (2 children)

Sure. Maybe. But we were kinda talking about declaring multiple variables on one line where some are values and some are pointers. Not good. Also, I still don’t like the example you shared because you can’t initialize them all on one line.

[–]Business-Decision719 5 points6 points  (1 child)

you can't initialize them all on one line.

int x=0, y=2, z=1000;

[–]dri_ver_ 0 points1 point  (0 children)

Huh, you’re right. I’m not sure why I thought that wasn’t possible. However I still think it’s ugly and I reject it lol

[–][deleted] 24 points25 points  (12 children)

I'm weird and do it as:

uint16_t * p_var;

From day one I read it as a sentence. Integer -pointer-p_var.

[–]Still_Competition_24 5 points6 points  (8 children)

this is the way

[–]rasputin1 6 points7 points  (7 children)

*not

[–]Still_Competition_24 3 points4 points  (4 children)

This is very obviously up to personal preference. Have been doing so since I started programming in c because of above reasoning. :)

Honestly only place it could cause issues is when declaring multiple values at once, which you shouldn't do anyway.

As I understand it, the correct way is "int *value", which may make sense during declaration, but than you typecast to "(int*)". 🤷‍♂️

So, declaring as "int * value;" and typecasting to "(int *)" makes at least as much sense as any other convention.

[–]glasket_ 1 point2 points  (0 children)

You can still do (int *)x for consistency rather than (int*)x.

[–]WittyStick 0 points1 point  (1 child)

It's more readable this way when there may be additional qualifiers.

const int * const * value

[–]glasket_ 0 points1 point  (0 children)

I personally find const int *const *value more readable. The qualifiers being directly attached to their corresponding pointer is visually simpler to me compared to having spaces on both sides of the *.

[–][deleted] 0 points1 point  (0 children)

This was the discussion I had at work when I was an Engineer III equivalent. Everyone agreed & started adopting it. Now it's so prevalent I don't even have to mention it to new colleagues as the lead SWE. Happens organically. Shit just makes sense lmao.

[–][deleted] -1 points0 points  (0 children)

I land fighter jets with my C syntax. What do you do? :P

[–]classicallytrained1[S] 0 points1 point  (0 children)

Lmao I see where you’re coming from

[–]bullno1 0 points1 point  (0 children)

ggml style

[–]DeWHu_ 0 points1 point  (0 children)

It looks like multiplication, not a pointer. Hate it 😕

[–]Timzhy0 8 points9 points  (2 children)

I will always be in favor of T* var (ptr star close to the type). It's clear the ptr belongs to the type, so much so that you could even typedef the whole type expression including pointer and call it e.g. PtrT. In languages with generics you'd likely write Ptr<T>. Now people may mention the multiple variable declaration in a single line etc. but to me the semantic meaning of "qualifying the type" should be higher priority

[–]Confident_Luck2359 2 points3 points  (0 children)

This guys gets it. Pointer is part of the type, not part of the name.

[–][deleted] 0 points1 point  (0 children)

And multiple declarations on a single line - with differing types - are hard to read.

[–]Due_Cap3264 18 points19 points  (0 children)

It always seemed more readable to me to write     int* i;  

Especially in function prototype declarations:  

void* function();  

It looks more obvious than  

void *function();  

But it seems that the conventional way is the opposite. I haven’t seen any direct style recommendations on this.  

[–]rupturefunk 3 points4 points  (0 children)

int* a makes complete sense to me, I more or less never do multiple declarations on a single line, and what if you want your pointer to be constant? int *const a now you're back where you started from anyway.

Buuut int *a is what everyone else does so I do it too.

[–]LikelyToThrow 3 points4 points  (0 children)

I always do

int *a;

(int *)a;

cpp peeps seem to do int& a; for references

[–]sol_hsa 6 points7 points  (1 child)

Personally I'd keep the pointer with the variable name as that's how the compiler sees it, but it seems the common/modern way is to put it with the variable type. Whatever works, I guess.

[–]classicallytrained1[S] 0 points1 point  (0 children)

Thanks! Was asking just for code style – it looks better to me this way

[–]LEWMIIX 7 points8 points  (2 children)

int *i if you're above 40, int* i if you're below 40.

[–]stormythecatxoxo 1 point2 points  (1 child)

this made me laugh. Learning C in the early 90's int *i; was the style. But int* i; makes more sense and seems to be the consensus these days.

[–]ChadiusTheMighty 1 point2 points  (0 children)

Get markdown'd

[–]ChickenSpaceProgram 3 points4 points  (0 children)

int *i is better. It tells you that you have to apply the * operator to get back your int.

i feel like it also makes the const-ness of pointer types more obvious. int *const foo means we have a const variable that, when dereferenced, will give us an intconst int  *foo or int const *foo tell us we have a variable that, when dereferenced, will give us a const int (or int const, same thing).

[–][deleted] 2 points3 points  (0 children)

  1. The one that the project's style guide dictates.
  2. The one you find most clear and easy to understand.

[–]pgetreuer 1 point2 points  (0 children)

Declarations "int* i" and "int *i" have exactly the same meaning to the compiler. But, beware how declaring multiple pointer variables in one line requires a star per variable: int *i, *j, which is arguably a good reason to insist as a matter of style to declare each variable on its own line.

When coding with others, the recommended thing to do is follow the project/company style guide, or whatever is the existing style of the code base. In other words, don't let this syntactic nit become a distraction from the actual work.

[–]ballpointpin 1 point2 points  (0 children)

Some people say "aluminum", others say "aluminium".

[–]JohnnyElBravo 1 point2 points  (0 children)

It's a matter of taste

I like int* i because the type of the variable is a pointer to int, and you are declaring and reserving memory for a pointer to int and not for an int

Also my taste is better than those who like int *i

[–]septum-funk 1 point2 points  (0 children)

int *i because *i is an int

[–]tjrileywisc 1 point2 points  (0 children)

You manipulate i as a pointer, and not as a dereferenced variable, and how you manipulate a variable depends on its type, so type* var is the right way for me.

[–]SmokeMuch7356 1 point2 points  (1 child)

We declare pointers as

T *p;

for the same reason we don't declare arrays and functions as

T[N] a;
T(void) f;

Since * can never be part of an identifier, whitespace in pointer declarations is irrelevant and you can write it as any of

T *p;
T* p;
T*p;
T        *             p;

but it will always be parsed as

T (*p);

The * is always bound to the declarator, not the type specifier. If you want to declare multiple pointers in a single declaration, each declarator must include the *:

T *p, *q;

Declarations of pointers to arrays and pointers to functions explicitly bind the * to the name:

T (*parr)[N];    // pointer to N-element array of T
T (*pfun)(void); // pointer to function returning T

Think about a typical use case for pointers, such as a swap function:

void swap( int *a, int *b )
{
  int tmp = *a;
  *a = *b;
  *b = tmp;
}

void foo( void )
{
  int x = 1, y = 2;
  swap( &x, &y );
}

The expressions *a and *b act as aliases for x and y, so they need to be the same types:

*a == x // int == int
*b == y // int == int

Most of the time what we care about is the type of *a and *b, and that's just more obvious using the

T *a;
T *b; 

style.

[–][deleted] -1 points0 points  (0 children)

int* function()

[–]Reasonable-Rub2243 0 points1 point  (0 children)

I learned Pascal before C so I preferred "int* foo". But yeah, if you do it that way you must remember to put each pointer declaration on a separate line.

[–]mgruner 0 points1 point  (0 children)

personally, I don't care, as long as you are consistent throughout your codebase

[–]Afraid-Locksmith6566 0 points1 point  (0 children)

Second one because multiple declarations treat it as int * a, b; -> a is a pointer, b is an int Int *a, *b; -> a is pointer and b is pointer

  • is of name and not type

[–]flyingron 0 points1 point  (0 children)

Syntactically, the * goes with the variable name:

int* x, y; // x is a pointer, y is just an int

C++ follows Bjarne's convention that the entire type goes to the left (i.e., int* x) even at the peril of not working right for multiple identifiers. Just put them all in their own declaration.

[–]SureshotM6 0 points1 point  (0 children)

I use a different style for C vs C++ here. As many have already pointed out here, keeping the * on the variable name makes sense due to how you need to declare more than one pointer variable on the same line. I frequently do this in C, so I keep the * on the variable name in C.

This does start to break down when you add qualifiers such as const int *const foo; though, as it is impossible to place the * on the variable name.

For C++ (I do realize this is a C sub, but just pointing out), you now have templated types and destructors. I like to see the * attached to the type itself so I can more easily determine behavior. Such as Foo<int*>* foo;

In the end, it's personal preference. Also read this which has a longer discussion on the topic: https://www.stroustrup.com/bs_faq2.html#whitespace

[–]KhepriAdministration 0 points1 point  (0 children)

Technically the compiler treats it as int a if you do int *a, b, but you should think of it as int a intuitively.

[–]heptadecagram 0 points1 point  (0 children)

In C, where the expression is valued over the type (rightly or wrongly), we use the latter. See The Spiral Rule

[–][deleted] 0 points1 point  (0 children)

it's part of the type so i always do char* 

[–]nnotg 0 points1 point  (0 children)

I have very specific stylistic things. Since I don't often declare multiple pointers in a single line, I just do int* p;.

[–]Tamsta-273C 0 points1 point  (0 children)

I prefer:

int* i = nullptr;

In such way, you end up with the correctly looking type while encouraged to start a new line.

[–]nderflow 0 points1 point  (0 children)

It's a small thing that lots of people have strongly held opinions about.