How to assign one char* to another char* - c++

Its my first question here.
I have a piece of code:
char* str1 = "yes" ;
char* str2 = "no" ;
*str1 = *str2; //----crash
*str1 = *str2; //here program crashes.
When I can do the same with integer pointers, then why not with char pointers.
Please explain.

This original code,
char* str1 = "yes" ;
char* str2 = "no" ;
*str1 = *str2; //----crash
*str1 = *str2; //here program crashes.
… is invalid, not permitted, as of C++11 and later. We're now at C++14 and in a short while will presumably be at C++17.
What does a C++11 compiler say about it? E.g., what does MinGW g++ 5.1.0 with option -std=c++14, say about it?
C:\my\forums\so\121> g++ foo.cpp
foo.cpp: In function 'int main()':
foo.cpp:3:18: error: ISO C++ forbids converting a string constant to 'char*' [-Wpedantic]
char* str1 = "yes" ;
^
foo.cpp:4:18: error: ISO C++ forbids converting a string constant to 'char*' [-Wpedantic]
char* str2 = "no" ;
^
C:\my\forums\so\121> _
However, Visual C++ 2015 update 2 erroneously accepts the code.
The reason why the implicit conversion to char* was dropped from the language was precisely that it's unsafe. It allows the code to attempt modification of the literals, as this code does. But the literals can be stored in read-only memory, which then can cause a crash (as it did for the OP), or other undesirable behavior. It's just Undefined Behavior, where anything can happen, including that the code appears to “work”.
How to fix it?
Use std::string.
Like this:
#include <string>
using namespace std;
auto main() -> int
{
string str1 = "yes" ;
string str2 = "no" ;
str1 = str2; // OK.
}
If you absolutely want to use C level zero-terminated strings handled via pointers, perhaps in order to be compatible with some C code, then use const as appropriate for pointers, use local or dynamically allocated arrays for storage as appropriate, and use the C standard library's string functions, or roll your own, they're very simple functions:
#include <assert.h>
#include <string.h> // The ".h" header is a C++ version of C's header.
auto main() -> int
{
char str1[] = "yes" ;
char const* const str2 = "no" ;
int const n2 = strlen( str2 );
assert( sizeof( str1 ) > n2 );
strcpy( str1, str2 );
assert( strcmp( str1, "no" ) == 0 );
}

Please note, that char* is a pointer to a char, not a string object. A literal "yes" is actually a const char*, because the literals will be constant data in the programms data section. For compatibility with C C++ still allows to initialize a char* with a const char*.
Also note, that the unary * operator on a pointer dereferences the pointer.
Now that you do here is assigning the first character of str2 ('n') to the first character of str1. Since the first character of str1 is a constant in the programs data section, that will of course fail.
If you really want to assign the first char, first produce a char array on the heap:
char* str1 = (char*)malloc(4); // here str1 is non const
strncpy(str1, "yes", 4);
const char* str2 = "no";
*str1 = *str2; // now str1 contains "nes".
I assume you are trying to work with strings. Please prefer std::string:
std::string str1 = std::string("yes");
std::string str2 = std::string("no");
str1 = str2 // now str1 is "no" as well.
With C++14 string literals you can make it even more elegant:
auto str1 = "yes"s;
auto str2 = "no"s;
str1 = str2 // now str1 is "no" as well.
Whenever reasonable, use the standard library instead of C legacy constructs. You probably won't get it better.

As per the comments, the OP simply wants to make str1 to "no"
Instead of
*str1 = *str2;
You should do
str1 = str2;
str1 is a pointer that points to the first character of the given string.
*str dereferences the pointer giving you the first character of the string str1. So what your code was doing was trying to make the first character of str1 to the first character of str2
In my code, I am making str1 point to the same location ass str2 which in effect will give you two variables pointing to the same memory location.
If you want to copy the contents of str2 to str1 then use the strcpy function.

Related

How to convert a string type to an array of chars

