In C++ Primer book, there is an explanation on type aliases as:
typedef char *pstring;
const pstring cstr = 0; // cstr is a constant pointer to char
They say that the following is a wrong interpretation:
const char *cstr = 0;
However it makes sense to me, to replace the typedef alias with its original meaning.
In a normal scenario without type aliasing a constant pointer is defined as:
char *const cstr = 0;
Why is it constant pointer rather than pointer to const?
Can anyone explain in clear terms because the book doesn't seem to clarify it much.
2 * 3 + 1 is 7. But how come if I do int i = 3 + 1; and then 2 * i it gives 8? Shouldn't the variable be replaced with its original meaning?
It's because 2 * 3 + 1 is interpreted as (2 * 3) + 1, while 2 * i is the same as 2 * (3 + 1). These mean different things and work out to different numbers. When you give 3 + 1 a name, when you use the name it doesn't break up the number back into 3 + 1 in order to only multiply the 3.
The reason that const char * is different from const pstring is very similar. const char * is interpreted as (const char) * i.e. a pointer to a constant char. But const pstring is the same as const (char *) i.e. a constant pointer to a char. pstring is a whole type by itself, and when you do const pstring it doesn't split up the char * in order to make the char part const.
Note: if you did #define pstring char * then const pstring would be the same as const char *, because macros (#defines) are just treated as text replacements.
Related
I am reading application code developed in the IBM RSARTE C++ version. Here is a piece of C++ code:
const char * const * av = RTMain::argStrings();
How to understand the left-hand side syntax when there are two const and two *?
const char * const * av = RTMain::argStrings();
is the same as
char const * const * av = RTMain::argStrings();
const applies to what's left of const.
So, av is a non-const pointer to a const* to const char.
The returned pointer, av, is non-const and can be changed.
The pointer av is pointing at is const and can not be changed.
The char that pointer is pointing at is const and can not be changed.
Read this declaration
const char * const * av
from right to left. There is declared the pointer av ( * av ) that points to a constant pointer ( * const ) that in turn points to an object of the type const char.
To simplify this declaration consider this code snippet.
const char *literal = "Hello World!";
const char * const * pointer_to_the pointer_literal = &literal;
So using the pointer pointer_to_the pointer_literal you may not write for example
*pointer_to_the pointer_literal = "Bye";
and you may not write
**pointer_to_the pointer_literal = 'h';
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.
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...
The standard C library functions strtof and strtod have the following signatures:
float strtof(const char *str, char **endptr);
double strtod(const char *str, char **endptr);
They each decompose the input string, str, into three parts:
An initial, possibly-empty, sequence of whitespace
A "subject sequence" of characters that represent a floating-point value
A "trailing sequence" of characters that are unrecognized (and which do not affect the conversion).
If endptr is not NULL, then *endptr is set to a pointer to the character immediately following the last character that was part of the conversion (in other words, the start of the trailing sequence).
I am wondering: why is endptr, then, a pointer to a non-const char pointer? Isn't *endptr a pointer into a const char string (the input string str)?
The reason is simply usability. char * can automatically convert to const char *, but char ** cannot automatically convert to const char **, and the actual type of the pointer (whose address gets passed) used by the calling function is much more likely to be char * than const char *. The reason this automatic conversion is not possible is that there is a non-obvious way it can be used to remove the const qualification through several steps, where each step looks perfectly valid and correct in and of itself. Steve Jessop has provided an example in the comments:
if you could automatically convert char** to const char**, then you could do
char *p;
char **pp = &p;
const char** cp = pp;
*cp = (const char*) "hello";
*p = 'j';.
For const-safety, one of those lines must be illegal, and since the others are all perfectly normal operations, it has to be cp = pp;
A much better approach would have been to define these functions to take void * in place of char **. Both char ** and const char ** can automatically convert to void *. (The stricken text was actually a very bad idea; not only does it prevent any type checking, but C actually forbids objects of type char * and const char * to alias.) Alternatively, these functions could have taken a ptrdiff_t * or size_t * argument in which to store the offset of the end, rather than a pointer to it. This is often more useful anyway.
If you like the latter approach, feel free to write such a wrapper around the standard library functions and call your wrapper, so as to keep the rest of your code const-clean and cast-free.
Usability. The str argument is marked as const because the input argument will not be modified. If endptr were const, then that would instruct the caller that he should not change data referenced from endptr on output, but often the caller wants to do just that. For example, I may want to null-terminate a string after getting the float out of it:
float StrToFAndTerminate(char *Text) {
float Num;
Num = strtof(Text, &Text);
*Text = '\0';
return Num;
}
Perfectly reasonable thing to want to do, in some circumstances. Doesn't work if endptr is of type const char **.
Ideally, endptr should be of const-ness matching the actual input const-ness of str, but C provides no way of indicating this through its syntax. (Anders Hejlsberg talks about this when describing why const was left out of C#.)
Visual Studio c++ 2005
I am getting an error on the last line of this code.
int Utils::GetLengthDiff ( const char * input, int & num_subst )
{
int num_wide = 0, diff = 0 ;
const char * start_ptr = input ;
num_subst = 0 ;
while ( ( start_ptr = strstr ( start_ptr, enc_start ) ) != NULL )
{
char * end_ptr = strstr ( start_ptr, enc_end ); // Error
So I changed the line to this and it worked ok
const char * end_ptr = strstr ( start_ptr, enc_end );
So why would I need to declare end_ptr as a const as well?
Many thanks,
C++ has two overloaded versions of this function. http://www.cplusplus.com/reference/clibrary/cstring/strstr/
const char * strstr ( const char * str1, const char * str2 );
char * strstr ( char * str1, const char * str2 );
Since your start_ptr is const char * the C++ compiler resolves to call the version that takes a const char * as the first parameter, that version also returns a const char *, so you have to change your return value to match.
So why would I need to declare end_ptr as a const as well?
For the same reason that start_ptr needs to be const char*: strstr returns the type const char* (= char const*) because it searches inside a constant string (the parameter you pass to strstr is also const char*). In particular, it’s not the pointer that is const, it’s the memory it points to. Think of it as a pointer to an immutable (i.e. constant) string. You can change what it points to but not the individual characters inside the string.
This is different from an unchangeable pointer which points to a mutable string, i.e. a string where you can change individual characters.
Suppose that the return value from strstr were char*, with a const char* first parameter, as it is in C. Then you could write:
const char *s = "hello, world";
strstr(s, "hello")[0] = 'j';
The code would compile and run (with undefined behavior), but it's the kind of error which const was specifically designed to avoid. You've converted a const char* to char* without a cast.
C can't really do anything about it: if strstr returned const char* then you'd have to cast back to non-const explicitly in the case where the input is non-const and you want to modify the string. Because C++ has function overloading it can (and does) plug the loophole and make both cases work correctly. Hence in C++, the above code fails to compile, and so does your example code.