5

Is there a "good" way to write "pointer to something" in C/C++ ?
I use to write void foo( char *str ); But sometimes I find it quite illogical because the type of str is "pointer to char", then it should more logical to attach the * to the type name.
Is there a rule to write pointers ?

char*str;
char* str;
char *str;
char * str;
Franck Freiburger
  • 26,310
  • 20
  • 70
  • 95
  • 1
    Are you in C or C++? Because the answer is totally different. – Puppy Feb 16 '11 at 12:00
  • 2
    `void foo(pointer_to_char str);` :) – Nick Dandoulakis Feb 16 '11 at 12:15
  • Why not `std::string`? Or `const char*`, at the least. – GManNickG Feb 16 '11 at 12:30
  • @GMan: Regarding `const char*`, a function with `void` return that doesn't modify its input is either utterly pointless, or else is an assert of some kind, or else is doing something mucky with globals. Two of those are bad, the other one a bit more specialized than I think we're entitled to assume from a no-context invented example ;-) I do agree though that `char *str` isn't what you want to see 10 minutes before you were hoping to leave for the day. – Steve Jessop Feb 16 '11 at 12:42
  • 2
    @SteveJessop: I don't agree with your categorization. It might have some completely useful and non-pointless side-effect like `syslog` and, personally, I wouldn't class this side effect as "doing something mucky with globals". – CB Bailey Feb 16 '11 at 13:08
  • Attaching the `*` to `str` is perfectly logical if you change your viewpoint just a little; the type of `*str` is `char`. Some people prefer that view. – molbdnilo Feb 16 '11 at 14:43
  • @Charles: true, I guess although logging can fail, in practice you don't report failure. Anyway, it seems wrong to me to suggest that the type `char*` should never occur as a parameter. – Steve Jessop Feb 16 '11 at 15:15

5 Answers5

21

There is no strict rule, but bear in mind that the * attaches to the variable, so:

char *str1, *str2; // str1 and str2 are pointers
char* str1, str2;  // str1 is a pointer, str2 is a char

Some people like to do char * str1 as well, but it's up to you or your company's coding standard.

DrAl
  • 70,428
  • 10
  • 106
  • 108
  • 5
    This is indeed the reason why many guidelines recommend attaching `*` to the variable name. However, I think a better practice is to avoid declaring several variables in the same line: I find it clearer, more maintainable and less error-prone. And in this case, the position of the `*` is of little importance (personnaly, I put a space before and after, it makes it easier to spot pointers (or references), but that is mostly a matter of taste). – Luc Touraille Feb 16 '11 at 12:21
  • Bear in mind that people have argued over where the `*` attaches to for longer than you have lived. – James Morris Feb 16 '11 at 12:21
  • 1
    Good example indeed. But what to do with `char * const str1;`? – Gauthier Feb 16 '11 at 12:22
  • @Luc Touraille: +1 to your comment. I would usually put the variables on separate lines as well; I just didn't mention it as I didn't feel it was that relevant to the question itself. – DrAl Feb 16 '11 at 12:23
  • 2
    This is one of many reasons why you shouldn't use "," when declaring variables. The solution is *not* to adapt a certain pointer declaration syntax, but to declare each variable on a line of its own. Then you won't have ridiculous newbie bugs caused by this obfuscated comma declaration syntax. – Lundin Feb 16 '11 at 13:58
9

The common C convention is to write T *p, whereas the common C++ convention is to write T* p. Both parse as T (*p); the * is part of the declarator, not the type specifier. It's purely an accident of pointer declaration syntax that you can write it either way.

C (and by extension, C++) declaration syntax is expression-centric; IOW, the form of a declaration should match the form of an expression of the same type in the code.

For example, suppose we had a pointer to int, and we wanted to access that integer value. To do so, we dereference the pointer with the * indirection operator, like so:

x = *p; 

The type of the expression *p is int; thus, it follows that the declaration of p should be

int *p  

The int-ness of p is provided by the type specifier int, but the pointer-ness of p is provided by the declarator *p.

As a slightly more complicated example, suppose we had a pointer to an array of float, and wanted to access the floating point value at the i'th element of the array through the pointer. We dereference the array pointer and subscript the result:

f = (*ap)[i];

The type of the expression (*ap)[i] is float, so it follows that the declaration of the array pointer is

float (*ap)[N];

The float-ness of ap is provided by the type specifier float, but the pointer-ness and array-ness are provided by the declarator (*ap)[N]. Note that in this case the * must explicitly be bound to the identifer; [] has a higher precedence than unary * in both expression and declaration syntax, so float* ap[N] would be parsed as float *(ap[N]), or "array of pointers to float", rather than "pointer to array of float". I suppose you could write that as

float(* ap)[N];

but I'm not sure what the point would be; it doesn't make the type of ap any clearer.

Even better, how about a pointer to a function that returns a pointer to an array of pointer to int:

int *(*(*f)())[N];

Again, at least two of the * operators must explicitly be bound in the declarator; binding the last * to the type specifier, as in

