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.
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.
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.
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;
}
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.
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)
Related
The function below uses const char *s1
What the function does is perhaps not important. It returns 1 if the string
contains characters other than allowed characters. It returns 0 if it
doesn't.
int TEST (const char *s1);
int TEST (const char *s1) {
char * s2= "o123";
return s1[ strspn(s1, s2) ] != '\0';
}
The function seems to work just fine if I were to remove const portion from it.
Why do I need const terminology in that function, if it seems to work fine without it? What is the importance of it? What are the implications of
using?
not using?
When you have const char *s1 you are telling the compiler that you will not modify the contents of the memory that s1 is pointing to. It's a semantic signal for the compiler so you do not make mistakes in the function (attempts to change the contents will results in errors). It might also allow the compiler to add some optimizations.
But more importantly it's a signal to other programmers reading your code, and using your function. And with "other programmers" I also include you in a few weeks, months or years time, when you might come back to the code and have forgotten the details of it.
importance of “const”?
3 reasons:
Applicability
Code correctness
Speed
Consider what the calling code is allowed to do
int TEST_with_const(const char *s1);
int TEST_without_const(char *s1);
char *cs;
const char *ccs
...
TEST_with_const(cs); // allowed
TEST_with_const(ccs); // allowed
TEST_without_const(cs); // allowed
TEST_without_const(ccs); // fails to compile.
The last one fails because TEST_without_const(char *s1); is telling the outside world, I want a pointer to memory that I might alter. ccs is not a pointer to modifiable memory.
Assuming TEST_without_const(char *s1); has the same body of int TEST (const char *s1), it did not need a pointer to modifiable memory
By using const char *s1 the function's body will complain during compilation should a modification of the memory pointed to by s1 is attempted. If the function design does not need to modify the memory pointed to by s1, this check helps insure correctness.
Depending on complier, some optimizations can occur with const char *, but not with char *.
const in this function prevents you to write something to memory where variable points to.
Here, you are only checking value if it is not equal to \0 and it is ok because you do only read operation.
int TEST (const char *s1) {
char * s2= "o123";
return s1[ strspn(s1, s2) ] != '\0';
}
If you do this, trying to write through s1 pointer:
int TEST (const char *s1) {
char * s2= "o123";
s1[0] = '4'; //Error, s1 is const pointer, can't write to memory pointed to by s1
return s1[ strspn(s1, s2) ] != '\0';
}
const pointer in your case means that this function should not write any data to input pointer, only read operation can be performed. You can in fact change where s1 points, only write to memory through s1 is not allowed. This is to prevent any mistakes to now write unexpectedly because it may in some cases lead to undefined behaviour.
The usage of const prevents you or somebody else working with your code from doing something accidentally wrong. Moreover it is for documentation purposes as the reader of the code knows that these functions are not changing the characters (read-only) the pointer points to.
Further the compiler may optimize your code if you use const correctness because it knows that these values are not changing inside the functions being read-only. But the first reason of documenting and making your function safer is more important.
There are three forms you always come accross with: char* s1, const char* s1 and const char* const s1. The forth but rarely needed form is: char* const. The meanings are as follows:
1.
char* s1:
In this case s1 is just a pointer to memory of one or more characters.
The following can be/can not be done inside of the function:
/* Function might changes content of s1 */
int TEST (char* s1)
{
s1[0] = 'A'; /* works */
*s1 = 'A'; /* same as above works */
++s1; /* this works because the copy of the pointer is non constant */
...
}
The following calls can be/can not be made:
char* str;
const char* const_str;
...
TEST(str); /* works as str as no restrictions */
TEST(const_str); /* fails because function might change const const_str */
2.
const char* s1:
The term: const char* s1 means s1 is a pointer to memory of one or more characters that can't be changed with this pointer. The following can be/can not be done inside of the function:
/* Function is read-only and doesn't changes content of s1 */
int CONST_TEST (const char* s1)
{
s1[0] = 'A'; /* compiler fail */
*s1 = 'A'; /* same as above compiler fail */
++s1; /* this works because the copy of the pointer is non constant */
...
}
The following calls can be/can not be made:
char* str;
const char* const_str;
...
CONST_TEST(str); /* works as str as no restrictions */
CONST_TEST(const_str); /* works because function is read-only and const_str is it also */
The compiler will fail compiling and tell you that you try to write to a memory location that is marked as constant.
3.
const char* const s1:
This means: s1 is a constant pointer to memory of one or more characters that can't be changed with this pointer. This is an extension to the first approach, the pointer s1 itself is passed by value and this copy can't be changes inside the function. So that you can not do something like ++s1 inside the function, therefore the pointer will allways point to the same memory location.
4.
char* const s1:
This is like case 3 but without s1 pointing to memory marked as constant. Therefore the content s1 is pointing to can be changed like case 1 but with a pointer being constant.
Is there a reason strcpy's signature is this:
char *strcpy(char *dest, const char *src);
instead of this?
char *strcpy(char *const dest, const char *src);
As far as I know, the function will never change the pointer.
Am I misunderstanding what const pointers should be used for? In my mind, when a function I write accepts a pointer which won't be changed (via realloc, etc.), then I mark it as a const pointer so the caller can be assured their pointer won't be moved on them. (In case they have other structs/etc. referencing that pointer location that would become outdated)
Is that an OK practice, or will it have unintended consequences?
The source code for strcpy is very roughly this:
char *strcpy(char *dest, const char *src)
{
while (*dest++ = *src++);
}
Here we actually do modify dest but this has no consequence for the caller because inside the strcpyfunction, dest is a local variable.
But following code won't compile because dest is const:
char *strcpy(char * const dest, const char *src)
{
while (*dest++ = *src++);
}
we would need to write this:
char *strcpy(char * const dest, const char *src)
{
char *temp = dest;
while (*temp++ = *src++);
}
which introduces a non necessary temp variable.
Qualifiers on function arguments are completely ignored in declarations (prototypes). This is required by the C language, and it makes sense, because there is no possible meaning such qualification could have to callers of the function.
In the case of const char *src, the argument src is not what's qualified; the type it points to is qualified. In your hypothetical declaration for dest, the qualifier applies to dest and is thus meaningless.
char *foo(char *const dest, const char *src) { ... } means the pointer dest will not change in the body of the function.
It does not mean the data pointed to by dest will or will not change.
const char *src assures the calling code that the data pointed to by src will not change.
In calling a function like strcpy(d,s) or foo(d,s), the calling code does not care if the function changes its copy of the pointer. All the calling code cares about is if the data pointed to by s or d is changed and that is control by the const of the left side of *
char *dest, // data pointed by `dest` may or may not change.
const char *src // data pointed by `src` will not change change because of `src`.
It is meaningless to mark it as const as you suggest. In C, function arguments are passed as copy. It means that the variable dest inside strcpy() is actually a new variable (pushed on the stack), which holds the same content (here, the address).
Look at this function prototype:
void foo(int const a);
This has no semantic value, because we know that the original variable a that we passed to foo() can't be changed because it is a copy. Only the copy will potentially change. When foo return, we are guaranteed that the original variable a is unchanged.
In function parameters, you want to use the keyword const only if the function could actually persistently change the state of the variable. For example:
size_t strlen(const char *s);
This marks the content of the variable s (ie, the value stored at the address s points to) as const. Therefore, you are guaranteed your string will be unchanged when strlen returns.
As far as I know, the function will never change the pointer.
Yes, but you can. You are free to change the pointer. No need to make dest pointer const.
For example:
int main(void)
{
char *s = "Hello";
char *d = malloc(6);
strcpy(d, s);
puts(d);
strcpy(d, "World");
puts(d);
}
I'm learning the C language.
My question is:
Why is the param of strlen a "const" ?
size_t strlen(const char * string);
I'm thinking it's because string is an address so it doesn't change after initialization. If this is right, does that mean every time you build a function using a pointer as a param, it should be set to a constant ?
Like if I decide to build a function that sets an int variable to its double, should it be defined as:
void timesTwo(const int *num)
{
*num *= 2;
}
or
void timesTwo(int *num)
{
*num *= 2;
}
Or does it make no difference at all ?
C string is a pointer to a zero-terminated sequence of characters. const in front of char * indicates to the compiler and to the programmer calling the function that strlen is not going to modify the data pointed to by the string pointer.
This point is easier to understand when you look at strcpy:
char * strcpy ( char * destination, const char * source );
its second argument is const, but its first argument is not. This tells the programmer that the data pointed to by the first pointer may be modified by the function, while the data pointed to by the second pointer will remain constant upon return from strcpy.
The parameter to strlen function is a pointer to a const because the function is not expected to change what the pointer points to - it is only expected to do something with the string without altering it.
In your function 'timesTwo', if you intend to change the value that 'num' points to, you should not pass it in as a pointer-to-const. So, use the second example.
Basically, the function is promising that it will not modify the contents of of the input string through that pointer; it says that the expression *string may not be written to.
Here are the various permutations of the const qualifier:
const char *s; // s may be modified, *s may not be modified
char const *s; // same as above
char * const s; // s may not be modified, *s may be modified
const char * const s; // neither s nor *s may be modified
char const * const s; // same as above
Do excuse me to the basic"ness" of this question. I am at a loss with pointers at times. I have a char * but I need to convert it to a char * const * to be able to correctly use it in the fts() function. How do i do that?
Thanks
You are not supposed to do that kind of conversion, because the types are not compatible.
About pointers and pointers to pointers
char * is a pointer to a string of characters, whereas char ** is an pointer to a pointer to a string of characters. (the const is a bonus). This probably means that instead of supplying a string of characters, you should provide an array of string of characters.
Those two things are clearly incompatible. Don't mix them with a cast.
About the fts_* API
To find the solution to your problem, we need to read the fts_* function API (e.g. at http://linux.die.net/man/3/fts), I see that:
FTS *fts_open(char * const *path_argv, int options,
int (*compar)(const FTSENT **, const FTSENT **));
with your char * const * parameter path_argv, the description explains:
[...] If the compar() argument is NULL, the directory traversal order is in the order listed in path_argv for the root paths [...]
which confirms that the fts_open function is really expected a collection of paths, not one only path.
So I guess you need to pass to it something like the following:
char *p[] = { "/my/path", "/my/other/path", "/another/path", NULL } ;
About the const
Types in C and C++ are read from right to left. So if you have:
char * : pointer to char
char const * : pointer to const char (i.e. you can't modify the pointed string, but you can modify the pointer)
const char * : the same as char const *
char * const : const pointer to char (i.e. you can modify the pointed string, but you can't modify the pointer)
char ** : pointer to pointer to char
char * const * : pointer to const pointer to char (i.e. you can modify the pointer, and you can modify the strings of char, but you can't modify the intermediary pointer
It can be confusing, but reading them in the right-to-left order will be clear once you are more familiar with pointers (and if you programming in C or C++, you want to become familiar with pointers).
If we go back to the initial example (which sends a bunch of warnings on gcc with C99) :
char ** p = { "/my/path", "/my/other/path", "/another/path", NULL } ;
I played with the API, and you can feed it your paths two ways:
char * p0 = "/my/path" ;
char * p1 = "/my/other/path" ;
char * p2 = "/another/path" ;
/* with a fixed-size array */
char * pp[] = {p0, p1, p2, NULL} ;
FTS * fts_result = fts_open(pp, 0, NULL);
Edit 2011-11-10: snogglethorpe rightfully commented this solution is not a C89 valid solution, even if it compiles successfully with gcc (excluding pendantic + C89 flags). See Error: initializer element is not computable at load time for more info on that
or:
/* with a malloc-ed array */
char ** pp = malloc(4 * sizeof(char *)) ;
pp[0] = p0 ;
pp[1] = p1 ;
pp[2] = p2 ;
pp[3] = NULL ;
FTS * fts_result2 = fts_open(pp, 0, NULL);
free(pp) ;
Edit
After reading others answers, only two of them (mkb and moshbear) avoid the "just cast the data" error.
In my own answer, I forgot the NULL terminator for the array (but then I don't know the Linux API, nor the fts_* class of functions, so...)
I'm assuming you're talking about fts_open:
FTS *fts_open(char * const *path_argv, int options,
int (*compar)(const FTSENT **, const FTSENT **));
What it's wanting of you is an array of const char* pointers, ie. an array of strings. The const is there just to tell you that it's not going to modify your strings, and gives you the opportunity to pass const strings.
Non-const variables can be treated as const, however you shouldn't usually treat them the other way around.
The first argument is just like argv passed to main, you could just have:
char *path_argv[] = { "/first_path/", "/second_path/", NULL };
It's important that the last element is NULL to indicate the end of the array.
Note also that path_argv could also be declared as:
char **path_argv
OR*
char * const *path_argv
Any of these are suitable types to be passed as the first argument to fts_open. You do, however, obviously have to initialize it differently than the above, but those are other ways you can declare path_argv. I made that unclear previously.
And then just fts_open(path_argv, options, compar), where options is your options, and compar is your compare function.
You need to make a second array, which is NULL-terminated (because fts()'s first argument is argv).
E.g.
char *const buf2[2] = { buf, NULL };
fts(buf2);
In short, I would like to do this:
const char **stringPtr = &getString();
However, I understand that you can't & on rvalues. So I'm stuck with this:
const char *string = getString();
const char **stringPtr = &string;
I can live with two lines. Am I introducing problems with this hack? I should have no fear of passing stringPtr out of the function it is declared in, right?
Edit: My apologies for not originally including the full context.
I have taken on the summer project of building a video game from the ground up in C using OpenGL for graphics. I'm reading configuration data from a text file using libconfig.
One of the convenience functions for finding a specific string from your configuration file looks like this:
int config_setting_lookup_string(const config_setting_t *setting,
const char *name, const char **value)
{
config_setting_t *member = config_setting_get_member(setting, name);
if(! member)
return(CONFIG_FALSE);
if(config_setting_type(member) != CONFIG_TYPE_STRING)
return(CONFIG_FALSE);
*value = config_setting_get_string(member);
return(CONFIG_TRUE);
}
The way that value is assigned means that if you give the function an uninitialized value, it attempts to derefence undefined garbage, which pretty much always causes me a segfault. My current workaround for this issue is to initialize value to another pointer first, like so:
const char *dummyPtr;
const char **fileName = &dummyPtr;
config_setting_lookup_string(foo, "bar", fileName);
So I am trying to figure out the best way to rewrite the last part of the function so that I won't have to perform this two-step initialization. I was thinking that the changed function would look like this:
int config_setting_lookup_string(const config_setting_t *setting,
const char *name, const char **value)
{
config_setting_t *member = config_setting_get_member(setting, name);
if(! member)
return(CONFIG_FALSE);
if(config_setting_type(member) != CONFIG_TYPE_STRING)
return(CONFIG_FALSE);
const char *string = config_setting_get_string(member);
value = &string;
return(CONFIG_TRUE);
}
If you're calling a function that needs a const char**, you could do it like this:
const char *s = getString();
myFunction(&s);
Since s is allocated on the stack in the above example, if you want to return a const char** from your function, you will need to put it on the heap instead:
const char **sp = malloc(sizeof(const char *));
*sp = getString();
return sp;
HTH
string in your case is a local, so taking the address of it is a bad idea since the memory for the local can (and likely will be) re-used for other purposes when you leave the method. In general, it is not a good idea to use the address of a local variable outside of its scope.
What are you trying to achieve?
No, you can't change config_setting_lookup_string() in the way you've described. You're returning a pointer to the string variable, but as soon as that function ends that variable goes out of scope and is destroyed.
You can, however, fix your initial problem quite easily. Leave the definition of config_setting_lookup_string() as it is, and call it like so:
const char *fileName = NULL;
config_setting_lookup_string(foo, "bar", &fileName);
From the added information, it seems what you are trying to do is call a function which wants to return a string through one of the function arguments. The best way to do this in my opinion would be something like:
const char* fileName;
config_setting_lookup_string(..., &fileName);
(...)
return fileName;
This will allocate room for a const char* on the stack. The function call will fill the pointer with the address of the string it wants to return. This pointer value can then be passed out of the function if needed (unlike the pointer to the pointer, which would point to the stack, and be invalid when the function returns).
Note that initializing fileName with "getString()" would presumably leak memory, since the pointer to the returned string would be overwritten, and the string never deallocated.
You need the two lines. However, string is a local variable on the stack, once it goes out of scope, you may not have a pointer to the data returned by getString().
I like nornagon and caf's solution,
const char *fileName;
config_setting_lookup_string(foo, "bar", &fileName);
but if you can change config_setting_lookup_string you could also do it this way:
int config_setting_lookup_string(..., const char *&value)
{
...
const char *string = config_setting_get_string(member);
value = string;
...
}
const char *fileName;
config_setting_lookup_string(foo, "bar", fileName);
If you return stringPtr, you will be returning a pointer to a local variable (string). So no, you can't do that.
Why are you trying to do this? That might allow us to make better suggestions.
Update:
Okay, now I see what you're trying to do. You're doing it wrong:
value = &string;
If value is meant as an output parameter, the above line cannot work because you're assigning to a local variable.
Don't let the extra level of indirection confuse you. If you were writing a function that had an output parameter of type T, you'd write it as:
void foo(T* value)
{
*value = GetT();
}
Now replace T with const char*:
...
*value = string;
...
And now you're not involving any temporary, local variables. Of course, that's how the code was originally written (and that part of it was correct), so that doesn't really help you. To address your intent, you should:
Make config_setting_lookup_string do assert(value != NULL).
Audit the callers of the function and fix them to stop passing garbage. They should be doing:
const char* foo;
config_setting_lookup_string(..., &foo);
and NOT:
const char** foo;
config_setting_lookup_string(..., foo);