I'm trying to translate some C code to D, and I've come across this:
char[] welcome = "\t\tWelcome to the strange land of protected mode!\r\n";
It gives this warning:
main.d:5:18: error: cannot implicitly convert expression ("\x09\x09Welcome to the strange land of protected mode!\x0d\x0a") of type string to char[]
5 | char[] welcome = "\t\tWelcome to the strange land of protected mode!\r\n";
| ^
How do I do this without typing each character out individually in the array?
As already mentioned, strings already are an array of chars. In fact, here is the definition of string:
alias string = immutable(char)[];
(from object.d)
A string thus differs from a char[] only in that the contents of the array is immutable.
Depending on your goal, you may not need a char[] after all, and string will work as well.
If you need the array to be writable (i.e. you expect welcome[2] = 'x'; to work), then using .dup will create a copy at runtime.
Sometimes C function declarations are not properly annotated with const, and will not accept pointers to immutable characters. In this case, using a cast is acceptable.
I don't think there is a language feature to place a string literal directly in a writable data segment, in the same way that static char[] s = ['a', 'b', 'c']; does, but it's likely doable as a template or CTFE function.
12.16.1 - Strings
A string is an array of characters. String literals are just an easy way to write character arrays. String literals are immutable
(read only).
char[] str1 = "abc"; // error, "abc" is not mutable
char[] str2 = "abc".dup; // ok, make mutable copy
immutable(char)[] str3 = "abc"; // ok
immutable(char)[] str4 = str1; // error, str4 is not mutable
immutable(char)[] str5 = str1.idup; // ok, make immutable copy
The name string is aliased to immutable(char)[], so the above declarations could be equivalently written as:
char[] str1 = "abc"; // error, "abc" is not mutable
char[] str2 = "abc".dup; // ok, make mutable copy
string str3 = "abc"; // ok
string str4 = str1; // error, str4 is not mutable
string str5 = str1.idup; // ok, make immutable copy
So:
char[] welcome = "\t\tWelcome to the strange land of protected mode!\r\n".dup;

Problems with strcpy and strcat

I just learned about the cstring and some functions in cstring library. When I tried to use the function strcpy, I got a confusing problem. Can anyone thoroughly explain to me why the first code doesn't work while the second one runs totally fine?
First code:
char *str1 = "hello";
char *str2 = "hi";
strcpy(str1, str2);
cout << str1;
Second code
char str1[] = "hello";
char *str2 = "hi";
strcpy(s1,s2);
cout << str1;
I guess the problem is how I declare the variable str1 but I still have no idea why it doesn't work when str1 is a pointer.
First, statement char *str1 = "hello" should give you a warning because you are assigning a pointer to string literal "hello" (which is const) to non-const pointer char* str1. But if you wrote const char *str1 = "hello", then the warning would disappear but you'd get an error with strcpy, because the first operand must not be const.
The second statement works because in char str1[] = "hello", variable str1 is actually an array (not a pointer), which is initialised with a let's say copy of "hello". Hence, you are allowed to overwrite the contents of str1 later on. Note that str1 is not a pointer but an array; it rather decays to a pointer (to the memory of the first character of the array) when used in the context where a pointer is expected.

Dynamic length of strings in C++

I've debugged some programs in C++ and I notice a difference between for instance :
char str[] = "It's a test";
But when you use string in <string> header, it seems that has a variable length and for instance, the following is allowed:
string str1 = "abcdefg";
str1 = "abc";
But this is not allowed :
char str[] = "It's a test";
str = "abc";
It won't work! What's the implementation behind that?
You can initialize an array, which is done with
char array[] = "some string literal";
but you can't assign to an array. That's just the rules of the language.
The std::string class have a special overload for the assignment operator that allows it to be assigned to.
you thought that when at first you have initialised the array of characters and another time when you use it it is not needed to initialise again! but its not true...every time you declare and initialise any array and when ever you are using it again you have to do it again! for example:
char user[] = "sci3nt15t";
char user[] = "Ender";
its good for you to have a look at a definition of string and array.
hope it helps.

C++ pointers under windows 7