int* (*(*f)())[N];

just indicates confused thinking IMO.

Even though I use it in my own C++ code, and even though I understand why it became popular, the problem I have with the reasoning behind the T* p convention is that it just doesn't apply outside of the simplest of pointer declarations, and it reinforces a simplistic-to-the-point-of-being-wrong view of C and C++ declaration syntax. Yes, the type of p is "pointer to T", but that doesn't change the fact that as far as the language grammar is concerned * binds to the declarator, not the type specifier.

For another case, if the type of a is "N-element array of T", we don't write

T[N] a;

Obviously, the grammar doesn't allow it. Again, the argument just doesn't apply in this case.

EDIT

As Steve points out in the comments, you can use typedefs to hide some of the complexity. For example, you could rewrite

int *(*(*f)())[N];

as something like

typedef int *iptrarr[N];           // iptrarr is an array of pointer to int
typedef iptrarr *arrptrfunc();     // arrptrfunc is a function returning
                                   // a pointer to iptrarr

arrptrfunc *f;                     // f is a pointer to arrptrfunc

Now you can cleanly apply the T* p convention, declaring f as arrptrfunc* f. I personally am not fond of doing things this way, since it's not necessarily clear from the typedef how f is supposed to be used in an expression, or how to use an object of type arrptrfunc. The non-typedef'd version may be ugly and difficult to read, but at least it tells you everything you need to know up front; you don't have to go digging through all the typedefs.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • 1
    "`int* (*(*f)())[N];` just indicates confused thinking IMO." - darn straight. For the love of basic readability, use a couple of typedefs :-) – Steve Jessop Feb 16 '11 at 20:28
  • 4
    @Steve: Ah, but typedefs introduce their own problems. `int *(*(*f)())[N];` may border on unreadability, but at least you know at a glance how `f` should be used in an expression. If all that's hidden behind a typedef like `Fptr f`, though, you have to go digging for the definition to see how to properly use it. I know I'm an outlier in this respect, but I prefer the non-typedef'd version for that very reason. And hiding pointers behind typedefs always seems to lead to heartburn for me. – John Bode Feb 16 '11 at 21:50
3

The "good way" depends on

  1. internal coding standards in your project
  2. your personal preferences

(probably) in that order.

René Nyffenegger
  • 39,402
  • 33
  • 158
  • 293
  • 1
    @Soubok: still works. The more logical or natural way depends on your project standards and your personal preferences. It's a subjective issue of readability and aesthetics. People who try to construct it otherwise to "prove" that their preferences are "correct" are thieves and cowards. – Steve Jessop Feb 16 '11 at 12:38
1

There is no right or wrong in this. The important thing is to pick one coding standard and stick to it.

That being said, I personally believe that the * belongs with the type and not the variable name, as the type is "pointer to char". The variable name is not a pointer.

Lundin
  • 195,001
  • 40
  • 254
  • 396
0

I think this is going to be heavily influenced by the general pattern in how one declares the variables.

For example, I have a tendency to declare only one variable per line. This way, I can add a comment reminding me how the variable is to be used.

However, there are times, when it is practical to declare several variables of the same type on one line. Under such circumstances, my personal coding rule is to never, NEVER, EVER declare pointers on the same line as non-pointers. I find that mixing them can be a source of errors, so I try to make it easier to see "wrongness" by avoiding mixing.

As long as I follow the first guideline, I find that it does not matter overly much how I declare the pointers so long as I am consistent.

However, if I use the second guideline and declare several pointers on the same line, I find the following style to be most beneficial and clear (of course others may disagree) ...

char  *ptr1, *ptr2, *ptr3;

By having no space between the * and the pointer name, it becomes easier to spot whether I have violated the second guideline.

Now, if I wanted to be consistent between my two personal style guidelines, when declaring only one pointer on a line, I would use ...

char  *ptr;

Anyway, that's my rationale for part of why I do what I do. Hope this helps.

Sparky
  • 13,505
  • 4
  • 26
  • 27
  • 1
    Could you please name your reasons *why* it is practical to declare several variables at one line? The original reason for this obfuscated syntax is that C was designed at a time when HD space was so valuable, you had to keep the source code files themselves compact. I can only come up with the following reasons why you would declare several variables on one line: 1) programming on a computer with a HD from the 70s, 2) laziness, 3) obfuscated C coding contest, 4) reducing wear & tear on your keyboard, 5) lacking knowledge of how source code translates into machine code. – Lundin Feb 16 '11 at 14:19
  • The point is that should it be thought necessary to break or bend the first guideline, try do it as sanely, safely and sparingly as possible. Why break it? The main reason (or excuse if you prefer) is that of perceived readability.Declaring one variable per line has the potential to chew up a lot of screen space. Or, if you want a somewhat contrived example, consider nested loops N levels deep, each one having its own index/counter. Instead of having N variables on N lines each one with a comment that reads "loop variable", put them all on one line with the same comment. – Sparky Feb 16 '11 at 15:57