How to put values to const char **? - c

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);

Related

Best way to pass a string array to a function imposing const-ness in all levels down

In C we cannot assign a char** to const char *const * because of this problem. So, what's the base way to declare a function accepting an array of strings?
My input parameters may be of any types, including:
char **
const char **
...
I end up using the Antti Haapala's suggestion (thank you Antti Haapala!). Using const char * const * as the argument type and explicitly casting incompatible types.
#define STR_ARR(v) _Generic((v), \
char**: (const char *const *)(v), \
char *const *: (const char *const *)(v), \
default: (v))
void foo(const char * const * strings);
Usage:
char **strs1;
foo(STR_ARR(strs1));
const char **strs2;
foo(STR_ARR(strs2));
The best way is to have the caller sort their code out. Otherwise you can do a type-safe wrapper macro along the lines of this:
#include <stdio.h>
void str_print_ro (const char* str_arr[], size_t n)
{
for(size_t i=0; i<n; i++)
{
puts(str_arr[i]);
}
}
#define str_print(arr,n) _Generic((arr), \
const char** : str_print_ro, \
char** : str_print_ro) ((const char**)(arr), n)
int main (void)
{
char* arr[] = {"hello", "world"};
str_print(arr, sizeof arr/sizeof *arr);
}
It probably doesn't make much sense to const-qualify the pointers themselves. If you for some reason need that too, then const char* const str_arr[] should sort it, and that one can be converted to from char** and const char** both.

char const *const *const varName

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

warning with const operator (in struct)

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.

strcpy() and strcat() giving errors in initialization & conversion. in C

invalid conversion from const char to const char* ,
initializing argument 2 of char* strcpy(char*, const char*) ,
invalid conversion from const char to const char* ,
initializing argument 2 of char* strcat(char*, const char*).
void subString(char s[])
{
char *sub;
char newS;
sub=s;
strcpy(newS,sub[0]);
strcat(newS,sub[1]);
printf("%s\n",newS);
return;
}
Please answer in terms of C language.
let s="abab"
you need to make newS a char* and allocate space for it...
char *newS = malloc(strlen(sub) + 1);

C: const vs no const ..how come this compiles?

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;

Resources