José D.
José D.

Reputation: 4275

const char * VS char const * const (Not about what is const)

So, I know the differences between char const *, char * const, and char const * const. Those being:

char* the_string : I can change the char to which the_string points, and I can modify the char at which it points.

const char* the_string : I can change the char to which the_string points, but I cannot modify the char at which it points.

char* const the_string : I cannot change the char to which the_string points, but I can modify the char at which it points.

const char* const the_string : I cannot change the char to which the_string points, nor can I modify the char at which it points.

(from const char * const versus const char *?)

Now, my question is: Let's say I'm writing a function that would not modify the C string that is passed to it, for example:

int countA(??? string) {
    int count = 0;
    int i;
    for (i=0; i<strlen(string); i++) {
         if (string[i] == 'A') count++;
    }
    return count;
}

Now, what should the header be?

int countA(char const * string); 
int countA(char const * const string);

My feeling is that I should use the second one, because I'm not going to modify the pointer itself, neither the contents of the array. But when I look to the header of standard functions they use the first one. Example

char * strcpy ( char * destination, const char * source );

Why?

(In fact char const * doesn't really make sense to me, because if you're thinking about the abstract string, either you are not modifying the string (so, char const * const because you are not modifying the pointer, neither the contents) or you will modify the string (so just char * because, you may modify the contents and you may need to allocate more memory, so you may need to modify the pointer)

I hope someone can make all this clear to me. Thanks.

Upvotes: 12

Views: 9515

Answers (5)

Steve Jessop
Steve Jessop

Reputation: 279385

The non-defining declarations:

int countA(char const * string);
int countA(char const * const string);
int countA(char const * foobar);
int countA(char const *);

are all equivalent. The string parameter names (in effect) a local variable inside the implementation of countA. It's none of the caller's business whether the implementation modifies that variable or not, and it doesn't affect the signature of the function.

It is the caller's business whether the function modifies the referand of string, so the first const is important. It is slightly the caller's business what the variable is named, but only because the convention is to name parameters in declarations as a hint what they're used for. Documentation is the way to completely convey the meaning of each parameter, not its name.

If you want a rule: omit the second const, because it clutters the declaration while telling the caller nothing of any use.

You could include it in the function definition, but there are some problems with doing so. You either need to keep the header up to date with the definition (in which case you'll sometimes find yourself changing the header due to a change in implementation details that doesn't affect callers). Or else you have to accept that the header doesn't match the definition, which will occasionally upset people who see:

int countA(char const * const string) {
    return 0; 
}

and search the headers for int countA(char const * const string), or vice-versa see the header and search the source. They need a smarter search term.

Upvotes: 3

md5
md5

Reputation: 23727

  • char const *s : s is a pointer to const char.
  • char *const s : s is a constant pointer to char.

When s is a function parameter, the first notation is more useful than the second.

  • With char const *, you can't modify the pointed value.
  • With char *const, you can't modify the value of your pointer. It is like int const in function parameters : you can't do operations directly onto your parameter. It doesn't change anything for the call function. (now, it's almost useless for the compiler, but it's meaningful for programmers)

Upvotes: 2

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726987

When you declare a function parameter as const char * const, it is not different to your callers from const char *: they could not care less what you do with that pointer, because to them it is all "pass by value" anyway.

The second const is there for you, not for your users. If you know that you are not going to modify that pointer, then by all means declare it const char * const: it is going to help you and others who maintain your code to catch errors later.

As for the standard library, my guess is that they did not want to make it const char * const because they wanted an ability to modify the poitners:

char * strcpy ( char * destination, const char * source ) {
    char *res = destination;
    while (*destination++ = *source++)
        ;
    return res;
}

Upvotes: 3

DevSolar
DevSolar

Reputation: 70381

In this case, it does not matter whether the pointer itself is const or not, because it is passed by-value anyway: Whatever strcpy does to source will not affect the caller's variable, because strcpy will operate on a copy of the caller's source on the stack, not the original. Note I am talking about the pointer value, not what the pointer points to, which should obviously not be changed since it is the source parameter.

char dest[10];
char const * source = "Hello";
strcpy( dest, source );
// no matter what strcpy does, the value of source will be unchanged

Within strcpy, you need to iterate pointers over the arrays pointed to by destination and source anyway. Not declaring the parameters as const allows the function to use the values from the stack directly, without copying / casting them first.

Upvotes: 6

cnicutar
cnicutar

Reputation: 182734

Having const char * represents a contract. It's a promise the function will not use that pointer to modify the contents passed by the user. Whether the pointer itself is constant or not is less valuable.

So, for the caller, whether the pointer itself is const or not makes no difference whatsoever.

In many implementations "string" functions regularly modify the passed pointer without modifying the contents. If the spec (the C standard) would mandate the pointer itself to be constant, it would be a limiting factor for all implementations, without providing any benefit for the caller.


As a side note, I think you shouldn't make everything const and then work your way around it. Just make stuff const if it feels the function shouldn't have reason to change it. In short, don't go const-mad, it's not a silver bullet and can be a recipe for frustration.

Upvotes: 5

Related Questions