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.
Related
I want to implement my own string implementation for education. For that I defined a struct named string as follows:
struct string {
const char *const data;
const int length;
};
I use functions to create these string structs and then I assign them to variables.
In order to override the const int length I use the following trick:
*(int *) &result.length = // a int
Now I also want to write to the const char *const data.
As far as I know the first const makes sure that you cant edit the items at which the pointer points, and the second const is that you can't point the pointer to a different memory location. These are properties of an immutable string. So my question is: How can I assign something to the const char *const data like I did to the const int length?
Edit: result as shown above is an instance of the struct string
Form the struct string at its declaration and initialize it.
Also recommend to store the size and not the length and use size_t.
#include <stdio.h>
#include <stdlib.h>
struct string {
const char * const data;
const size_t size;
};
struct string string_copy(const char *src) {
size_t size = strlen(src) + 1;
char *copy = malloc(size);
if (copy) {
memcpy(copy, src, size);
} else {
size = 0;
}
struct string retval = {copy, size}; // ****
return retval;
// or return a compound literal (C99)
return (struct string){ copy, size};
}
void string_free(struct string s) {
free((void*)s.data);
}
int main(void) {
struct string a = string_copy("Hello");
printf("%zu <%s>\n", a.size, a.data);
string_free(a);
// do not use `a` subsequently
return 0;
}
I do not recommend to initialize with a string literal like struct string retval = {"World", 6}; as that limits the usefulness of struct string.
Using a opaque struct has many advantages #Jonathan Leffler that exceed this approach - mainly to keep other code from messing with the struct string.
On ARM-GCC in C
when defining a const string array and accessing it directly the strings are correctly placed in the .rodata section.
If I however have a struct with a pointer to the string array placed in .data section and uses ram. How can I put myStrings into a read only section and save ram?
const char * myStrings[] = {"String1", "String2"}; //.rodata
const char * myStrings2[] = {"String3", "String4"}; //.data
typdef struct {
const char ** strings;
int a;
} mystruct_t;
const mystruct_t mystruct = {myStrings2,2};
void main()
{
for(uint8_t i=0;i<2;i++)
{
printf("%s",myStrings[i]);
printf("%s",mystruct.strings[i]);
}
}
edit: provided minimal code.
as #Dmitri pointed out, only the pointers to the strings are stored in ram. This can be avoided by declaring them constant as well
const char * const myStrings2[] = {"String3", "String4"};
typdef struct {
const char * const * strings;
int a;
} mystruct_t;
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
I have one function:
int compare(char * c1, char * c2){
...
...
}
What are the various styles in which I can write a function int ret_compare(void * item) that returns a pointer to compare?
There are two main styles, one using a typedef and one not (with two variants of the typedef). Your comparator should take constant pointers, as below:
int compare(const char *c1, const char *c2) { ... }
// Raw definition of a function returning a pointer to a function that returns an int
// and takes two constant char pointers as arguments
int (*ret_compare1(void *item))(const char *, const char *)
{
// Unused argument - item
return compare;
}
// More usual typedef; a Comparator2 is a pointer to a function that returns an int
// and takes two constant char pointers as arguments
typedef int (*Comparator2)(const char *, const char *);
// And ret_compare2 is a function returning a Comparator2
Comparator2 ret_compare2(void *item)
{
// Unused argument - item
return compare;
}
// Less usual typedef; a Comparator3 is a function that returns an int
// and takes two constant char pointers as arguments
typedef int Comparator3(const char *, const char *);
// And ret_compare3 is a function returning a pointer to a Comparator3
Comparator3 *ret_compare3(void *item)
{
// Unused argument - item
return compare;
}
Note that these comparators cannot be used with bsearch() and qsort() (unless you use fairly gruesome casts) because those comparators are expected to take const void * arguments.
Note, too, that for comparing strings, as opposed to single characters, the function used by qsort() or bsearch() should be similar to:
int string_comparator(const void *v1, const void *v2)
{
const char *s1 = *(char **)v1;
const char *s2 = *(char **)v2;
return(strcmp(s1, s2));
}
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);