There are many times that I get compile errors when I use char* instead of const char*. So, I am not sure the actual difference, the syntax and the compile mechanism.
If you're after the difference between the two, just think of them as:
char* is a pointer that points to a location containing a value of type char that can also be changed. The pointer's value can be changed, i.e. the pointer can be modified to point to different locations.
const char* is a pointer, whose value can be also changed, that points to a location containing a value of type char that cannot be changed.
const char * means "pointer to an unmodifiable character." It's usually used for strings of characters that shouldn't be modified.
Say you're writing this function:
int checkForMatch(const char * pstr)
You've promised (through the function signature) that you will not change the thing pointed to by pstr. Now say part of checking for a match would involve ignore the case of letters, and you tried to do it by converting the string to upper case before doing your other checks:
strupr(pstr);
You'll get an error saying you can't do that, because strupr is declared as:
char * strupr(char* str);
...and that means it wants to be able to write to the string. You can't write to the characters in a const char * (that's what the const is for).
In general, you can pass a char * into something that expects a const char * without an explicit cast because that's a safe thing to do (give something modifiable to something that doesn't intend to modify it), but you can't pass a const char * into something expecting a char * (without an explicit cast) because that's not a safe thing to do (passing something that isn't meant to be modified into something that may modify it).
Of course, this is C, and you can do just about anything in C, including explicitly casting a const char * to a char * — but that would be a really, really bad idea because there is (presumably) some reason that the thing being pointed to by the pointer is const.
char * : non-constant pointer to non-constant character
const char * : non-constant pointer to constant character
char *const : constant pointer to non-constant character
const char * const : constant pointer to constant character
Reference [link]
I always try to define parameters with const char* not char* because converting from std::string to conts char* is easy by .c_str() method. However converting std::string to char* is not that easy.
Probably I'm too picky. In my book, the character(s) pointed to by a const char* can possibly be changed but not via the const char*. A const char * can point to modifiable storage. Example:
char a[] = "abracadabra";
const char * ccp = &a[0]; // ccp points to modifiable storage.
*&a[0] = 'o'; // This writes to a location pointed to by const char* ccp
So, my wording is:
A char * is a pointer that be changed and that also allows writing through it when dereferenced via * or [].
A const char * is a pointer that be changed and that does not allow writing through it when dereferenced via * or [].
Related
I implemented my own strcpys to find if there is any difference between src as const char* & char *, but don't find any difference between the following 2 & both worked the same.
char * my_strcpy(char*dest, char* src)
{
while ('\0' != *src)
*dest++ = *src++;
*dest++ = '\0';
return dest;
}
char * my_strcpy2(char*dest, const char* src)
{
while ('\0' != *src)
*dest++ = *src++;
*dest++ = '\0';
return dest;
}
Is there any reason that the strcpy takes the source pointer as const char* instead of char*?
Is there any reason that the strcpy takes the source pointer as char* instead of const char*?
The source pointer should be const char *. The reason is common for all functions (not just strcpy) that do not intend to change the source accidentally inside the function.
The practice applies to both library functions like strcpy or your own custom functions. As with library function like strcpy there is no chance that the source is accidentially changed. But for your own (or everyone else) custom function, anything can happen. And if you do modify it accidentially, then you would get a compile error telling you so. And that's when the const is making a difference.
"don't find any difference between the following 2" -- what could the differences be, in your wildest dreams?
The only difference the const declaration has is on the caller side. By the const parameter declaration the function promises not to change the memory accessed through the pointer. It promises only to read through it, which is consistent with the semantics of strcpy(). (Note: Whether the function actually does not write through the pointer is not guaranteed at all. But it promises.)
The caller can therefore call the function with a pointer to constant data and assume that the function will not attempt to write to it.
That is important syntactically, logically and materially:
The language permits the caller to provide a pointer to const data as the argument (it would not allow that for your first non-const version).
The caller can be sure that sensitive data is not altered inside the function as a side effect; imagine a pointer into kernel data structures here. (Counter-example: strtok() writes to the original string, which is therefore not declared const!)
The data may be physically read-only (like, it may be burned into the ROM of a controller), so that an attempt to write to it would cause, well, to quote the excellent Max Barry: a "catastrophic system failure. (...) I'm not saying it's a big deal."
For starters function strcpy returns pointer to the destination string. Your function should also return pointer to the destination string. It is a common convention for functions that process strings in the C Standard.
So the function can look the following way
char * my_strcpy( char *dest, const char *src )
{
char *p = dest;
while ( *p++ = *src++ );
return dest;
}
In this case it can be called for example the following way
const char *hello = "Hello, World!";
char s[14];
puts( s, hello );
Specifying the second parameter of the function as a pointer to a constant character string means 1) that the function guarantees that it will not change the pointed string and 2) allows to pass to the function constant strings.
A pointer to a non-constant object can be implicitly converted to a pointer to constant object. The reverse operation is not allowed without explicit casting.
So if the parameter is declared like pointer to a constant string then you can pass non-constant strings along with constant strings to the same function as arguments. Otherwise the function can not be called with constant strings because the compiler will issue an error saying that it unable to convert an object of type const char * to an object of type char *.
I implemented my own strcpys to find if there is any difference between src as const char* & char *, but don't find any difference between the following 2 & both worked the same.
char * my_strcpy(char*dest, char* src)
{
while ('\0' != *src)
*dest++ = *src++;
*dest++ = '\0';
return dest;
}
char * my_strcpy2(char*dest, const char* src)
{
while ('\0' != *src)
*dest++ = *src++;
*dest++ = '\0';
return dest;
}
Is there any reason that the strcpy takes the source pointer as const char* instead of char*?
Is there any reason that the strcpy takes the source pointer as char* instead of const char*?
The source pointer should be const char *. The reason is common for all functions (not just strcpy) that do not intend to change the source accidentally inside the function.
The practice applies to both library functions like strcpy or your own custom functions. As with library function like strcpy there is no chance that the source is accidentially changed. But for your own (or everyone else) custom function, anything can happen. And if you do modify it accidentially, then you would get a compile error telling you so. And that's when the const is making a difference.
"don't find any difference between the following 2" -- what could the differences be, in your wildest dreams?
The only difference the const declaration has is on the caller side. By the const parameter declaration the function promises not to change the memory accessed through the pointer. It promises only to read through it, which is consistent with the semantics of strcpy(). (Note: Whether the function actually does not write through the pointer is not guaranteed at all. But it promises.)
The caller can therefore call the function with a pointer to constant data and assume that the function will not attempt to write to it.
That is important syntactically, logically and materially:
The language permits the caller to provide a pointer to const data as the argument (it would not allow that for your first non-const version).
The caller can be sure that sensitive data is not altered inside the function as a side effect; imagine a pointer into kernel data structures here. (Counter-example: strtok() writes to the original string, which is therefore not declared const!)
The data may be physically read-only (like, it may be burned into the ROM of a controller), so that an attempt to write to it would cause, well, to quote the excellent Max Barry: a "catastrophic system failure. (...) I'm not saying it's a big deal."
For starters function strcpy returns pointer to the destination string. Your function should also return pointer to the destination string. It is a common convention for functions that process strings in the C Standard.
So the function can look the following way
char * my_strcpy( char *dest, const char *src )
{
char *p = dest;
while ( *p++ = *src++ );
return dest;
}
In this case it can be called for example the following way
const char *hello = "Hello, World!";
char s[14];
puts( s, hello );
Specifying the second parameter of the function as a pointer to a constant character string means 1) that the function guarantees that it will not change the pointed string and 2) allows to pass to the function constant strings.
A pointer to a non-constant object can be implicitly converted to a pointer to constant object. The reverse operation is not allowed without explicit casting.
So if the parameter is declared like pointer to a constant string then you can pass non-constant strings along with constant strings to the same function as arguments. Otherwise the function can not be called with constant strings because the compiler will issue an error saying that it unable to convert an object of type const char * to an object of type char *.
Your answers are very much sought to clear this major lacuna in my understanding about const that I realized today.
In my program I have used the statement const int *ptr=&i; but haven't used any const qualifier for the variable i.Two things are confusing me:
1) When I try to modify the value of i using ptr ,where I have used const int *ptr=&i;,I get the error assignment of read-only location '*ptr'|,even though I haven't declared the variable i with the const qualifier.So what exactly the statement const int *ptr=&i; mean and how does it differ from int * const ptr=&i;?
I had it drilled into my head that const int *ptr=&i; means that the pointer stores the address of a constant,while int * const ptr=&i; means the pointer is itself constant and can't change.But today one user told me in discussion(LINK) that const int *ptr means the memory pointed to must be treated as nonmodifiable _through this pointer_.I find this something new as this kinda means "some select pointer can't alter the value(while others can)".I wasn't aware of such selective declarations!!But a 180k veteran attested to it that that user is correct!!.So can you state this in a clearer,more detailed and more rigorous way?What exactly does ``const int *ptr=&i; mean?
2) I was also told that we can lie to the program in the statement const int *ptr=&i; by assigning the address of a non-constant to the pointer.What does it mean?Why are we allowed to do that?Why don't we get a warning if we assign the address of a non-constant to the pointer ptr which expects address of a constant?And if it is so forgiving about being assigned address of non-constant,why it throws an error when we try to change the value of that non-constant,which is a reasonable thing to do,the pointed variable being a non-constant?
#include <stdio.h>
int main ()
{
int i=8;
const int *ptr=&i;
*ptr=9;
printf("%d",*ptr);
}
error: assignment of read-only location '*ptr'|
The definition const int *ptr = &i; essentially says “I will not modify i through ptr.” It does not say that the int that ptr points to is const, it says that ptr should not be used to modify it.
This conversion is allowed because it makes sense: Since i is not const, I am allowed to modify it, but I can also choose not to modify it. No rule is broken when I choose not to modify i. And, if I create a pointer to i and say “I am not going to use this pointer to modify i”, that is fine too.
The reason you would want to do this is so that you can pass the address of an object to a routine that takes a pointer to a const object. For example, consider the strlen routine. The strlen routine does not modify its input, so its parameter is a pointer to const char. Now, I have a pointer to char, and I want to know its length. So I call strlen. Now I am passing a pointer to char as an argument for a parameter that is pointer to const char. We want that conversion to work. It makes complete sense: I can modify my char if I want, but the strlen routine is not going to, so it treats them as const char.
1) You get an error with *ptr = something; because you declared ptr as a pointer to const int, but then you violated your promise not to use ptr to modify the int. The fact that ptr points to an object that is not const does not negate your promise not to use ptr to modify it.
2) It is not a lie to assign the address of a non-const object to a pointer to const. The assignment does not say that the object is const, it says that the pointer should not be used to modify the object.
Additionally, although you have not asked this, the const attribute in C is not completely binding. If you define an object to be const, you should not modify it. However, there are other situations in which a pointer to const is passed to a routine that converts it to a pointer to non-const. This is effectively a defect in the language, an inability to retain all the information necessary to handle const in the ways we might prefer. An example is the strchr routine. Its declaration is char *strchr(const char *s, int c). The parameter s is const char * because strchr does not change its input. However, the pointer that strchr routines is derived from s (it points to one of the characters in the string). So, internally, strchr has converted a const char * to char *.
This allows you to write code that passes a char * to strchr and uses the returned pointer to modify the string, which is fine. But it means the compiler cannot completely protect you from mistakes such as passing a const char * to strchr and using the returned pointer to try to modify the string, which may be an error. This is a shortcoming in C.
Unravelling this:
const int *ptr means that "*ptr is a const int"; i.e. "ptr is a pointer to a const int". You can't write *ptr = 9 since *ptr is a constant. You can however write int j; ptr = &j; since you can allow the pointer ptr to point at a different int.
int * const ptr means "ptr is a constant pointer to an int". You can write *ptr = 9 since you are not changing the address that ptr is pointing to. You can't assign it to something else though; i.e. int j; ptr = &j; will not compile.
As for the second part (2), it's very useful to have const int* ptr, especially in function prototypes since it tells the caller of the function that the variable to which ptr is pointing will not be modified by the function. As for assignment, if you had int* m = &i, then ptr = m is ok but m = ptr is not ok since the latter will 'cast away the constness'; i.e. you've circumvented the const.
How would I go about defining the following string for the following function?
As of now I get the warning:
C4047: '=' : 'const char' differs in levels of indirection from 'char [4]'
and the error:
C2166: l-value specifies const object.
Both in the third line of the code below:
uint8_t *buffer= (uint8_t *) malloc(sizeof(uint32_t));
const char *stringaling= (const char *) malloc(sizeof(uint32_t));
*stringaling = "fun";
newval = protobuf_writeString (buffer, stringaling);
uint32_t protobuf_writeString(uint8_t *out,const char * str)
{
if (str == NULL)
{
out[0] = 0;
return 1;
}
else
{
size_t len = strlen (str);
size_t rv = uint32_pack (len, out);
memcpy (out + rv, str, len);
return rv + len;
}
}
const char *stringaling= (const char *) malloc(sizeof(uint32_t));
*stringaling = "fun";
This is not valid code. You are trying to assign to a const variable, which is illegal. Then you are trying to assign an array of characters to a character. And finally, even if you had a non-const array of characters of the right size, you still can't assign arrays, because they're not first-class values.
Try using
char *stringaling = malloc(sizeof(uint32_t));
strcpy(stringaling, "fun");
...instead, and see if that doesn't work better. Note, however, that it's pretty much accidental that (at least usually) sizeof(uint32_t) happens to be the right size to hold "fun". You normally don't want to do that.
Alternatively, you may want:
char const *stringaling = "fun";
or:
char stringaling[] = "fun";
The assignment you had won't work though -- C has only the very most minimal support for strings built into the language; most operations (including copying a string) are normally done via library functions such as strcpy.
"fun" is a string literal, which is essentially a const char *.
stringaling is also a const char *, so your third line is trying to assign a const char * to a const char, which is not going to fly.
If it's a constant string, you can just do this:
const char *stringaling = "fun";
If your input string is dynamic, you can do this:
char *stringaling= (char *) malloc(strlen(inputString)+1);
strcpy(stringaling, inputString);
Obviously, if you malloc it, you need to free it, or feel the wrath of a memory leak.
If you really want to initialize the char *, you could write this instead:
const char *stringaling = "fun";
And here's some reference.
without all the stuff you can also use:
newval = protobuf_writeString (buffer, "fun" );
First problem:
const char *stringaling= (const char *) malloc(sizeof(uint32_t));
Several problems on this line.
First of all, you don't want to declare stringaling as const char *; you will not be able to modify whatever stringaling points to (IOW, *stringaling will not be writable). This matters since you want to copy the contents of another string to the location pointed to by stringaling. Drop the const keyword.
Secondly, malloc(sizeof(uint32_t)) just happens to allocate enough bytes (4) for this particular string, but it's not clear that you meant to allocate 4 bytes. When allocating memory for an array (and strings are arrays), explicitly indicate the number of elements you intend to allocate.
Finally, casting the result of malloc is considered bad practice in C. The cast will suppress a useful diagnostic message if you forget to include stdlib.h or otherwise don't have a prototype for malloc in scope. As of the 1989 standard, malloc returns void *, which can be assigned to any other object pointer type without needing to cast. This isn't true in C++, so a cast is required there, but if you're writing C++ you should be using new instead of malloc anyway.
So, change that line to read
char *stringaling = malloc(LEN); // or malloc(LEN * sizeof *stringaling), but
// in this case that's redundant since
// sizeof (char) == 1
where LEN is the number of chars you want to allocate.
The general form for a malloc call is
T *p = malloc (N * sizeof *p);
where T is the base type (int, char, float, struct ..., etc.), and N is the number of elements of type T you want to allocate. Since the type of the expression *p is T, sizeof *p == sizeof(T); if you ever change the type of p, you don't have to replicate that change in the malloc call itself.
Second problem:
*stringaling = "fun";
Again, there are several issues at play. First, you cannot assign string values using the = operator. String literals are array expressions, and in most contexts array expressions have their type implicitly converted ("decay") from "N-element array of T" to "pointer to T". Instead of copying the contents of the string literal, you would be simply assigning a pointer to the first character in the string.
Which would "work" (see below), except that you're dereferencing stringaling in the assignment; the type of the expression *stringaling is const char (char after making the change I indicated above), which is not compatible for assignment with type char *. If you drop the dereference operator and write
stringaling = "fun";
you'd fix the compile-time error, but now you have another problem; as mentioned above, you haven't copied the contents of the string literal "fun" to the memory block you allocated with malloc; instead, you've simply copied the address of the string literal to the variable stringaling. By doing so, you lose track of the dynamically-allocated block, causing a memory leak.
In order to copy the string contents from one place to another, you'll have to use a library function like strcpy or strncpy or memcpy, like so:
strcpy(stringaling, "fun");
If stringaling doesn't need to live on the heap (for example, you're only using it within a single function and deallocating it before returning), you could avoid memory management completely by declaring it as a regular array of char and initializing it with "fun":
char stringaling[] = "fun";
This is a special case of initializing an array in a declaration, not an assignment expression, so the = does copy the contents of the string literal to the stringaling array. This only works in an array declaration, however. You can later modify the array with other string values (up to 3 characters plus the 0 terminator), but you'd have to use strcpy again:
strcpy(stringaling, "one");
If you don't need to modify the contents of stringaling, you could just do
const char *stringaling = "fun";
This copies the address of the string literal "fun" to the variable stringaling. And since attempting to modify the contents of a string literal invokes undefined behavior, we do want to declare stringaling as const char * in this case; that will prevent you from accidentally modifying the string literal.
The standard C library functions strtof and strtod have the following signatures:
float strtof(const char *str, char **endptr);
double strtod(const char *str, char **endptr);
They each decompose the input string, str, into three parts:
An initial, possibly-empty, sequence of whitespace
A "subject sequence" of characters that represent a floating-point value
A "trailing sequence" of characters that are unrecognized (and which do not affect the conversion).
If endptr is not NULL, then *endptr is set to a pointer to the character immediately following the last character that was part of the conversion (in other words, the start of the trailing sequence).
I am wondering: why is endptr, then, a pointer to a non-const char pointer? Isn't *endptr a pointer into a const char string (the input string str)?
The reason is simply usability. char * can automatically convert to const char *, but char ** cannot automatically convert to const char **, and the actual type of the pointer (whose address gets passed) used by the calling function is much more likely to be char * than const char *. The reason this automatic conversion is not possible is that there is a non-obvious way it can be used to remove the const qualification through several steps, where each step looks perfectly valid and correct in and of itself. Steve Jessop has provided an example in the comments:
if you could automatically convert char** to const char**, then you could do
char *p;
char **pp = &p;
const char** cp = pp;
*cp = (const char*) "hello";
*p = 'j';.
For const-safety, one of those lines must be illegal, and since the others are all perfectly normal operations, it has to be cp = pp;
A much better approach would have been to define these functions to take void * in place of char **. Both char ** and const char ** can automatically convert to void *. (The stricken text was actually a very bad idea; not only does it prevent any type checking, but C actually forbids objects of type char * and const char * to alias.) Alternatively, these functions could have taken a ptrdiff_t * or size_t * argument in which to store the offset of the end, rather than a pointer to it. This is often more useful anyway.
If you like the latter approach, feel free to write such a wrapper around the standard library functions and call your wrapper, so as to keep the rest of your code const-clean and cast-free.
Usability. The str argument is marked as const because the input argument will not be modified. If endptr were const, then that would instruct the caller that he should not change data referenced from endptr on output, but often the caller wants to do just that. For example, I may want to null-terminate a string after getting the float out of it:
float StrToFAndTerminate(char *Text) {
float Num;
Num = strtof(Text, &Text);
*Text = '\0';
return Num;
}
Perfectly reasonable thing to want to do, in some circumstances. Doesn't work if endptr is of type const char **.
Ideally, endptr should be of const-ness matching the actual input const-ness of str, but C provides no way of indicating this through its syntax. (Anders Hejlsberg talks about this when describing why const was left out of C#.)