I can get non-const pointer to const object?!!
-
I have the following
char *s("Anton"); //Anton is my name s[0]='B'; cout<<s<<endl; //Program output: Anton
The program compiles without errors and warnings. But the output of the program is surprising.
The problem is that compiler allows me to get non-const pointer to const string "Anton"! How does this happen? It should give me an error in the first line, something like: *Cannot convert "const char *" to "char ". May be the bug in the compiler? I tried to get non-const pointers to other const objects, but without success; this happens only with strings.
I'm using Visual Studio.
-
copy ctor vs. = "..."?
-
That's really strange.
char *s("Anton"); //Anton is my name s[0] = 'B'; cout<<s[0]<<endl; // Program output: B (!) cout<<s<<endl; // Program output: Anton cout<<s[0]<<endl; // Program output: A (!!!!!)
Seems like something is gonna changed, but I don't understand it completely either. Pointers are quite strange sometimes...
Use one of the following possibilities, then it should work:char s[]("Anton") char s[] = "Anton"
-
i dont get the point, why should the string be a const object?
char* s("Anton"); char s[]("Anton");
do these two lines differ from each other?
-
Afaik is this not an compiler-error but just a relict from C. But I would have guessed that a memory-access-error would occure, rather than the string being "reset" or something..
-
SAn schrieb:
I have the following
char *s("Anton"); //Anton is my name s[0]='B'; cout<<s<<endl; //Program output: Anton
The program compiles without errors and warnings. But the output of the program is surprising.
The problem is that compiler allows me to get non-const pointer to const string "Anton"! How does this happen? It should give me an error in the first line, something like: *Cannot convert "const char *" to "char ". May be the bug in the compiler? I tried to get non-const pointers to other const objects, but without success; this happens only with strings.
I'm using Visual Studio.
There is a (deprecated) conversion from array of const char (array of const wchar_t) to pointer to char (pointer to wchar_t) if and only if such a pointer object is being initialised by a string literal. This conversion exists as a compatibility feature. However, attempting to modify a string literal through such a pointer is undefined.
-
point-getter schrieb:
i dont get the point, why should the string be a const object?
char* s("Anton"); char s[]("Anton");
do these two lines differ from each other?
They differ very much. In the first case, "s" is a pointer to the char-array. The second one should imo be a char-array itself, into which the string "Anton" is copied.
-
Badestrand schrieb:
point-getter schrieb:
i dont get the point, why should the string be a const object?
char* s("Anton"); char s[]("Anton");
do these two lines differ from each other?
They differ very much. In the first case, "s" is a pointer to the char-array. The second one should imo be a char-array itself, into which the string "Anton" is copied.
well, a char array behaves just like a pointer to char, so i can use it in the same way and i can also do the same things with both. so imo these lines differ only in detail, or does the compiler maybe create a "temporary object" in the first line, where s points to?
-
point-getter schrieb:
or does the compiler maybe create a "temporary object" in the first line, where s points to?
I think those constant strings are placed in a readyonly-section in the RAM. So when you'll write
char* a = "abc"; char* b = "abc";
, both should point to the same location. If I'm right and these strings are placed in some readonly-section, then modifing these strings will cause an error. However, temporary objects would be fatal because no-one would be able to clean up afterwards.
So the main difference is that
char* a="abc"
should be readonly, whilechar a[]="abc"
can be modified as you want.
-
Badestrand schrieb:
So when you'll write
char* a = "abc"; char* b = "abc";
, both should point to the same location. If I'm right and these strings are placed in some readonly-section, then modifing these strings will cause an error. However, temporary objects would be fatal because no-one would be able to clean up afterwards.
But you are wrong. Just test it:
char* a = "abc"; char* b = "abc"; cout<<&a<<" "<<&b<<endl; a = "xyz"; cout<<a<<endl;
The addresses of a and b are not the same. b is 4 Bytes later.
And the char* variables aren't read-only, either. At the example above, I get "xyz" as output.
-
Try this out:
char* a = "abc"; char* b = "abc"; std::cout << reinterpret_cast<int>(a) << " " << reinterpret_cast<int>(b) << std::endl;
Of course do the variables a and b have different addresses, but what I wanted to claim is that the string-literals are at the same address*. And those string-literals should be constant, I'm getting a memory-error with
a[0] = 'h';
* So the variables a and b point to the same address. So even if no error occurs, this would give you something unexpected:
//Somewhere char* a = "abc"; a[0] = 'd'; // Somewhere else char* b = "abc"; std::cout << b << std::endl; // would print "dbc"
-
Badestrand schrieb:
* So the variables a and b point to the same address. So even if no error occurs, this would give you something unexpected:
//Somewhere char* a = "abc"; a[0] = 'd'; // Somewhere else char* b = "abc"; std::cout << b << std::endl; // would print "dbc"
No, it wouldn't. If you don't believe, just try it out. I get the output "abc".
But the thing that is strange, if you change a single character and diplay it, you get the first time the new (changed) character, but the 2nd time, it's the old one againchar* a = "abc"; a[0] = 'd'; // Somewhere else char* b = "abc"; std::cout << a[0] << std::endl; // output "d" std::cout << a[0] << std::endl; // output "a" std::cout << b[0] << std::endl; // output "a" std::cout << a << std::endl; // output "abc" std::cout << b << std::endl; // output "abc"
-
Hm. I think our compilers handle that differently and they possibly are allowed to, since this is undefined behaviour (as camper said). With my MSVC++ 2005 Express I'm not able to change a[0], so I cannot try what would be written
But it seems that you're right that I am wrong; at least the implementation of handling string-literals seems to be compiler-dependent. I thought it would be popular to put those string-literals to read-only-sections and let all pointers point to those locations.
PS: What compiler are you working with? GCC?
-
point-getter schrieb:
i dont get the point, why should the string be a const object?
The string-literal is a constant object with static storage duration because the standard says so.
point-getter schrieb:
well, a char array behaves just like a pointer to char, so i can use it in the same way and i can also do the same things with both.
almost. There is an implicit conversion from array of T to rvalue pointer to T. That doesn't mean that there aren't differences in any places, sizeof being a prominent example. Similarly, an expression of function can be converted to a pointer to function and thus behaves alsmost the same way. They are still distinct types though (more obvious too: one is an object type while the other is not).
Badestrand schrieb:
I think those constant strings are placed in a readyonly-section in the RAM. So when you'll write
char* a = "abc"; char* b = "abc";
, both should point to the same location.
That is unspecified. Two string-literals with the same content may share the same address but needn't to.
assert("foo"=="foo");
may fail sometimes and sometimes not (some compilers have switches to influence this behaviour).
Thinking of read-only RAM is probably not the best explanation - while that can be true sometimes, usually normal programs on your average desktop computer do not use such memory. The may-not-be-modified restriction allows the compiler to assume that it contents does not change and thus possibly enable more aggressive optimization, for examplechar* foo = "bar"; cout<<foo[0];
doesn't actually have to use foo but may directly call the <<-operator with 'b' as argument.
-
Thank you for clearing this
-
camper schrieb:
There is a (deprecated) conversion from array of const char (array of const wchar_t) to pointer to char (pointer to wchar_t) if and only if such a pointer object is being initialised by a string literal. This conversion exists as a compatibility feature. However, attempting to modify a string literal through such a pointer is undefined.
You see, this deprecated conversion is sometimes surprising people. Is there a way to disable this conversion (by compiler command-line switches, for example) ?
Undefined behaviour seams to be very undefined...
-
Badestrand schrieb:
And those string-literals should be constant, I'm getting a memory-error with
a[0] = 'h';
For me it depends of the compiler mode. In "debug" mode I'm getting memory-error. But in "release" mode there is no error (but some fancy results due to compiler optimisations, may be).
By the way, placing of the same (sub)strings in one memory location is called "string pooling". There is a key /GF in Microsoft compiler, allowing (but not forcing) it to do that pooling. It needed sometimes to reduce the size of .exe file.
-
Badestrand schrieb:
PS: What compiler are you working with? GCC?
No, I'm using Microsoft Visual C++ 2008 Express Edition.
Thank you, I didn't know about this undefined conversion behaviour... If you initialize char-Arrays always with []-bracks and without pointers, you won't get any problems, will you?
-
What about using C++ std::strings instead of oldscool C-Style memory-leak-prone char-arrays and pointers?