Making a Direct2D program, I want to convert from int to WCHAR so I wrote the following code
void DemoApp::OnRender() {
//...
int a = 256;
std::wstring wStr = std::to_wstring(a);
static const WCHAR* pStrNum = wStr.c_str();
//Print the number to the screen
_pRenderTarget->DrawText(
pStrNum,
sizeof(pStrNum)/sizeof(pStrNum[0]),
_pTextFormat,
rect,
_pBrush);
//...
};
However, after one loop, the pStrNum changed to something weird, with the starting character is 5028 decimal base.
After messing a bit, I changed the conversion code to
const WCHAR* pStrNum = wStr.c_str();
The string printed almost correctly on the screen and everything seems to be normal except for the sizeof(pStrNum)/sizeof(pStrNum[0]) having the value of 2, therefore print only the first two characters on the screen.After all, I have to use lstrlenW() to get the number of elements in that string.
I need explaination on why static const WCHAR* is different from const WCHAR* and causes error
And why sizeof() doesn't work in this case?
I think (and I'll know for sure If I get lots of downvotes) that the behaviour of your code is undefined
This is because
static const WCHAR* pStrNum = wStr.c_str();
has static storage will be initialised once.
But wStr will be initialised every time the function is called, and that is the problem: in all subsequent calls to the function, the pointer will be dangling and the behaviour is undefined.
If I were you, I'd evaluate the .c_str() on a just in time basis. There will be no performance overhead in doing this.
To answer your question: use wStr.size() to get the length of the string: sizeof() returns the size of the data type (evaluated at compile time), not the string length.
sizeof(pStrNum) gives you the size of WCHAR*, not the string it points to.
You can only calculate an array's length using sizeof(arr)/sizeof(arr[0]) when you have access to the array declaration. At other times, you need to pass a size along with the array or iterate over its elements until you find a sentinel element marking the end of the elements. For a C-style string, you can iterate over its elements until you find one with value \0. wcslen does this for wchar_t.
_pRenderTarget->DrawText(
pStrNum,
wcslen(pStrNum),
_pTextFormat,
rect,
_pBrush);
Or, simpler, as Kerrek SB suggests, remove all use of pStrNum
_pRenderTarget->DrawText(
wStr.data(),
wStr.size(),
_pTextFormat,
rect,
_pBrush);
sizeof gives you the size of the object representation of whatever you pass it. You are giving pStrNum to sizeof, and pStrNum is a const WCHAR*, so what you're getting is the size of the pointer. sizeof doesn't work out the length of strings.
The reason your code doesn't work is that the compiler uses the static type of the variable to evaluate sizeof. sizeof(pStrNum) will be either 4 or 8 bytes, depending on your OS, as the variable is a pointer.
Just rewrite the code as:
_pRenderTarget->DrawText(
wStr.c_str(),
wStr.length(),
_pTextFormat,
rect,
_pBrush);
and you'll be ok
Related
I'm working on an exercise to calculate the length of a string using pointers.
Here's the code I've written below:
int main() {
std::string text = "Hello World";
std::string *string_ptr = &text;
int size = 0;
//Error below: ISO C++ forbids comparison between pointer and integer [-fpermissive]
while (string_ptr != '\0') {
size++;
string_ptr++;
}
std::cout << size;
}
In a lot of examples that I've seen, the string is often a char array which I also understand is a string. However, I want to try calculate it as a string object but I'm getting the error below.
Is it possible to calculate it where the string is an object, or does it need to be a char array?
If you just want the size of the string, well, use std::string::size():
auto size = text.size();
Alternatively, you can use length(), which does the same thing.
But I'm guessing you're trying to reimplement strlen for learning purposes. In that case, there are three problems with your code.
First, you're trying to count the number of characters in the string, and that means you need a pointer to char, not a pointer to std::string. That pointer should also point to constant characters, because you're not trying to modify those characters.
Second, to get a pointer to the string's characters, use its method c_str(). Getting the address of the string just gets you a pointer to the string itself, not its contents. Most importantly, the characters pointed to by c_str() are null terminated, so it is safe to use for your purposes here. Alternatively, use data(), which has been behaving identically to c_str() since C++11.
Finally, counting those characters involves checking if the value pointed to by the pointer is '\0', so you'll need to dereference it in your loop.
Putting all of this together:
const char* string_ptr = text.c_str(); // get the characters
int size = 0;
while (*string_ptr != '\0') { // make sure you dereference the pointer
size++;
string_ptr++;
}
Of course, this assumes the string does not contain what are known as "embedded nulls", which is when there are '\0' characters before the end. std::string can contain such characters and will work correctly. In that case, your function will return a different value from what the string's size() method would, but there's no way around it.
For that reason, you should really just call size().
First things first, the problem is irrelevant. std::string::size() is a O(1) (constant time) operation, as std::string's typically store their size. Even if you need to know the length of a C-style string (aka char*), you can use strlen. (I get that this is an exercise, but I still wanted to warn you.)
Anyway, here you go:
size_t cstrSize(const char* cstr)
{
size_t size(0);
while (*cstr != '\0')
{
++size;
++cstr;
}
return size;
}
You can get the underlying C-style string (which is a pointer to the first character) of a std::string by calling std::string::c_str(). What you did was getting a pointer to the std::string object itself, and dereferencing it would just give you that object back. And yes, you need to dereference it (using the * unary operator). That is why you got an error (which was on the (string_ptr != '\0') btw).
You are totally confused here.
“text” is a std::string, that is an object with a size() method retuning the length of the string.
“string_ptr” is a pointer to a std::string, that is a pointer to an object. Since it is a pointer to an object, you don’t use text.size() to get the length, but string_ptr->size().
So first, no, you can’t compare a pointer with an integer constant, only with NULL or another pointer.
The first time you increase string_ptr it points to the memory after the variable text. At that point using *string_ptr for anything will crash.
Remember: std::string is an object.
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.
I have a const char
const char example[] = "\x4D\x5A\xE8\x00\x00\x00\x00\x5B\x52\x45\x55\x89\xE5\x81\xC3";
and
DWORD* example2 = "\xAA\xBB\xCC\xDD";
and i want to change the last 4 bytes of example1 with those on example2
what can I do in C++?
i have tried memcpy , strcpy and strcpy_s with no luck
You should not modify a constant array!
Modifying a inherently constant object/variable leads to Undefined Behavior.
Just don't do it. Make a copy of it and modify that copy or if you want to modify the same array simply don't declare it as const.
Donot modify a constant string.
const char example[] = "\x4D\x5A\xE8\x00\x00\x00\x00\x5B\x52\x45\x55\x89\xE5\x81\xC3"; here, your string has a few NULL string terminator. This will NOT work with functions in <string.h> (such as strlen() and others)
Instead use memcpy, memset functions to append ONLY after knowing the length of the binary string.
Store your result in a character array, but don't assume it will work as a regular string because of your data.
your example[] char array is defined as const so you can not modify it.
1) You should get an eror in the compilation if you change your const char array in this way
example[2] ='R';
2) You should get a warning if you modify your const char array via memcpy or via strcpy
Change it to
char example[] = "\x4D\x5A\xE8\x00\x00\x00\x00\x5B\x52\x45\x55\x89\xE5\x81\xC3";
And you can not use strcpy because your character array contains x00 in the middle so this will affect the strcpy function. Because strcpy stop when it find x00 in the char array
example[] char array contains x00 in the middle, so to find the length of example[] with strlen will not work properly. For this case I suggest to use sizeof(example) instead.
Here after how you can make your copy:
char example[] = "\x4D\x5A\xE8\x00\x00\x00\x00\x5B\x52\x45\x55\x89\xE5\x81\xC3";
DWORD* example2 = "\xAA\xBB\xCC\xDD";
if (sizeof(example)>=sizeof(example2))
memcpy(example+sizeof(example)-sizeof(example2), example2, sizeof(example2));
Const variables can't be changed. This is by design. In the case of a c string, you can have the contents of the string const or the pointer to the string const.
Since you are defining it as a const character array, the pointer is implicitely const and the contents are explicitly const.
const char * const mystring = "hello"
In this case the first "const" tries to apply left (there is nothing), so it applies right (to the char type). So the string content may not change. The second const tries to apply left, so it makes the pointer itself const. That means that the mystring pointer must always point to where the "h" from "hello" in memory is.
So afterwards if I try:
mystring[0] = "y"
or
mystring = "gooodbye!"
They would not work. If you removed the first or second const respectively, they could be made to work.
The purpose of const allows you to say ahead of time "this variable cannot be modified". That means that if it is modified then there is a problem. Generally you should always use const with any variable that you do not want to be modified after instantiation.
You should never modify a constant including a constant array. If you want to change what you have above, create a copy of it and change the copy. As pointed out by RasmusKaj strcpy will not help you here as the source strings contains zero chars so maybe use memcpy for the creation of the copy.
I have extracted the contents of a file mapped into memory, into an array which looks like:
char* const arr = static_cast<char *>(file.get_address());
whilst iterating through the array I wish to be able to call:
for(int i=0; i<file.get_size(); i++){
atoi(arr[i]);
}
however, atoi requires type const char* and arr[i] is type char* const. How may I resolve this?
First of all, I question your use of const in...
char* const arr = static_cast<char *>(file.get_address());
In this case, the const applies to the pointer, not to what it points at. So, via your arr pointer, you could do this...
arr[0] = 'a';
...which I think is not what you're trying to protect against. Instead, I think what you really want is:
const char* arr = static_cast<const char *>(file.get_address());
...which resolves what your question was posted about. In this way, you have a pointer that points to characters that can't be changed (at least not directly through that pointer).
Then, in your loop, you're calling atoi() on each character of the whole file, which I doubt is what you really want to do. Are you expecting a whole bunch of single-digit decimal (base 10) numbers, with no separators? That's the only use case for looping the way you are. For the sake of argument, let's suppose that's what you really want. OK, then, where do you want the results to go? You're not assigning the returned value of atoi() to anything. You're converting the single-digit (presumably ASCII) numbers from text into numeric form, but throwing away the results.
But I think that's probably not what you really want anyway.
Let's rewrite your code so that it will convert the file's first textual value (assuming it's not preceded by garbage) into an integer, and then print it. As in your example, we'll assume the file is already read into some object named file and that we can get its data buffer by calling file.get_address(). Here's what you'd want:
const char* arr = static_cast<const char *>(file.get_address());
int firstNumericValue = atoi(arr);
std::cout << "firstNumericValue = " << firstNumericValue << "\n";
...and that's all, no looping required! If you want to read in multiple values from the file, of course you could use looping, but you'll want to look into more advanced functions, such as sscanf() or strtol(). If you use strtol(), its second argument lets you get a pointer to the next place to begin converting for any subsequent calls. But examples for these abound, and you can research them yourself.
atoi(&(arr[i]));
will do the trick.
The & operator gives you a pointer to the char and the extra parentheses ensure that you are getting a pointer to the i-th element.
atoi doesn't care about the const on the array declaration, so it isn't relevant here.
In the CString header file (be it Microsoft's or Open Foundation Classes - http://www.koders.com/cpp/fid035C2F57DD64DBF54840B7C00EA7105DFDAA0EBD.aspx#L77 ), there is the following code snippet
struct CStringData
{
long nRefs;
int nDataLength;
int nAllocLength;
TCHAR* data() { return (TCHAR*)(&this[1]); };
...
};
What does the (TCHAR*)(&this[1]) indicate?
The CStringData struct is used in the CString class (http :// www.koders.com/cpp/fid100CC41B9D5E1056ED98FA36228968320362C4C1.aspx).
Any help is appreciated.
CString has lots of internal tricks which make it look like a normal string when passed e.g. to printf functions, despite actually being a class - without having to cast it to LPCTSTR in the argument list, e.g., in the case of varargs (...) in e.g. a printf. Thus trying to understand a single individual trick or function in the CString implementation is bad news. (The data function is an internal function which gets the 'real' buffer associated with the string.)
There's a book, MFC Internals that goes into it, and IIRC the Blaszczak book might touch it.
EDIT: As for what the expression actually translates to in terms of raw C++:-
TCHAR* data() { return (TCHAR*)(&this[1]); };
this says "pretend you're actually the first entry in an array of items allocated together. Now, the second item isnt actually a CString, it's a normal NUL terminated buffer of either Unicode or normal characters - i.e., an LPTSTR".
Another way of expressing the same thing is:
TCHAR* data() { return (TCHAR*)(this + 1); };
When you add 1 to a pointer to T, you actually add 1* sizeof T in terms of a raw memory address. So if one has a CString located at 0x00000010 with sizeof(CString) = 4, data will return a pointer to a NUL terminated array of chars buffer starting at 0x00000014
But just understanding this one thing out of context isnt necessarily a good idea.
Why do you need to know?
It returns the memory area that is immediately after the CStringData structure as an array of TCHAR characters.
You can understand why they are doing this if you look at the CString.cpp file:
static const struct {
CStringData data;
TCHAR ch;
} str_empty = {{-1, 0, 0}, 0};
CStringData* pData = (CStringData*)mem_alloc(sizeof(CStringData) + size*sizeof(TCHAR));
They do this trick, so that CString looks like a normal data buffer, and when you ask for the getdata it skips the CStringData structure and points directly to the real data buffer like char*