I got this confusion while learning c++:
int *a = 8 ;
This gives an error because, as I have understood it, i am trying to set an integer to a pointer which is a memory location. But,
const char *name = "name";
works perfectly fine? I don't get it as name should be an hexadecimal memory location but i am trying to set it to a series of characters.
A string literal, "name" in your case, is of typeconst char[]. An array can decay to a pointer which is what's happening in this case. That pointer will then point to the first element in the array. Note that since C++11 assigning to a char* instead of a const char* (thus needing a conversion) as you are doing is illegal, always use const char* for string literals, or better yet, std::string.
8 is of type int, which has no conversion to a pointer type that an array has.
The rules for int* and char* are the same. However, you compare apples to oranges.
You cannot assign a value of the respective type to its pointer (it doesn’t matter whether there is a const here; I made things const for consistency with the next example where it matters to some extend):
int const* ip = 8; // ERROR
char const* cp = ‘8’; // ERROR
Arrays decay into pointers upon the slightest opportunity. String literals are arrays of type char const[N] where N is the number of chars in the string literal, including the terminating null char.
int ia[] = { 8 };
char ca[] = { ‘8’ };
int const* ip = ia; // OK
char const* cp = ca; // OK
char const* lp = “8”; // OK
Related
I am trying to understand how pointers,arrays and string literals work in C++.
Suppose we have the following line of code:
const char* const letters[] = {"A+","A"};
If I understand correctly, this declaration declares letters to be an array of constant pointers to constant characters. From my understanding, the compiler will actually convert each string literal to a null terminated char array and each element of letters is actually a constant pointer to the first element of that array.
So, for instance, letters[0] is actually a pointer to the "A" of "A+". However
std::cout<< letters[0];
actually outputs "A+" to the standard output. How can this be? Especially since letters[0] is a constant pointer?
My second question is related to the declaration above: if string literals are actually const char arrays, then why does the following line of code
const char* const letters[] = {{'A','+','\0'},{'A','\0'}};
throws
error: braces around scalar initializer for type ‘const char* const’
const char* const letters[] = {{'A','+','\0'},{'A','\0'}};
^
Thank you!
The standard specifies that a string literal is represented - as far as your program is concerned - as an array of const characters of static storage duration with a trailing '\0' terminator. The standard doesn't specify HOW a compiler achieves this effect, only that your program can treat the string literal in that way.
So modifying a string literal is either prevented (e.g. passing a string literal to a function expecting a char * is a diagnosable error, and the code will not compile) or - if code works around the type system to modify any character in a string literal - involves undefined behaviour.
In your example, letters[0] is of type const char *, and has a value equal to the address of the first character in the string literal "A+".
std::cout, being of type std::ostream, has an operator<<() that accepts a const char *. This function is called by the statement std::cout << letters[0] and the function assumes the const char * points at a zero-terminated array of char. It iterates over that array, outputting each character individually, until it encounters the trailing '\0' (which is not output).
The thing is, a const char * means that the pointer is to a const char, not that the pointer cannot be changed (that would be char * const). So it is possible to increment the pointer, but not change the value it points at. So, if we do
const char *p = letters[0];
while (*p != '\0')
{
std::cout << *p;
++p;
}
which loops over the characters of the string literal "A+", printing each one individually, and stopping when it reaches the '\0' (the above produces the same observable output std::cout << letters[0]).
However, in the above
*p = 'C';
will not compile, since the definition of p tells the compiler that *p cannot be changed. However, incrementing p is still allowed.
The reason that
const char* const letters [] = {{'A','+','\0'},{'A','\0'}};
does not compile is that an array initialiser cannot be used to initialise pointers. For example;
const int *nums = {1,2,3}; // invalid
const * const int nums2 [] = {{1,2,3}, {4,5,6}}; // invalid
are both illegal. Instead, one is required to define arrays, not pointers.
const int nums[] = {1,2,3};
const int nums2[][3] = {{1,2,3}, {4,5,6}};
All versions of C and C++ forbid initialising pointers (or arrays of pointers in your example) in this way.
Technically, the ability to use string literals to initialise pointers is actually the anomaly, not the prohibition on initialising pointers using arrays. The reasons C introduced that exemption for string literals are historical (in very early days of C, well before K&R C, string literals could not be used to initialise pointers either).
As for your first question, the type of letters[0] is const char * const. This is a pointer to a character, but not a character itself. When passing a pointer to a character to std::cout, it will treat it as a NUL-terminated C string, and writes out all characters from the start of the memory pointed to until it encounters a NUL-byte. So that is why the output will be A+. You can pass the first character of the first string by itself by writing:
std::cout << letters[0][0];
The fact that the pointers and/or the C strings themselves are const doesn't matter here, since nothing is writing to them.
As for your second question, const char * const declares a single array, but you are providing a nested array on the right-hand side of that statement. If you really wanted two arrays of characters, write:
const char *const letters[] = {{'A', '+', '\0'}, {'A', '\0'}};
That is equal to your code form the first question. Or if you want a single array:
const char *const letters = {'A', '+', '\0', 'A', '\0'};
That line is equal to:
const char *const letters = "A+\0A";
char characters[] = {'h','e','l','l','o'};
char* characters[] = {"h","e","l","l","o"};
How is the latter able to point to individual strings?
How is the latter able to point to individual strings?
When you write this:
char characters[] = {'h','e','l','l','o'};
you define an array of type char, i.e. you have defined a variable of type char[5]. Hence you can initialize it with elements of type char.
In contrast, when you write:
char* characters[] = {"h","e","l","l","o"};
you define an array of type char*, i.e. you have defined a variable of type char*[5] -- and char* means pointer to char, i.e. C style string. Hence you can initialize it with elements of type string literal.
Perhaps the second array should more aptly be named strings[] instead of characters[].
To be precise, string literals such as 'h', are themselves of type const char[2]1, which corresponds in pointer terms to const char*. So an array of such strings should be defined const char* strings[] = ... and not char* strings[] = ....
1 const char[2] and not const char[1] as it is null terminated, as in it's an array holding 1st element to be 'h and 2nd to be '\0'
Because of different types. In your first example you have an array of chars, in your second example you have an array of pointers to chars (array of arrays if you want). String literals are of type const char[] which translates to const char*. You should have a const qualifier in your second example:
const char* characters[] = {"h","e","l","l","o"};
It just so happens your string literals have one character in them followed by a hidden null terminating character. So if you had:
const char test[] = "h";
what you actually have is:
const char test[] = {'h', '\0'};
Add a pointer to the above example and you have an array of null terminated character arrays.
To make things more clear you could also have:
const char* characters[] = {"hello","world","etc"};
Prefer std::string to the above approach as it does all the heavy lifting for you.
im realy confused about const char * and char *.
I know in char * when we want to modify the content, we need to do something like this
const char * temp = "Hello world";
char * str = new char[strlen(temp) + 1];
memcpy(str, temp, strlen(temp));
str[strlen(temp) + 1] = '\0';
and if we want to use something like this
char * str = "xxx";
char * str2 = "xts";
str = str2;
we get compiler warning. it's ok I know when i want to change char * I have to use something memory copy. but about const char * im realy confused. in const char * I can use this
const char * str = "Hello";
const char * str2 = "World";
str = str2; // and now str is Hello
and I have no compiler error ! why ? why we use memory copy when is not const and in const we only use equal operator ! and done !... how possible? is it ok to just use equal in const? no problem happen later?
As other answers say, you should distinguish pointers and bytes they point to.
Both types of pointers, char * and const char *, can be changed, that is, "redirected" to point to different bytes. However, if you want to change the bytes (characters) of the strings, you cannot use const char *.
So, if you have string literals "Hello" and "World" in your program, you can assign them to pointers, and printing the pointer will print the corresponding literal. However, to do anything non-trivial (e.g. change Hello to HELLO), you will need non-const pointers.
Another example: with some pointer manipulation, you can remove leading bytes from a string literal:
const char* str = "Hello";
std::cout << str; // Hello
str = str + 2;
std::cout << str; // llo
However, if you want to extract a substring, or do any other transformation on a string, you should reallocate it, and for that you need a non-const pointer.
BTW since you are using C++, you can use std::string, which makes it easier to work with strings. It reallocates strings without your intervention:
#include <string>
std::string str("Hello");
str = str.substr(1, 3);
std::cout << str; // ell
This is a confusing hangover from the days of early C. Early C didn't have const, so string literals were "char *". They remained char * to avoid breaking old code, but they became non-modifiable, so const char * in all but name. So modern C++ either warns or gives an error (to be strictly conforming) when the const is omitted.
Your memcpy missed the trailing nul byte, incidentally. Use strcpy() to copy a string, that's the right function with the right name. You can create a string in read/write memory by use of the
char rwstring[] = "I am writeable";
syntax.
That is cause your variables are just a pointers *. You're not modifiying their contents, but where they are pointing to.
char * a = "asd";
char * b = "qwe";
a = b;
now you threw away the contents of a. Now a and b points to the same place. If you modify one, both are modified.
In other words. Pointers are never constants (mostly). your const predicate in a pointer variable does not means nothing to the pointer.
The real difference is that the pointer (that is not const) is pointing to a const variable. and when you change the pointer it will be point to ANOTHER NEW const variable. That is why const has no effect on simple pointers.
Note: You can achieve different behaviours with pointers and const with more complex scenario. But with simple as it, it mostly has no effect.
Citing Malcolm McLean:
This is a confusing hangover from the days of early C. Early C didn't have const, so string literals were "char *". They remained char * to avoid breaking old code, but they became non-modifiable, so const char * in all but name.
Actually, string literals are not pointers, but arrays, this is why sizeof("hello world") works as a charm (yields 12, the terminating null character is included, in contrast to strlen...). Apart from this small detail, above statement is correct for good old C even in these days.
In C++, though, string literals have been arrays of constant characters (char const[]) right from the start:
C++ standard, 5.13.5.8:
Ordinary string literals and UTF-8 string literals are also referred to as narrow string literals. A narrow string literal has type “array of n const char”, where n is the size of the string as defined below, and has static storage duration.
(Emphasised by me.) In general, you are not allowed to assign pointer to const to pointer to non-const:
char const* s = "hello";
char ss = s;
This will fail to compile. Assigning string literals to pointer to non-const should normally fail, too, as the standard explicitly states in C.1.1, subclause 5.13.5:
Change: String literals made const.
The type of a string literal is changed from “array of char” to “array of const char”.
[...]char* p = "abc"; // valid in C, invalid in C++
Still, string literal assignement to pointer to non-const is commonly accepted by compilers (as an extension!), probably to retain compatibility to C. As this is, according to the standard, invalid, the compiler yields a warning, at least...
While creating an array of pointers for int data type the following code works:
int var[] = {10, 100, 200, 1000};
int *ptr[] = {&var[0], &var[1], &var[2], &var[3]};
While creating an array of pointers for char data type the following is legal:
char *names[] = {"Mathew Emerson", "Bob Jackson"};
But if I create an array of pointers for int data type as follows:
int var[] = {10, 100, 200, 1000};
int *ptr[] = {var[0], var[1], var[2], var[3]};
I get a compiler error. I understand why I am getting a compilation error in the above method of declaration for array of int data type, as var[i] is not a reference to a variable to which a pointer must point to i.e. its address, but shouldn't I also get error by the same logic in the declaration of my char array of pointer.
What is the reason that its is acceptable in char array of pointers?
Is " a string value " an address of something to which a pointer can point to or is it just a const string value.
char *names[] = {"Mathew Emerson", "Bob Jackson"};
Is not legal in C++. A string literal has the type of const char[] so it is illegal to store it as a char* as it violates const-correctness. Some compilers allow this to still compile as a legacy from C since string literals have the type char[] but it is not standard C++. If you turn up the warnings on your compiler you should get something along the lines of
main.cpp: In function 'int main()':
main.cpp:5:53: warning: ISO C++ forbids converting a string constant to 'char*' [-Wpedantic]
char *names[] = {"Mathew Emerson", "Bob Jackson"};
If you want an array of strings then I suggest you use a std::string like
std::string names[] = {"Mathew Emerson", "Bob Jackson"};
The reason
char *names[] = {"Mathew Emerson", "Bob Jackson"};
"works" is that since the string literals are arrays they implicitly decay to pointers so
{"Mathew Emerson", "Bob Jackson"}
Becomes
{ address_of_first_string_literal, address_of_second_string_literal}
and then those are used to initialize the pointers in the array.
int *ptr[] = {var[0], var[1], var[2], var[3]};
Cannot work because var[N] is a reference to the int in the array and not a pointer.
"Mathew Emerson" is of type const char* - it is already a pointer, thus you can directly store it in an array of pointers. The reason you need & for the int case is to "convert" int to int*.
(Ignoring the const-ness problem as mentioned in other answers...)
Each string literal you write ("Mathew Emerson", "Bob Jackson", ...) requires some storage location in the compiled code later.
It is as if you had written somewhere
char const[] MathewEmerson = { 'M', 'a', /*...*/, 'o', 'n', 0 };
So you you could construct your char const* array then as:
char const* names[] = { &MathewEmerson[0], /*...*/ };
As for arrays, the address of the array itself and its first element is the same, and arrays are implicitely converted to pointers, you can write instead
char const* names[] = { MathewEmerson, /*...*/ };
All this is done implicitely for you, if you use string literals.
Similarly, you could have written:
int *ptr[] = {var, &var[1], &var[2], &var[3]};
(note: var, not &var[0] for the first item) and if we go further, even:
int *ptr[] = {var, var + 1, var + 2, var + 3};
The result always would have been the same. Readability, understandability of one variant vs another? Well, another topic...
Your misconception is wrapped up in your interpretation of what is represented by: "Mathew Emerson"
This is an array of characters that will be instantiated in read only memory as part of your program's bootstrapping. This array of characters is called a String Literal, specifically a:
Narrow multibyte string literal. The type of an unprefixed string literal is const char[]
NathanOliver's answer correctly describes that your compiler doesn't have the warning level turned up high enough so it is allowing the, const char[] to decay into a char*. This is very bad because:
Attempting to modify a string literal results in undefined behavior: they may be stored in read-only storage (such as .rodata) or combined with other string literals[1]
It would have been completely legal and logical to do this however: const char *names[] = {"Mathew Emerson", "Bob Jackson"} Hopefully that clarifies for you what's happening well enough for you to understand that working with a String Literal is working with a pointer. Your code: int *ptr[] = {var[0], var[1], var[2], var[3]} is then illegal because, var[0] is an int& not an int*. It would be similarly illegal to do: char* ptr = {names[0][0], names[0][1], names[0][2], names[0][3]} Again the problem here would be that I was working with char&s not char*s.
I was working with the strcmp function in C, then i saw the function as arguments gets:
strcmp(_const char *s1, const char *s2)_;
And actually i passed normal char array and it worked. Any ideas why this happening?
If you have for example the following code
char c = 'A';
char *p = &c;
const char *cp = &c;
then it means that you can change variable c using pointer p but you may not change it using pointer cp
For example
*p = 'B'; // valid assignment
*cp = 'B'; // compilation error
Thus function declaration
int strcmp(const char *s1, const char *s2);
means that inside the function the strings pointed to by s1 and s2 will not be changed.
There are two ways to use const key word to a pointer:
int my_int = 3;
const int* pt = &my_int; //prevent to modify the value that pointer pt points to
int* const ps = &my_int; //prevent to modify the value of pointer ps:
//it means the pointer is a const pointer, you can't modify the value of the pointer
//The value of the pointer ps is a memory address, so you can't change the memory address
//It means you can't reallocate the pointer(point the pointer to another variable)
int new_int = 5;
*pt = &new_int; //valid
*pt = 10; //invalid
*ps = &new_int; //invalid
*ps = 10; //valid
In strcmp function, the two arguments are pointer points to a const value, it means when you pass two char arrays or char pointers to the strcmp function, the function can use the value of those two pointers point to, but the function can't modify the value that you pass to it. That's why it works.
The const reference works in a similar way.
This worked, because passing non-const in place of const is allowed. It is the other way around that is prohibited:
char *hello = new char[20];
char *world= new char[20];
strcpy(hello, "hello");
strcpy(world, "world");
if (!strcmp(hello, world)) {
...
}
The const in the declaration is meant to tell the users of the API that the function will not modify the content of the string. In C++ this is important, because string literals are const. Without the const in the API, this call would have been prohibited:
if (!strcmp(someString, "expected")) { // <<== This would not compile without const
...
}
I think you intend to ask the mechanism of how the variable can compare the array.
if that's the case,
The pointer that has been declared in your example stores the initial address of the array's first element and
the ending point of the string can be determined by the detection null character that which in turn is the ending address of the array.
With that said the strcmp when called the pointer points to the strings or the character passed that is, the command would be assumed as follows strcmp("string1","string2");
and thus the comparison takes place as usual.
hmm i guess by this and with other examples posted around you can get a better picture for your answer.