I was always under the impression that const char **x
was the correct type to use for a dynamically allocated array of const strings, like so:
#include <stdlib.h>
int main()
{
const char **arr = malloc(10 * sizeof(const char *));
const char *str = "Hello!";
arr[0] = str;
free(arr);
}
However, when compiling this code with VS2017, I get this warning on the free
line:
warning C4090: 'function': different 'const' qualifiers
Is there something wrong with my code? FWIW, when I compile with GCC, I don't get any warnings, even with -Wall -Wextra -pedantic
.
It's easy to initialize a dynamic array to 0. Syntax: int *array{ new int[length]{} }; In the above syntax, the length denotes the number of elements to be added to the array.
Class std::string is already contains a dynamic string object and std::vector contains a dynamic array object.
Allocating Strings DynamicallyEdit In duplicating a string, s, for example we would need to find the length of that string: int len = strlen(s); And then allocate the same amount of space plus one for the terminator and create a variable that points to that area in memory: char *s2 = malloc((len + 1) * sizeof(char));
There is nothing wrong with your code. The rules for this are found in the C standard here:
6.3.2.3 Pointers
A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to the q-qualified version of the type; the values stored in the original and converted pointers shall compare equal.
Meaning that any pointer to object type (to a variable) may be converted to a void pointer, unless the pointer is qualified (const or volatile). So it is fine to do
void* vp;
char* cp;
vp = cp;
But it is not ok to do
void* vp;
const char* cp;
vp = cp; // not an allowed form of pointer conversion
So far so good. But when we mix in pointer-to-pointers, const
-ness is a very confusing subject.
When we have a const char** arr
, we have a pointer to pointer to constant char (hint: read the expression from right to left). Or in C standard gibberish: a pointer to a qualified pointer to type. arr
itself is not a qualified pointer though! It just points at one.
free()
expects a pointer to void. We can pass any kind of pointer to it unless we pass a qualified pointer. const char**
is not a qualified pointer, so we can pass it just fine.
A qualified pointer to pointer to type would have been char* const*
.
Note how gcc whines when we try this:
char*const* arr = malloc(10 * sizeof(char*const*));
free(arr);
gcc -std=c11 -pedantic-errors -Wall - Wextra
:
error: passing argument 1 of 'free' discards 'const' qualifier from pointer target type
Apparently, Visual Studio gives an incorrect diagnostic. Or alternatively you compiled the code as C++, which doesn't allow implicit conversions to/from void*
.
The assignment is valid for the same reason the following assignment is valid.
const char** arr = malloc(10 * sizeof(const char *));
void* p = arr;
This rule1 explains that the, if both operands are pointer types, the type left pointer is pointing to, must have the same qualifiers, as the type the right pointer is pointing to.
The right operand is a pointer that is pointing to a type that doesn't have any qualifiers. This type being type a type pointer to a const char (const char*
). Don't let that const qualifier confuse you, that qualifier dont't belong to the pointer type.
The left operand is a pointer that is pointing to a type that also doesn't have any qualifiers. The type being void. So the assignment is valid.
If the pointer is pointing to a type that has qualifiers, then the assignment would not be valid:
const char* const* arr = malloc(10 * sizeof(const char *));
void* p = arr; //constraint violation
The right operand is a pointer that is pointing to a type with the qualifier const, this type being a type const pointer to a const char (const char* const
).
The left operand is a pointer that is pointing to a type without any qualifiers, this type being type void. The assignment violates the constraint1.
1 (Quoted from: ISO/IEC 9899:201x 6.5.16.1 Simple assignment Constraints 1)
the left operand has atomic, qualified, or unqualified pointer type, and (considering
the type the left operand would have after lvalue conversion) one operand is a pointer
to an object type, and the other is a pointer to a qualified or unqualified version of
void, and the type pointed to by the left has all the qualifiers of the type pointed to
by the right;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With