I have a method that is having the following signature:
size_t advanceToNextRuleEntryRelatedIndex( size_t index, size_t nStrings, char const *const *const strings)
How do I interpret this: char const *const *const strings?.
Thanks,
Pavan.
char const *const *const strings
^ v ^ v ^ v
| | | | | |
+----- +--+ +--+
so basically it means all pointers and the strings that the pointers point to are constant, meaning the function cannot modify the passed strings in any way (except if it gets casted).
e.g.
char* p[] = {"string1","string2"};
which will decay into char**
when passed to
int n = 0;
advanceToNextRuleEntryRelatedIndex( n, 2, p);
In char const *const *const strings, strings is a pointer to a char pointer. Without the const qualifiers it would look like this:
char **strings;
The const qualifiers prohibit modifying the dereferenced value at the particular level of dereferencing:
**strings = (char) something1; // not allowed because of the first const
*strings = (char *) something2; // not allowed because of the second const
strings = (char **) something3; // not allowed because of the third const
In other words, the third const says that the pointer itself is immutable, the second const says that the pointed-to pointer is immutable and the first says that the pointed-to character is immutable.
The key-word const makes the declaration after this key-word to a constant.
The code explains better than words:
/////// Test-code. Place anywhere in global space in C/C++ code, step with debugger
char a1[] = "test1";
char a2[] = "test2";
char *data[2] = {a1,a2};
// Nothing const, change letters in words, replace words, re-point to other block of words
char **string = &data[0];
// Can't change letters in words, but replace words, re-point to other block of words
const char **string1 = (const char **) &data[0];
// Can neither change letters in words, not replace words, but re-point to other block of words
const char * const* string2 = (const char * const*) &data[0];
// Can change nothing, however I don't understand the meaning of the 2nd const
const char const* const* const string3 = (const char const* const* const ) &data[0];
int foo()
{
// data in debugger is: {"test1","test2"}
**string = 'T'; //data is now {"Test1","test2"}
//1 **string1 = 'T'; //Compiler error: you cannot assign to a variable that is const (VS2008)
*string1=a2; //data is now {"test2","test2"}
//2 **string2='T'; //Compiler error: you cannot assign to a variable that is const (VS2008)
//3 *string2=a2; //Compiler error: you cannot assign to a variable that is const (VS2008)
string2=string1;
//4 **string3='T'; //Compiler error: you cannot assign to a variable that is const (VS2008)
//5 *string3=a2; //Compiler error: you cannot assign to a variable that is const (VS2008)
//6 string3=string1; //Compiler error: you cannot assign to a variable that is const (VS2008)
return 0;
}
static int dummy = foo();
/////// END OF Test-code
Related
it may be a nooby question but i cant figure out why i get a warning
struct4.c:32:15: warning: assignment discards ‘const’ qualifier from pointer target type [enabled by default] crea[i].size = wsize[i%5];
compiling this:
struct shirt {
char *size;
char *colour;
} ;
typedef struct shirt Camicia;
void loadshirt (Camicia * const crea, const char *wsize[] , const char *wcolour[]);
int main (void) {
Camicia collezione[50];
const char *sizearray[] = {"xs","s","m","l","xl"};
const char *colourarray[] = {"black","blue","yellow","orange"};
loadshirt(collezione,sizearray,colourarray);
printf("%s\n",collezione[4].size);
printf("%s\n",collezione[4].colour);
return 0;
}
void loadshirt (Camicia * const crea, const char *wsize[] , const char *wcolour[]) {
int i=0;
while (i<50) {
crea[i].size = wsize[i%5];
crea[i].colour = wcolour[i%4];
i++;
}
}
You defined data members of the structure as pointers to non-const character strings.
struct shirt {
char *size;
char *colour;
} ;
However in the function you are assigning pointers to const character strings to pointers to non-const character strings
crea[i].size = wsize[i%5];
crea[i].colour = wcolour[i%4];
See declarations of wsize and wcolour in the parameter list
const char *wsize[] , const char *wcolour[]
You may not do that.
Define the data members as pointers to const strings
struct shirt {
const char *size;
const char *colour;
} ;
Or define the parameters as having type of pointers to non-const strings
char *wsize[] , char *wcolour[]
In this case you have to change also the definitions of the corresponding arguments
char *sizearray[] = {"xs","s","m","l","xl"};
char *colourarray[] = {"black","blue","yellow","orange"};
In C strings literals have types of non-const arrays.
Here your function takes a const pointer to a Camicia
void loadshirt (Camicia const * crea, const char *wsize[] , const char *wcolour[]) {
And 3 lines later you try to modify crea :
crea[i].size = wsize[i%5];
crea[i].colour = wcolour[i%4];
You can't do that.
When the compiler says something along the lines of X discards 'const' qualifier it means exactly that. Something is const, but you're trying to modify it as if it weren't.
It's important to try to understand the compiler's error messages, you'll save a lot of time.
Now if you want to fix the function, first you'll need to remove the const qualifier from crea in the list of parameters.
But also note that here wsize and wcolour are const, while Camicia is defined like this:
struct shirt {
char *size;
char *colour;
} ;
typedef struct shirt Camicia;
Either make your struct Camicia store const char* or modify the other parameters to be char*. Since you're using string literals in main, you'll probably want everything to be const char*.
to avoid the runtime seg fault events,
the following code will work correctly.
this code takes into account that the arrays in main()
are actually an array of pointers to char* (I.E. strings)
#include <stdio.h>
#include <stdlib.h>
#define MAX_SHIRTS (50)
struct shirt {
const char *size;
const char *colour;
} ;
// struct shirt * const says the pointer is const,
// not that the contents of where the pointer points is const
void loadshirt (struct shirt * const, const char **, const char **);
int main (void) {
struct shirt collezione[MAX_SHIRTS];
// create two arrays of const pointers to consts
const char const *pSize[] = {"xs","s","m","l","xl"};
const char const *pColour[] = {"black","blue","yellow","orange"};
loadshirt(collezione, pSize, pColour);
printf("%s\n",collezione[4].size);
printf("%s\n",collezione[4].colour);
return 0;
}
void loadshirt (struct shirt * const crea, const char **pSize , const char **pColour)
{
int i=0;
for(i=0; i<MAX_SHIRTS; i++)
{
crea[i].size = pSize[i%5];
crea[i].colour = pColour[i%4];
}
}
You are making a non-const pointer to a const pointer, you can't modify the contents the const pointer points to, but if you discard const qualifier you can do it through the new non-const pointer, so the compiler is warning you about that.
I can't figure out why I get this warning from clang by myself:
function_prototype_const_modifier.c:13:8: warning: initializing 'char *' with an
expression of type 'const char *' discards qualifiers
[-Wincompatible-pointer-types]
char *ptr1 = source;
^ ~~~~~~
1 warning generated.
The code is very simple
#include<stdio.h>
char *my_strcpy(char *destination, const char *source);
int main(void) {
char str1[] = "this is something";
char str2[] = "123456789123456789";
my_strcpy(str2, str1);
puts(str2);
return 0;
}
char *my_strcpy(char *destination, const char *source) {
char *ptr1 = source;
char *ptr2 = destination;
while(*ptr1 != '\0') {
*ptr2++ = *ptr1++;
}
*ptr2 = '\0';
return destination;
}
any idea?
source is a const char *, a pointer to const characters, so the characters cannot be changed by dereferencing the pointer (i. e. source[0] = 'A'; is a constraint violation).
However, assigning it to a char * discards this constraint; a simple char * suggests that the characters pointed to by the ptr1 pointer are not constant and you can now freely write ptr1[0] = 'A'; without getting compiler errors (a "diagnostic message").
Consider what this means when you pass in a string literal. Since a string literal is "readonly" (it's a const char []), trying to modify its contents is undefined behavior. So if you call
my_strcpy(destination, "Constant String");
but in the code for some reason you write
ptr1[0] = 'A';
you won't get a compiler diagnostic message because ptr1 is a pointer to non-const chars, but your program will still invoke undefined behavior (and in practice, most likely crash, since string literals are placed in readonly memory regions).
You just need to change:
char *ptr1 = source;
to:
const char *ptr1 = source;
You are pointing to the same area in memory, but not qualifying it as const as well, which the argument is.
You then allow the function body to modify that part of memory which is labelled const.
Because type of L.H.S is char * and type of R.H.S is const char *.
The reason is exactly as what error says:
function_prototype_const_modifier.c:13:8: warning: initializing 'char *' with an expression of type 'const char *' discards qualifiers
The statement allows you to discard the const qualifier and it allows to modify the pointed string through ptr1 and ptr2 and hence the compiler complains.
You are assigning a pointer to a character constant to a pointer to a char.
By doing that you risk modifying the character(s).
In this case, just about what's we can do.
Thanks of clearness information for #user529758.
Just plus a answer.
Modified:
#include<stdio.h>
char *my_strcpy(char *destination, const char *source);
int main(void) {
char str1[] = "this is something";
char str2[] = "123456789123456789";
my_strcpy(str2, str1);
puts(str2);
return 0;
}
char *my_strcpy(char *destination, const char *source) {
char *ptr1 = (char*)source;
char *ptr2 = destination;
while(*ptr1 != '\0') {
*ptr2++ = *ptr1++;
}
*ptr2 = '\0';
return destination;
}
I am getting the following warning for two lines of my code.
initialization discards qualifiers from pointer target type
The two lines are the sources of the warning.
function (const char *input) {
char *str1 = input;
char *str2 = "Hello World\0";
}
I think the first line gives an error because I try to assign a const char* to a char*. How would I fix that?
You need to declare it const:
const char *str1 = input;
void function (const char *input) {
char *str1 = input;
char *str2 = "Hello World\0";
}
in C an object of type char * cannot be initialized with an object of type const char *.
You have do this instead:
const char *str1 = input;
Also a string literal like "Hello World" is already null terminated, there is no need to add the null character yourself, do this instead:
char *str2 = "Hello World";
I have a simple C function which I declare as:
int strLen(const char* str_)
{
str_ = (char*) 0;
return 0;
}
I was very surprised that that compiles! Why is that?
Whereas this onedoesn't compile (which makes sense):
int str(const int i_)
{
i_ = 0;
return 0;
}
Because const char* str_ says that str_ is a pointer to const characters.
You can change str_ itself, but not what it points to.
int strLen(const char* str_)
{
str_ = (char*) 0; /* allowed */
str_[0] = '\0'; /* not allowed */
return 0;
}
In the first one, you are changing what the pointer str_ points to; the pointer str_ is not const; it just points to const data. You can make the pointer const as follows:
int strLen(const char* const str_)
This follows the conventions of C declarations,
char *str;
means that *str will give you a char (or in other words, str is a pointer-to-a-char). Similarly,
const char *str;
means that *str will give you a const char, or in other words, str is a pointer-to-a-constant-char. So, you are not allowed to change *str, but you may change str.
If you want to make str itself const, use the following syntax:
char *const str;
If I declare a variable const char ** stringTable, how should I be able to put values to it if it is a const? (It has to be const because a function I am supposed to use takes const char ** as a parameter.)
Edit:
No you cannot convert from char ** to const char ** implicitly. Compiler complains:
cannot convert parameter 3 from 'char **' to 'const char **'
Wow, I'm surprised nobody got this! Maybe I can get a necromancer badge. Implicit const casting only scans one level deep. So a char* can become a const char* but it won't dig deep enough inside the a char** type to find what needs to be changed to make it a const char**.
#include <iostream>
using namespace std;
void print3( const char **three ) {
for ( int x = 0; x < 3; ++ x ) {
cerr << three[x];
}
}
int main() {
// "three" holds pointers to chars that can't be changed
const char **three = (const char**) malloc( sizeof( char** ) * 3 );
char a[5], b[5], c[5]; // strings on the stack can be changed
strcpy( a, "abc" ); // copy const string into non-const string
strcpy( b, "def" );
strcpy( c, "efg" );
three[0] = a; // ok: we won't change a through three
three[1] = b; // and the (char*) to (const char*) conversion
three[2] = c; // is just one level deep
print3( three ); // print3 gets the type it wants
cerr << endl;
return 0;
}
Apart from other mentions that you can pass char** into function that takes const char **,
const char** is a non-const pointer to const char*, you can declare it and freely put values of type const char* in it.
On the other hand, you would not be able to do it, if you declared it as const char * const * or const char * const * const.
yourfunc(const char **p);
...
const char *array_str[10];
array_str[0] = "foo"; /* OK, literal is a const char[] */
yourfunc(array_str);
Here is what cdecl says:
cdecl> explain const char **table
declare table as pointer to pointer to const char
cdecl> explain const char * const *table
declare table as pointer to const pointer to const char
cdecl> explain const char * const * const table
declare table as const pointer to const pointer to const char
That const declaration is a quarantee of the function, you dont have to fullfill it. That means the function will keep your array untouched (it will just read). So you can pass a nonconst variable to a function expecting const.
You can pass a char ** to a function declared as taking a const char ** -- Might be worth taking a look at the documentation for const on MSDN
char ** can be converted to const char **, so if you want to call a function which takes a const char ** as a parameter, just supply your char ** and it'll be implicitly converted.
If you want to write a function which takes a const char ** as parameter and then modifies the char data it references, you're breaking the contract with your compiler, even if you might get it to work via casts!
With my compiler (gcc version 3.4.4 in cygwin), I found that I could pass char * to const char *, but not char ** to const char **, unlike what most of the answers are saying.
Here is one way you can build something up that works; maybe it will help you.
void printstring( const char **s ) {
printf( "%s\n", *s );
}
int main( int argc, char** argv ) {
char *x = "foo"; // here you have a regular mutable string
const char *x2 = x; // you can convert that to a constant string
const char **y = &x2; // you can assign the address of the const char *
printstring(y);
}
you can un-const char* by using a cast operator: (char*)
void do_something(const char* s)
{
char* p=(char*)s;
p[0]='A';
}
use the same idea with the arrays char**
const char ** indicates that the underlying character is constant. So, while you can't do something like this:
const char **foo = ...;
**foo = 'a'; // not legal
but there is nothing preventing you from manipulating the pointer itself:
// all the following is legal
const char **foo = 0;
foo = (const char **)calloc(10, sizeof(const char *));
foo[0] = strdup("foo");
foo[1] = strdup("baz");
That said, if you did want to modify the actual character data, you could use a non-const pointer and cast it:
char **foo = ...;
func((const char **)foo);