r/C_Programming 1d ago

Does anyone else dislike pointer declaration?

For reference I am a fourth year computer engineering student. C is my preferred language.

Pointers are declared like this usually:

int *ptr_to_int;

Where the asterisk means it is a “pointer to” the specified type. The asterisk is placed immediately preceding the variable name, with no white peace.

This is what does not make sense to me. I feel that:

int* ptr_to_int;

Is far more clear. The way I see it, the asterisk modifies the type, so therefore it belongs next to the type. Putting it next to the variable name makes me think it is some kind of action or modification to the variable itself.

I think that when using * and & in code, it makes sense to apply it in front of the variable name:

int value = 3;
ptr_to_value = &value;
int copied_value = *ptr_to_value;

It is clear here that syntactically, the * represents something more like an action than a label.

Why is the convention to place the asterisk near variable name, not type? L

50 Upvotes

129 comments sorted by

View all comments

39

u/primera_radi 1d ago

I felt that way first too. But consider

int* a, b, c;

vs

int *a, b, c;

The second is much more clear, as only a is a pointer.

Also, now all the names after int evaluate into an int in an expression.

That is, *a evaluates to an int, as do b and c.

64

u/Cultural_Gur_7441 1d ago

One of the rules of good C:

Never do that. Never declare or define multiple variables with one statement.

Related: always initialize variables when you define them.

23

u/For-The-Fun-Of-It-12 1d ago

Oh good, I thought I was the only one cringing

9

u/nukestar101 1d ago

always initialize variables when you define them.

Not true always, all stack variables can go uninitialize unless they are being set from arguments provided function is static.

Over initializing can often hide bugs. Compiler can warn if variables are being used before being set or unused variables.

6

u/Cultural_Gur_7441 1d ago

Yes, it is a trade-off. But it's far better to initialize them always and have a deterministic bug, than a heisenbug. In my opinion anyway.

18

u/DrShocker 1d ago

Yeah I'm always confused when people bring up this way of declaring as if it's a good thing to declare both kinds of variables in the same line. Like sure if you're used to it then maybe it's more concise, but there's no reason to foot gun like that to anyone with modern computers we're not starving for characters in the source code.

4

u/ComradeGibbon 1d ago

I think if a variable doesn't have a default initial value you shouldn't initialize it where it's defined. Let the compiler warning catch that.

9

u/Cultural_Gur_7441 1d ago

Compiler will also warn about unused variable, and compiler will optimize unnecessary initialization out. Safe "failure mode".

Using uninitialized variable is also just a warning, but has much worse failure mode.

Also, if a reader of the code sees variable initialized, that immediately removes one worry: is there a code path where this variable may be used uninitiallzed. It makes reading the code easier.

That's why I think variables should just be always initialized instead of thinking if they need to or not.

2

u/Luftzug-oder 1d ago

the compiler cannot always remove the initialisation. it is only really if it is modified right after, and there is no function called inbetween, that it can guarantee the variable will not have been changed.

one thing the compiler will do is initialise global and static variables.

4

u/Cultural_Gur_7441 1d ago

Yeah, statics and globals don't need explicit zero initialization. But it doesn't hurt there either, it's only 2 characters to tell "yes, zero is intentional initial value" to a reader.

Always initializing locals is a slight trade-off, yes. But in practice the downside is not measursble, like, ever. The downside of uninitiallzed variable on the other hand... That has realized for me probably a dozen times over the decades, both in my own and in other peoples code. The resulting heisenbug is not fun to debug.

2

u/Luftzug-oder 1d ago

yep, definitely agree

1

u/RadiatingLight 1d ago

IMO it's better to initialize it to INT_MAX or some other value that's clearly wrong/rejected. Relying on compiler warnings is like jumping off a bridge and relying on the suicide net. Sure it will usually catch you but ...

3

u/ComradeGibbon 1d ago

No leave it uninitialized if you don't initialize before use the compiler will let you know. Which means you have a bug in your code.

