How to convert a string type to an array of chars - d

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;

Related

modify const char * vs char * content in easy way

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...

How to assign one char* to another char*

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.

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.

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.

What is the use of the c_str() function?

I understand c_str converts a string, that may or may not be null-terminated, to a null-terminated string.
Is this true? Can you give some examples?
c_str returns a const char* that points to a null-terminated string (i.e., a C-style string). It is useful when you want to pass the "contents"¹ of an std::string to a function that expects to work with a C-style string.
For example, consider this code:
std::string string("Hello, World!");
std::size_t pos1 = string.find_first_of('w');
std::size_t pos2 = static_cast<std::size_t>(std::strchr(string.c_str(), 'w') - string.c_str());
if (pos1 == pos2) {
std::printf("Both ways give the same result.\n");
}
See it in action.
Notes:
¹ This is not entirely true because an std::string (unlike a C string) can contain the \0 character. If it does, the code that receives the return value of c_str() will be fooled into thinking that the string is shorter than it really is, since it will interpret \0 as the end of the string.
In C++, you define your strings as
std::string MyString;
instead of
char MyString[20];.
While writing C++ code, you encounter some C functions which require C string as parameter.
Like below:
void IAmACFunction(int abc, float bcd, const char * cstring);
Now there is a problem. You are working with C++ and you are using std::string string variables. But this C function is asking for a C string. How do you convert your std::string to a standard C string?
Like this:
std::string MyString;
// ...
MyString = "Hello world!";
// ...
IAmACFunction(5, 2.45f, MyString.c_str());
This is what c_str() is for.
Note that, for std::wstring strings, c_str() returns a const w_char *.
Most old C++ and C functions, when dealing with strings, use const char*.
With STL and std::string, string.c_str() is introduced to be able to convert from std::string to const char*.
That means that if you promise not to change the buffer, you'll be able to use read-only string contents. PROMISE = const char*
In C/C++ programming there are two types of strings: the C strings and the standard strings. With the <string> header, we can use the standard strings. On the other hand, the C strings are just an array of normal chars. So, in order to convert a standard string to a C string, we use the c_str() function.
For example
// A string to a C-style string conversion //
const char *cstr1 = str1.c_str();
cout<<"Operation: *cstr1 = str1.c_str()"<<endl;
cout<<"The C-style string c_str1 is: "<<cstr1<<endl;
cout<<"\nOperation: strlen(cstr1)"<<endl;
cout<<"The length of C-style string str1 = "<<strlen(cstr1)<<endl;
And the output will be,
Operation: *cstr1 = str1.c_str()
The C-style string c_str1 is: Testing the c_str
Operation: strlen(cstr1)
The length of C-style string str1 = 17
c_str() converts a C++ string into a C-style string which is essentially a null terminated array of bytes. You use it when you want to pass a C++ string into a function that expects a C-style string (e.g., a lot of the Win32 API, POSIX style functions, etc.).
It's used to make std::string interoperable with C code that requires a null terminated char*.
You will use this when you encode/decode some string object you transfer between two programs.
Let’s say you use Base64 to encode some array in Python, and then you want to decode that into C++. Once you have the string you decode from Base64-decoded in C++. In order to get it back to an array of float, all you need to do here is:
float arr[1024];
memcpy(arr, ur_string.c_str(), sizeof(float) * 1024);
This is pretty common use, I suppose.
const char* c_str() const;
It returns a pointer to an array that contains a null-terminated sequence of characters (i.e., a C string), representing the current value of the string object.
This array includes the same sequence of characters that make up the value of the string object plus an additional terminating null - character ('\0') at the end.
std::string str = "hello";
std::cout << str; // hello
printf("%s", str); // ,²/☺
printf("%s", str.c_str()); // hello