whenever a value is assigned to any pointer variable that is not working under windows 7 (32 bit) environment. Program containing such a code are getting execution error.
Actually I was trying to concatenate two strings without using any library functions.
Example:
int main()
{
char *s1 = "Hello";
char *s2 = "World";
char *p;
p = s1;
while(*s1 != '\0')
s1++;
while(*s2 != '\0')
{
*s1 = *s2; // this line creating problem
s1++;
s2++;
}
*s1 = '\0'; // this line also creating problem
while(*p != '\0')
{
cout<<*p;
p++;
}
return 0;
}
You have not allocated space to write into -- that's why you're having a problem.
You've created s1 and pointed it at some read-only memory, and when you try to append, you're then writing into that region.
You could instead set p to point to some memory that a) you own (have the right to write into, not just the physical ability) and b) is large enough for the full allocation.
Your easiest way to do this will be instead to use std::string -- after all, you say you're using C++.
char *s1 = "Hello";
char *s2 = "World";
When you create s1 and s2 like this, you can't write:
*s2 = anything;
Because of string pooling s1 and s2 are immutable by default.
char *s1 = "Hello";
Here, "Hello" is a string literal, which is by definition const. s1 is a pointer to the first element of that string literal, and so points to read-only memory. You cannot change read-only memory, and so you can't change what is pointed to bys1. It would have been much more accrate and better if you had declared this as:
const char *s1 = "Hello";
In C++03, there is a special rule which allows assigning the pointer to a string literal to a non-const pointer. However that rule was removed in C++11, and your code is actually illegal now.
This is a good thing because even in C++03 there is nothing you can (legally) do with s1 that you couldn't do if it was const.
Later, you do something patently wrong:
while(*s2 != '\0')
{
*s1 = *s2; // this line creating problem
s1++;
s2++;
}
I'm not surprised that line of code is causing a problem for you -- it evokes Undefined Behavior because you are modifying read-only memory.
It looks like what you're really trying to do is create a string which is initialized with some known (unchanging) value, and then later modify the string. In order to do that, you must make a copy of the string literal. Easiest way to do that is to use std::string:
std::string s1 = "Hello";
Here "Hello" is still a string literal, but s1 is being constructed off of it. s1 is completely separate from the string literal, and now you can modify it however you wish.

Why can't I write to a string literal while I *can* write to a string object?

If i define something like below,
char *s1 = "Hello";
why I can't do something like below,
*s1 = 'w'; // gives segmentation fault ...why???
What if I do something like below,
string s1 = "hello";
Can I do something like below,
*s1 = 'w';
Because "Hello" creates a const char[]. This decays to a const char* not a char*. In C++ string literals are read-only. You've created a pointer to such a literal and are trying to write to it.
But when you do
string s1 = "hello";
You copy the const char* "hello" into s1. The difference being in the first example s1 points to read-only "hello" and in the second example read-only "hello" is copied into non-const s1, allowing you to access the elements in the copied string to do what you wish with them.
If you want to do the same with a char* you need to allocate space for char data and copy hello into it
char hello[] = "hello"; // creates a char array big enough to hold "hello"
hello[0] = 'w'; // writes to the 0th char in the array
string literals are usually allocated in read-only data segment.
Because Hello resides in read only memory. Your signature should actually be
const char* s1 = "Hello";
If you want a mutable buffer then declare s1 as a char[]. std::string overloads operator [], so you can index into it, i.e., s1[index] = 'w'.
Time to confuse matters:
char s0[] = "Hello";
s0[0] = 'w';
This is perfectly valid! Of course, this doesn't answer the original question so here we go: string literals are created in read-only memory. That is, their type is char const[n] where n is the size of the string (including the terminating null character, i.e. n == 6 for the string literal "Hello". But why, oh, why can this type be used to initialize a char const*? The answer is simply backward compatibility, respectively compatibility to [old] C code: by the time const made it into the language, lots of places already initialized char* with string literals. Any decent compiler should warn about this abuse, however.