In c++ we can write
1 char *s="hello"
but the below lines of program produces an error ( cannot convert char* to char)
2 char *s;
*s="hello";
I am confused here, what is difference between 1 and 2
why this error is coming?
In C++, a string literal is a constant array of characters, not just an array of characters like in C. Anyways, to assign to such a variable (Which is best avoided), you do not have to dereference the pointer. Dereferencing it accesses the first element, which is just a char. A char cannot hold an array of characters inside it, causing an error. This is more the reason why you should be using std::string.
Some compilers such as GCC provide extensions to make such code possible since it is not standards compliant code, and it would look like:
char* s = "hello";
s = "new string";
This generates the following warning in GCC (But still gets the expected result):
warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
Clang also has the same behavior with the same output (Also generating a warning)
A string is an array of characters. The start of a string therefore is const char *.
Therefore to reference a string, you can use const char * s = "hello";
However if you dereference a const char*, you get a const char. This isn't a string i.e. *s gives you 'h'.
In your code *s="hello";, you are saying "assign at the dereferened s the value "hello"". Dereferencing s is a character only, to which you are trying to assign a string.
The problem is the second asterisk in your second example.
The first code is this
char *s="hello";
The equivalent code is this
char *s;
s="hello";
No * before s in the second line.
Now as everyone is pointing out neither of these are legal C++. The correct code is
const char *s="hello";
or
const char *s;
s="hello";
Because string literals are constant, and so you need a pointer to const char.
I am confused here, what is difference between 1 and 2 why this error is coming?
As many others * in C++ means different things in different context:
char *s; // * here means that s type is a pointer to char, not just char
*s; // in this context * means dereference s, result of exression is char
int a = 5 * 2; // in this context * means multiply
so case 1 and 2 may look similar to you but they mean very different things hence the error.
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";
I am learning C++. In the program shown here, as far as I know, str1 and str2 store the addresses of first characters of each of the relevant strings:
#include <iostream>
using namespace std;
int main()
{
char str1[]="hello";
char *str2="world";
cout<<str1<<endl;
cout<<str2<<endl;
}
However, str1is not giving any warnings, while with str2 I get this warning:
warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
char *str2="world";
What's different between these two declarations that causes the warning in the second case but not the first?
When you write
char str1[] = "hello";
you are saying "please make me an array of chars that holds the string "hello", and please choose the size of the array str1 to be the size of the string initializing it." This means that str1 ends up storing its own unique copy of the string "hello". The ultimate type of str1 is char[6] - five for hello and one for the null terminator.
When you write
char *str2 = "world";
you are saying "please make me a pointer of type char * that points to the string literal "world"." The string literal "world" has type const char[6] - it's an array of six characters (five for hello and one for the null terminator), and importantly those characters are const and can't be modified. Since you're pointing at that array with a char * pointer, you're losing the const modifier, which means that you now (unsafely) have a non-const pointer to a const bit of data.
The reason that things are different here is that in the first case, you are getting a copy of the string "hello", so the fact that your array isn't const isn't a problem. In the second case, you are not getting a copy of "hello" and are instead getting a pointer to it, and since you're getting a pointer to it there's a concern that modifying it could be a real problem.
Stated differently, in the first case, you're getting an honest-to-goodness array of six characters that have a copy of hello in them, so there's no problem if you then decide to go and mutate those characters. In the second case, you're getting a pointer to an array of six characters that you're not supposed to modify, but you're using a pointer that permits you to mutate things.
So why is it that "world" is a const char[6]? As an optimization on many systems, the compiler will only put one copy of "world" into the program and have all copies of the literal "world" point to the exact same string in memory. This is great, as long as you don't change the contents of that string. The C++ language enforces this by saying that those characters are const, so mutating them leads to undefined behavior. On some systems, that undefined behavior leads to things like "whoa, my string literal has the wrong value in it!," and in others it might just segfault.
The problem is that you are trying to convert a string literal (with type const char*) to char*.
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...
I have read a lot about the subject and I am confused .
What used to work in a C file ,not working on a cpp file :
char *builtinFunctions[20];
Then I get error on the strcpy function here :
void Intepreter::setBuiltIns(char *builtins)
{
strcpy(builtinFunctions, builtins); // no matching function call to strcpy
}
I probably don't understand the basics here, but why in C++ this will not work ( do i need to use = instead ? )
strcpy(char *, const char*) = thats the structure
if I change the builtinFunctions from being a pointer it works.
EDIT:
The reason for being a const before this edit is that I read here :
Why is conversion from string constant to 'char*' valid in C but invalid in C++
that char *builtinFunctions[20]; will produce warning when :
builtinFunctions[0]="me";
and it did. I could fix it by removing the const .
This is an array of pointers to char.
char *builtinFunctions[20];
So you call
strcpy(builtinFunctions, builtins);
gets treated as strcpy(char **, char*), not as strcpy(char *dest, const char *src). So you get a mismatch for first parameter type.
EDIT:
So let's suppose builtinFunctions is "an array of words" you wish to populate, with void Intepreter::setBuiltIns(char *builtins) meant to do just that with it's first parameter being a pointer to a new incoming word. (And you're doing this in a C-style manner. Well, up to you.)
Some things to consider.
If you declare an array type arrName[N]; then the array's name
being used all alone without index is treated as a variable of type
type *arrName. If you type is initially char *, then
builtinFunctions by itself is of type char**. That's why your
strcpy fails, but strcpy(builtinFunctions[someIndex], builtins);
works.
Before invoking strcpy you should consider, if you have a
destination space allocated. builtinFunctions[someIndex] is of
type char *. Where does it point to? Is it a valid pointer to an
allocated space, or a gateway to hell of undefined behaviour strcpy will happily take you to?
In the following code snippet, I am not able to understand why the error is coming on LineA , but no error in Line B ?
//Global
char strA[80] = "A string to be used for demonstration purposes";
int t=60;
int main(void)
{
strA[80] = "I am trying to modify the source"; //Line A, gives error
t=60; //Line B, no errors
}
The error is:
2 IntelliSense: a value of type "const char *" cannot be assigned to
an entity of type
"char" c:\users\hu\cplustutorial.cpp 69 12 CPLUStutorial
I am not having the char string as const, so why this error?
Compiling with MS VS 2010.
This char strA[80] = "A string to be used for demonstration purposes"; initializes your array.
This strA[80] means a single character within that array. How can you store multiple characters in a single char. Use strcpy to copy the new string.
You are trying to assign the 80th element of strA (which incidentally doesn't exist) with a const char*, not the char[] itself. Also, you tagged the question as C++, so why use char[] instead of std::string?
In C++, the type of a string literal is const char[], not plain char[], so what you are trying to do is illegal by the C++ standard, hence the error you are seeing.
In order to modify the string you will first need to copy it, either using the C library function strcpy or (better) with a std::string.
You have to understand a string of character(string literal) has a type of const char * and you are trying to store it inside a single char(char[80]). Thats why its giving you error.Check this out http://www.stackoverflow.com/questions/20294015/.