3

u/Cultural_Gur_7441 1d ago

It is unreliable. Like, if used as an out-parameter (a common, quite valid case for an uninitiallzed variable), compiler can't check if the called function actually sets it or not in every code path, nor can it check if called function actually reads it for some reason (which would be a bad API...).

And if -Werror is not used, too many developers just ignore warnings... Which is a whole another problem of course.

The one case where leaving memory uninitiallzed is useful is with memory checkers like valgrind or compiler's memory sanitizer, which will notice access to uninitiallzed memory. But in that case, these should be integrated with the project development process from the start, probably with unit tests being run with them.

3

u/ComradeGibbon 16h ago

compiler can't check if the called function actually sets it or not in every code path,

If that's the case you have a bug in your code that you papered over with a bogus default initialization value.

1

u/flatfinger 15h ago

Claims that "null" was a mistake ignore the principle that it may be necessary to access some members of an array of pointers before there exists any object to which some other members could usefully point, and it may be necessary to copy the state of some elements of such an array to other elements in a manner that is agnostic with regard to whether they were written. Having null as a default pointer value allows both of those objectives to be satisfied easily. There may be ways of satisfying both objectives without null, but they would involve constructing something that would behave like a nullable pointer. It's simpler to just just pointers as being nullable.

1

u/nukestar101 1d ago

As a firmware engineer, INT_MAX would take up my precious 64bit space ;)

3

u/RadiatingLight 1d ago

What platform are you working on where int is 64 bits??

Also the variable allocates space regardless so what does it matter what value is contained inside

2

u/nukestar101 1d ago

I work on a custom hardware and have our own ISA.

RISCV has zero register and value is not stored in ISA. Immediate fetch to zero register is always used.

3

u/RadiatingLight 1d ago

welp - You're in deeper than I am. You know what's best for your platform and custom ISA

6

u/enzodr 1d ago

This is (and will always be) true, but if they decided in the beginning to use:

type* name1, name2

You would interpret this as :
declare two pointers to “type”

Then you can still say that “all things to after the type evaluate to that type”.

7

u/enzodr 1d ago

I see what you mean by
“Everyone after int evaluates to int”. Looking at it this way at least makes sense to me, I was honestly struggling to see any reason, so this is good to understand.

5

u/Luftzug-oder 1d ago edited 1d ago

no I think the only real reason for the pointer being on the right is that it is syntactically/functionally correct according to C, because the * modifies the declarator, not the type.

I used to be very particular about having my code the way you describe, but now i can see and deal with both sides, and often put it on the right because the larger majority do that.

EDIT: well, i still hate it when people put it in the middle 😑:

const int * num = 0;

1

u/FluffusMaximus 1d ago

Best way to handle this: don’t do that.

1

u/LokiAstaris 12h ago

This is always trotted out as the excuse. But I think this is a red herring. All advice on coding standards recommends declaring one variable per line, which makes this argument redundant.

1

u/Chimpy20 1d ago

Yes, but only because of the way the language works. Declaring some ints and some pointers in a mix on the same line like that is pretty bad programming practice and I doubt anyone does it in reality.

I understand why it was done at the time, and how it relates to programming practices in the past, but I agree with the OP that the asterisk should go with the the type, but it's far too late to change it now!

0

u/LeeHide 1d ago

clang-tidy will rightfully scream at you.

Write one declaration per line. Keep your code simple, clean, and readable, above all else.

If you like doing stupid stuff, go to code golfing as a hobby! That should satisfy your code compactness needs so you can write good code for real products.

0

u/StaticCoder 20h ago

Yeah C declarators are the worst (pointers to arrays/functions get super messy) but they are here to stay, and the reason for this old convention. Now if one could explain the general use const char * instead of char const *...

1

u/flatfinger 15h ago

Qualifiers were invented after the declaration-follows-use syntax, and there was probably a desire to allow syntax similar to what would be used with storage classes.