Converting a temporary character array to a string in D - d

I'm learning D language (I know C++ well)... I want to do some Windows specific stuff so I wrote this just to try out the API:
import core.sys.windows.windows;
import std.stdio;
string name()
{
char buffer[100];
uint size = 100;
GetComputerNameA(&buffer[0], &size);
return buffer;
}
void main()
{
writeln(name());
}
I get in my return statement:
test.d(11): Error: cannot implicitly convert expression (buffer) of type char[100] to string
Ok, in C++ it would call the constructor to make a string. It says implicit so lets cast it with a C style cast: return (string)buffer;.
test.d(11): Error: C style cast illegal, use cast(string)buffer
Ah ok, I remember, different syntax.
return cast(string)buffer;
Now it compiles but I just get garbage.
I assume that is is because it's storing a pointer in the string to the temporary buffer. I don't want to do this, I want to copy the characters into a string but annoyingly I can't seem to find how to do this?
So questions:
How do I construct an actual string from a char array that allocates storage properly? (Copies the characters)
Allocating a buffer of a random size like this and converting to a string seems ugly. Is there a proper way to do this in D? (I'm talking about the general question, not specifically this API just in case there is another API to get the computer name).
If either of those are answered in a manual where should I have looked to find details?
Thanks for any help and advice.

I think you need:
string name()
{
char buffer[100];
uint size = 100;
GetComputerNameA(buffer.ptr, &size);
return buffer[0 .. size].idup;
}

buffer.idup is the standard way to get an immutable copy. For this case, since you want a dynamically-sized string (and recall that string is really just shorthand for immutable(char)[]), you want buffer[0..size].idup, using D's array slicing.
See http://dlang.org/arrays.html for more information.
(This is a bit of a nitpick, but you may want to use buffer.ptr instead of &buffer[0], mostly for readability's sake.)

Related

How to avoid providing length along with char*?

There is a function which sends data to the server:
int send(
_In_ SOCKET s,
_In_ const char *buf,
_In_ int len,
_In_ int flags
);
Providing length seems to me a little bit weird. I need to write a function, sending a line to the server and wrapping this one such that we don't have to provide length explicitly. I'm a Java-developer and in Java we could just invoke String::length() method, but now we're not in Java. How can I do that, unless providing length as a template parameter? For instance:
void sendLine(SOCKET s, const char *buf)
{
}
Is it possible to implement such a function?
Use std string:
void sendLine(SOCKET s, const std::string& buf) {
send (s, buf.c_str(), buf.size()+1, 0); //+1 will also transmit terminating \0.
}
On a side note: your wrapper function ignores the return value and doesn't take any flags.
you can retrieve the length of C-string by using strlen(const char*) function.
make sure all the strings are null terminated and keep in mind that null-termination (the length grows by 1)
Edit: My answer originally only mentioned std::string. I've now also added std::vector<char> to account for situations where send is not used for strictly textual data.
First of all, you absolutely need a C++ book. You are looking for either the std::string class or for std::vector<char>, both of which are fundamental elements of the language.
Your question is a bit like asking, in Java, how to avoid char[] because you never heard of java.lang.String, or how to avoid arrays in general because you never heard of java.util.ArrayList.
For the first part of this answer, let's assume you are dealing with just text output here, i.e. with output where a char is really meant to be a text character. That's the std::string use case.
Providing lenght seems to me a little bit wierd.
That's the way strings work in C. A C string is really a pointer to a memory location where characters are stored. Normally, C strings are null-terminated. This means that the last character stored for the string is '\0'. It means "the string stops here, and if you move further, you enter illegal territory".
Here is a C-style example:
#include <string.h>
#include <stdio.h>
void f(char const* s)
{
int l = strlen(s); // l = 3
printf(s); // prints "foo"
}
int main()
{
char* test = new char[4]; // avoid new[] in real programs
test[0] = 'f';
test[1] = 'o';
test[2] = 'o';
test[3] = '\0';
f(test);
delete[] test;
}
strlen just counts all characters at the specified position in memory until it finds '\0'. printf just writes all characters at the specified position in memory until it finds '\0'.
So far, so good. Now what happens if someone forgets about the null terminator?
char* test = new char[3]; // don't do this at home, please
test[0] = 'f';
test[1] = 'o';
test[2] = 'o';
f(test); // uh-oh, there is no null terminator...
The result will be undefined behaviour. strlen will keep looking for '\0'. So will printf. The functions will try to read memory they are not supposed to. The program is allowed to do anything, including crashing. The evil thing is that most likely, nothing will happen for a while because a '\0' just happens to be stored there in memory, until one day you are not so lucky anymore.
That's why C functions are sometimes made safer by requiring you to explicitly specify the number of characters. Your send is such a function. It works fine even without null-terminated strings.
So much for C strings. And now please don't use them in your C++ code. Use std::string. It is designed to be compatible with C functions by providing the c_str() member function, which returns a null-terminated char const * pointing to the contents of the string, and it of course has a size() member function to tell you the number of characters without the null-terminated character (e.g. for a std::string representing the word "foo", size() would be 3, not 4, and 3 is also what a C function like yours would probably expect, but you have to look at the documentation of the function to find out whether it needs the number of visible characters or number of elements in memory).
In fact, with std::string you can just forget about the whole null-termination business. Everything is nicely automated. std::string is exactly as easy and safe to use as java.lang.String.
Your sendLine should thus become:
void sendLine(SOCKET s, std::string const& line)
{
send(s, line.c_str(), line.size());
}
(Passing a std::string by const& is the normal way of passing big objects in C++. It's just for performance, but it's such a widely-used convention that your code would look strange if you just passed std::string.)
How can I do that, unless providing lenght as a template parameter?
This is a misunderstanding of how templates work. With a template, the length would have to be known at compile time. That's certainly not what you intended.
Now, for the second part of the answer, perhaps you aren't really dealing with text here. It's unlikely, as the name "sendLine" in your example sounds very much like text, but perhaps you are dealing with raw data, and a char in your output does not represent a text character but just a value to be interpreted as something completely different, such as the contents of an image file.
In that case, std::string is a poor choice. Your output could contain '\0' characters that do not have the meaning of "data ends here", but which are part of the normal contents. In other words, you don't really have strings anymore, you have a range of char elements in which '\0' has no special meaning.
For this situation, C++ offers the std::vector template, which you can use as std::vector<char>. It is also designed to be usable with C functions by providing a member function that returns a char pointer. Here's an example:
void sendLine(SOCKET s, std::vector<char> const& data)
{
send(s, &data[0], data.size());
}
(The unusual &data[0] syntax means "pointer to the first element of the encapsulated data. C++11 has nicer-to-read ways of doing this, but &data[0] also works in older versions of C++.)
Things to keep in mind:
std::string is like String in Java.
std::vector is like ArrayList in Java.
std::string is for a range of char with the meaning of text, std::vector<char> is for a range of char with the meaning of raw data.
std::string and std::vector are designed to work together with C APIs.
Do not use new[] in C++.
Understand the null termination of C strings.

good manier to get char[] from another function. Starting thinking in c/c++

As I understood the correct programming style tells that if you want to get string (char []) from another function is best to create char * by caller and pass it to string formating function together with created string length. In my case string formating function is "getss".
void getss(char *ss, int& l)
{
sprintf (ss,"aaaaaaaaaa%d",1);
l=11;
}
int _tmain(int argc, _TCHAR* argv[])
{
char *f = new char [1];
int l =0;
getss(f,l);
cout<<f;
char d[50] ;
cin>> d;
return 0;
}
"getss" formats string and returns it to ss*. I thought that getss is not allowed to got outside string length that was created by caller. By my understanding callers tells length by variable "l" and "getcc" returns back length in case buffer is not filled comleatly but it is not allowed go outside array range defined by caller.
But reality told me that really it is not so important what size of buffer was created by caller. It is ok, if you create size of 1, and getss fills with 11 characters long. In output I will get all characters that "getss" has filled.
So what is reason to pass length variable - you will always get string that is zero terminated and you will find the end according that.
What is the reason to create buffer with specified length if getss can expand it?
How it is done in real world - to get string from another function?
Actually, the caller is the one that has allocated the buffer and knows the maximum size of the string that can fit inside. It passes that size to the function, and the function has to use it to avoid overflowing the passed buffer.
In your example, it means calling snprintf() rather than sprintf():
void getss(char *ss, int& l)
{
l = snprintf(ss, l, "aaaaaaaaaa%d", 1);
}
In C++, of course, you only have to return an instance of std::string, so that's mostly a C paradigm. Since C does not support references, the function usually returns the length of the string:
int getss(char *buffer, size_t bufsize)
{
return snprintf(buffer, bufsize, "aaaaaaaaaa%d", 1);
}
You were only lucky. Sprintf() can't expand the (statically allocated) storage, and unless you pass in a char array of at least length + 1 elements, expect your program to crash.
In this case you are simply lucky that there is no "important" other data after the "char*" in memory.
The C runtime does not always detect these kinds of violations reliably.
Nonetheless, your are messing up the memory here and your program is prone to crash any time.
Apart from that, using raw "char*" pointers is really a thing you should not do any more in "modern" C++ code.
Use STL classes (std::string, std::wstring) instead. That way you do not have to bother about memory issues like this.
In real world in C++ is better to use std::string objects and std::stringstream
char *f = new char [1];
sprintf (ss,"aaaaaaaaaa%d",1);
Hello, buffer overflow! Use snprintf instead of sprintf in C and use C++ features in C++.
By my understanding callers tells length by variable "l" and "getcc" returns back length in case buffer is not filled comleatly but it is not allowed go outside array range defined by caller.
This is spot on!
But reality told me that really it is not so important what size of buffer was created by caller. It is ok, if you create size of 1, and getss fills with 11 characters long. In output I will get all characters that "getss" has filled.
This is absolutely wrong: you invoked undefined behavior, and did not get a crash. A memory checker such as valgrind would report this behavior as an error.
So what is reason to pass length variable.
The length is there to avoid this kind of undefined behavior. I understand that this is rather frustrating when you do not know the length of the string being returned, but this is the only safe way of doing it that does not create questions of string ownership.
One alternative is to allocate the return value dynamically. This lets you return strings of arbitrary length, but the caller is now responsible for freeing the returned value. This is not very intuitive to the reader, because malloc and free happen in different places.
The answer in C++ is quite different, and it is a lot better: you use std::string, a class from the standard library that represents strings of arbitrary length. Objects of this class manage the memory allocated for the string, eliminating the need of calling free manually.
For cpp consider smart pointers in your case propably a shared_ptr, this will take care of freeing the memory, currently your program is leaking memory since, you never free the memory you allocate with new. Space allocate by new must be dealocated with delete or it will be allocated till your programm exits, this is bad, imagine your browser not freeing the memory it uses for tabs when you close them.
In the special case of strings I would recommend what OP's said, go with a String. With Cpp11 this will be moved (not copied) and you don't need to use new and have no worries with delete.
std::string myFunc() {
std::string str
//work with str
return str
}
In C++ you don't have to build a string. Just output the parts separately
std::cout << "aaaaaaaaaa" << 1;
Or, if you want to save it as a string
std::string f = "aaaaaaaaaa" + std::to_string(1);
(Event though calling to_string is a bit silly for a constant value).

Initialize wide char array

I have a wide char variable which I want to initialize with a size of string.
I tried following but didn't worked.
std::string s = "aaaaaaaaaaaaaaaaaaaaa"; //this could be any length
const int Strl = s.length();
wchar_t wStr[Strl ]; // This throws error message as constant expression expected.
what option do i have to achieve this? will malloc work in this case?
Since this is C++, use new instead of malloc.
It doesn't work because C++ doesn't support VLA's. (variable-length arrays)
The size of the array must be a compile-time constant.
wchar_t* wStr = new wchar_t[Strl];
//free the memory
delete[] wStr;
First of all, you can't just copy a string to a wide character array - everything is going to go berserk on you.
A std::string is built with char, a std::wstring is built with wchar_t. Copying a string to a wchar_t[] is not going to work - you'll get gibberish back. Read up on UTF8 and UTF16 for more info.
That said, as Luchian says, VLAs can't be done in C++ and his heap allocation will do the trick.
However, I must ask why are you doing this? If you're using std::string you shouldn't (almost) ever need to use a character array. I assume you're trying to pass the string to a function that takes a character array/pointer as a parameter - do you know about the .c_str() function of a string that will return a pointer to the contents?
std::wstring ws;
ws.resize(s.length());
this will give you a wchar_t container that will serve the purpose , and be conceptually a variable length container. And try to stay away from C style arrays in C++ as much as possible, the standard containers fit the bill in every circumstance, including interfacing with C api libraries. If you need to convert your string from char to wchar_t , c++11 introduced some string conversion functions to convert from wchar_t to char, but Im not sure if they work the other way around.

Assigning a string of characters to a char array

I Want to know why the first statements works and why not second one in c++
char a[10]="iqbal"; // it works
a="iqbal"; // does not work
Strictly speaking, an array is not a pointer! And an array ( base address of the array ) cant be a modifiable lvalue. ie it cannot appear on the left hand side of an assignment operator.Arrays decay into pointers only in certain circumstances. Read this SO post to learn when arrays decay into pointers. Here is one more nice article which explains the differences between arrays and pointers
Also read about lvalues and rvalues here so that you get an idea of things which cannot appear on the LHS of =
char a[10]="iqbal";  // it works
In this case, internally what happens is
a[0] = 'i';
a[1] = 'q';
.
.
a[5] = '\0';
So everything is fine as array[i] is a modifiable lvalue.
a="iqbal"; // does not work
Internally, this is roughly equivalent to
0x60000(Address of a, but is a simple number here ) = Address of "iqbal"
This is wrong as we cannot assign something to a number.
The char array a will be static and can not be changed if you initialize it like this. Anyway you can never assign a character string a="iqbal" in c. You have to use strncpy or memcpy for that. Otherwise you will try to overwrite the pointer to the string, and that is not what you want.
So the correct code would do something like:
char a[10];
strncpy(a, "iqbal", sizeof(a) - 1);
a[sizeof(a) - 1] = 0;
The -1 is to reserve a byte for the terminating zero. Note, you will have to check for yourself if the string is null terminated or not. Bad api. There is a strlcpy() call that does this for you but it is not included in glibc.
The first line is not a statement but a declaration with an initialization.
The second line is an expression statement with the assignment operator.
You cannot assign arrays in C.
But you can initialize an array with the elements of a string literal.
why the first statements works and why not second one in c++
Because they are different statements, almost wholly unrelated. Do not be confused by the fact that they both use the = symbol. In one case, it represents object initialization. In the other case, the assignment operator.
Your first line is legal because it is legal to initialize aggregates, including character arrays.
Your second line is not legal because it is not legal to assign to an array.
Since this is C++, may I suggest that you avoid naked arrays? For character strings use std::string. For other arrays use std::vector. If you do, you example becomes:
std::string a = "iqbal"; // it works
a="iqbal"; // so does this
When writing
char a[10]="iqbal"
You are initializing the elements of the character array a with the characters. We can do the same with int type (note that the char type gets a slightly different treatment) :
int a[10]={1,2,...};
But writing the following after declaration part would be invalid as a would be treated just like a pointer. So writing something like
a={1,2,...};
or a="iqbal"
won't be making any sense!
try:
char a[10]="iqbal";
char *my_a = a;
and work with my_a.
In C++11 you can use a lambda to do the initialization, like so:
bool test = true;
/*const*/ char a[10] = { //Aggregate initialization
[=] //capture by value
()//no parameters
{ //start lambda
switch (test) {
case true: return *"test=true"; //*"xxx" don't return a pointer, but the 'string' itself
case false: return *"test=false";
} //switch
}()}; //}, close the lambda, (), call it, }; close aggregate initialization
This comes in handy when your environment does not support std::string, like NVidia's CUDA or some strange embedded environment.
The lambda gets to be inlined, so internally it translates to char a[10] = test?"xxx":"yyy";
If you have the option to do so, you obviously want to always use std::string, because fixed sized char buffers are fundamentally a bad idea.
If you use std::string you can convert that to a char array using: chararray = mystring.c_str();. Which is useful if you insist on using printf: printf("s = %s", mystring.c_str());.
You cannot assign a string literal to a char array after the latter's declaration.
A nice, simple & effective alternative is to use std::strcpy to do so, like so:
struct S
{
char name[30];
};
S s;
std::strcpy( s.name,
"The moribunds salute you." );

how to initialize a char array?

char * msg = new char[65546];
want to initialize to 0 for all of them. what is the best way to do this in C++?
char * msg = new char[65546]();
It's known as value-initialisation, and was introduced in C++03. If you happen to find yourself trapped in a previous decade, then you'll need to use std::fill() (or memset() if you want to pretend it's C).
Note that this won't work for any value other than zero. I think C++0x will offer a way to do that, but I'm a bit behind the times so I can't comment on that.
UPDATE: it seems my ruminations on the past and future of the language aren't entirely accurate; see the comments for corrections.
The "most C++" way to do this would be to use std::fill.
std::fill(msg, msg + 65546, 0);
Absent a really good reason to do otherwise, I'd probably use:
std::vector<char> msg(65546, '\0');
what is the best way to do this in
C++?
Because you asked it this way:
std::string msg(65546, 0); // all characters will be set to 0
Or:
std::vector<char> msg(65546); // all characters will be initialized to 0
If you are working with C functions which accept char* or const char*, then you can do:
some_c_function(&msg[0]);
You can also use the c_str() method on std::string if it accepts const char* or data().
The benefit of this approach is that you can do everything you want to do with a dynamically allocating char buffer but more safely, flexibly, and sometimes even more efficiently (avoiding the need to recompute string length linearly, e.g.). Best of all, you don't have to free the memory allocated manually, as the destructor will do this for you.
This method uses the 'C' memset function, and is very fast (avoids a char-by-char loop).
const uint size = 65546;
char* msg = new char[size];
memset(reinterpret_cast<void*>(msg), 0, size);
memset(msg, 0, 65546)
You can use a for loop. but don't forget the last char must be a null character !
char * msg = new char[65546];
for(int i=0;i<65545;i++)
{
msg[i]='0';
}
msg[65545]='\0';
The C-like method may not be as attractive as the other solutions to this question, but added here for completeness:
You can initialise with NULLs like this:
char msg[65536] = {0};
Or to use zeros consider the following:
char msg[65536] = {'0' another 65535 of these separated by comma};
But do not try it as not possible, so use memset!
In the second case, add the following after the memset if you want to use msg as a string.
msg[65536 - 1] = '\0'
Answers to this question also provide further insight.
If you panic and can not assign dynamic data to a const char* in a constructor you can insert each element of a dynamic buffer piece by piece. You can even snprintf() to the buffer before making the imprint.
client_id = new char[26] {
buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],buf[8],buf[9],
buf[10],buf[11],buf[12],buf[13],buf[14],buf[15],buf[16],buf[17],buf[18],buf[19],
buf[20],buf[21],buf[22],buf[23],buf[24],'\0'
};
To cover up what you have been doing, maybe the editor has an option where you can set the forecolor same as the background?
Before being fired you can actually prime the const char in the header file declaration with enough space and then later assign real data in the constructor. Great!
const char* client_id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
It is a const pointer and does not have to be initialized before the constructor deals with it.
const char* client_id;
NOTE:
You can write at the top of the page: using namespace std,
and thus avoid writing std:: at the beginning of each command.
char * msg = new char[65546]={0};
This command reset all the array to 0.