Strange error in variable values C++ - c++

I have used this code. Here a string is present from location starting from 4 and length of string is 14. All these calculations are done prior to this code. I am pasting a small snippet of the error containing code.
void *data = malloc(4096);
int len = 14;
int fileptr = 4;
string str;
cout<<len<<endl;
cout<<fileptr<<endl;
memcpy(&str, (char *)data+fileptr, len);
cout<<len<<endl;
cout<<fileptr<<endl;
Output i get is:
14
4
4012176
2009288233
Here i am reading a string "System Catalog" from memory. Its displaying the string correctly. But the values of fileptr and len are abruptly changing after using memcpy() function.

string is not the same as a char*. string is an object. So you can't just memcpy() data to it. So the behavior of this code is undefined.
In your case, you are copying 14 bytes of junk data into str and corrupting the stack.
The result is that you are overwriting both len and fileptr with junk from the malloc().
I'm not sure exactly what you're trying to do, but if you want to create a string, you should do it like this:
string str = "System Catalog";

A string is an object and is not just a sequence of bytes. You cannot just memcpy over it from raw memory.
My guess is that in your code the str variable is allocated before other variables in stack memory and memcpy-ing over it you are overwriting them.
Note that your phrase "It's displaying the string correctly" has the seed of a common misconception about C++ in it.
When you do bad things in C++ (e.g. writing bytes over an object) you should expect the worst possible behavior. The worst possible behavior however is NOT an ugly result, a crash or a runtime error... but something that seems to work but that has bad consequences in the future.

You want to assign this many characters from that char pointer into a std::string, so you should look at what facilities a string object provides for doing that rather than hitting it over the head with memcpy(). As others have noted, memcpy() is for use in low-level C-style code, not for interacting with C++ objects.
In particular, you should study the assignment methods provided by std::string, one of which does exactly what you want -- which isn't a coincidence.

string is an object - please look up the semantics for it. Why are you doing this and what are you trying to achieve?

If for some reason you actually MUST use memcpy you can get the Internal address of the string to copy to (provided the string is big enough to contain the information you want to copy)
static_cast < char * >(&(str[0]));
But this is VERY VERY BAD. If you use it, I'm quite sure there are more crazy things going on in your code :-)

Related

better approach to copy portion of char array than strncpy

I used std::strncpy in c++98 to copy portion of a char array to another char array. It seems that it requires to manually add the ending character '\0', in order to properly terminate the string.
As below, if not explicitly appending '\0' to num1, the char array may have other characters in the later portion.
char buffer[] = "tag1=123456789!!!tag2=111222333!!!10=240";
char num1[10];
std::strncpy(num1, buffer+5, 9);
num1[9] = '\0';
Is there better approach than this? I'd like to have a one-step operation to reach this goal.
Yes, working with "strings" in C was rather verbose, wasn't it!
Fortunately, C++ is not so limited:
const char* in = "tag1=123456789!!!tag2=111222333!!!10=240";
std::string num1{in+5, in+15};
If you can't use a std::string, or don't want to, then simply wrap the logic you have described into a function, and call that function.
As below, if not explicitly appending '\0' to num1, the char array may have other characters in the later portion.
Not quite correct. There is no "later portion". The "later portion" you thought you observed was other parts of memory that you had no right to view. By failing to null-terminate your would-be C-string, your program has undefined behaviour and the computer could have done anything, like travelling back in time and murdering my great-great-grandmother. Thanks a lot, pal!
It's worth noting, then, that because it's C library functions doing that out-of-bounds memory access, if you hadn't used those library functions in that way then you didn't need to null-terminate num1. Only if you want to treat it as a C-style string later is that required. If you just consider it to be an array of 10 bytes, then everything is still fine.

C++ - Using GetPrivateProfileString without buffer

I'm using GetPrivateProfileStringA to read some things from a .ini file. I have some other class where I save things along with a string array. I have to use it like this to get a proper string into the ControlAlt array:
char buffer[24];
GetPrivateProfileStringA("CONTROLS",
"ShiftUpAlt",
"LeftThumb",
buffer,
(DWORD)24,
"./Gears.ini");
scriptControl->ControlAlt[ScriptControls::ControlType::ShiftUp] = buffer;
I've tried putting it in directly, like so:
GetPrivateProfileStringA("CONTROLS",
"ShiftUpAlt",
"LeftThumb",
(LPSTR)scriptControl->ControlAlt[ScriptControls::ControlType::ShiftUp],
(DWORD)24,
"./Gears.ini");
But then the value in ControlAlt is an LPSTR, which gives complications later when comparing it against a proper string. Is there a way to not use a buffer for this?
ControlAlt is defined as std::string ControlAlt[SIZEOF_ControlType];
GetPrivateProfileStringA requires a buffer to write a classic C-style '\0'-terminated string into, and a std::string is not such a buffer, although as you observe, a C-style string can be converted to a std::string.
More specifically, GetPrivateProfileStringA expects a char * (LPSTR in Windows API terms) pointing to a writable buffer and that buffer's length. std::string does not provide this - at best, it provides the c_str() accessor which returns const char * (LPCSTR in Windows API terms) - a pointer to a read-only buffer. The const-ness of the buffer data is a pretty good indication that modifying it is a bad idea and will more than likely lead to undefined behavior.
C++ '98 says: "A program shall not alter any of the characters in this sequence." However, implementations conforming to newer standards may well be more willing to put up with monkey business: resize() to make the buffer large enough, then use &foo[0] to get a char * that isn't const (or just const_cast away the protection on data()), let GetPrivateProfileStringA write to the buffer, then truncate the std::string at the '\0' wherever it landed. This still doesn't let you pass in a std::string directly to a function expecting a buffer pointer, though, because they are not the same thing - it just gives you a chance to avoid copying the string one extra time from the buffer.

Overlapping strings

I have a problem with overlapping char*.
I'm working in a low-memory environment, namely Arduino and I would like to use the least memory possible. I want to be able to prepend a string with another and to do it without any copying of variables which wastes memory.
This is standard C or C++.
char* bigPacket = (char*)malloc(25); //Makes a big string of length 25
char* payload = bigPacket + 2; //This is part of the big string, 2 chars in.
bigPacket[0] = 72; // Letter 'H'
bigPacket[1] = 72; //I'm expecting the final bigPacket to read "HHHello, world"
payload = "Hello, World";
print(bigPacket);
But the problem is that it does not print "HHHello, world" as it should. Instead, it just prints "HH". Is there a proper way to make it be able to overlap these strings to print "HHHello, world"?
You changed where payload points. What you needed to do was leave payload alone and change the data it points to.
strcpy(payload, "Hello World");
Edit: If you really want to avoid copies you'd end up with something like the SGI Rope class. But you'd pay a lot in code complexity.
If you want to do this without either very complicated code or multiple copies of data, destroying the benefit, you need to have the complete string as one literal in your program: "HHHelloWorld". You can then play with pointers and lengths to access various parts of it, but remember there is only one null byte, at the end of the string.
However, I suspect that this is an over-optimization. Arduino programming rarely involves a lot of very long string. It is important to keep the code simple and direct.
You should not mess with pointers for something like that. Instead you should store string literals in flash instead of sram memory. This is usually done with the help of progmem macros. Often the "F" macro is sufficient though. Then you can copy your strings - as needed - and if needed - into a suitable buffer.
Simplest example:
Serial.println(F("this is text from flash memory"));
You just assign the payload pointer to point to the constant string, you do not copy the string to what it currently points to.
In order to copy the string you need to use strcpy or memcpy:
char *bigPacket = malloc(25);
bigPacket[0] = bigpacket[1] = 72;
strcpy( bigpacket+2, "Hello, World");
print( bigPacket );
Note that this is rather unlikely to save memory, since "Hello, world" will exist as a constant string in your code, to save memory it is probably most efficient to call print multiple times.
However, I guess that is not possible in this case.

C++: Format not a string literal and no format arguments [duplicate]

This question already has answers here:
warning: format not a string literal and no format arguments
(3 answers)
Closed 8 years ago.
I've been trying to print a string literal but seems like I'm doing it wrong, since I'm getting a warning on compilation. It's probably due to wrong formatting or my misunderstanding of c_str() function, which I assume should return a string.
parser.y: In function ‘void setVal(int)’:
parser.y:617:41: warning: format not a string literal and no format arguments [-Wformat-security]
Line 617:
sprintf(temp, constStack.top().c_str());
Having those declarations
#include <stack>
const int LENGTH = 15;
char *temp = new char[LENGTH];
stack<string> constStack;
How can I provide a proper formating to string?
Simple - provide a format string:
sprintf(temp, "%s", constStack.top().c_str());
But much, much better:
string temp = constStack.top();
You are telling me in your comment that the problem is not so much the warning as the fact that your code doesn't do what you expect it to.
The solution to this and other, similar problems is to get rid of the strong C influence in your C++ code. Specifically, don't use raw dynamically allocated char arrays or sprintf. Use std::string instead.
In this case, you are using sprintf very incorrectly. Have you ever seen its signature? It goes like this:
sprintf(char *str, char const *format, ...)
str is the output of the operation. format describes what the output should be. The rest are the format arguments, which must by pure convention match what's described in format.
Now this "rest", written as ..., means that you can pass any number of arguments, even zero. And this is why your code even compiles (delivering a nice example for why ... is a dangerous feature, by the way).
In your code, the output string is, possibly incorrectly, your temp string. And the format to describe the output is, almost certainly incorrectly, what happens to sit on top of your stack.
Is this just about assigning one string to another, using sprintf simply because it more or less can do that as a very special case of what its feature set offers? There's no need for such hacks, as C++ has string assignment out of the box with std::string:
std::string temp = constStack.top();
Notice that this also eliminates the need to know the length of the string in advance.
If, for some reason, you really need formatting (but your question doesn't really show any need for it), then learn more about string streams as an alternative solution to format strings.
As the warning indicates it is issued as a result of the -Wformat-security option; you could simply disable the warning by removing the option; but it would be perhaps unwise.
The security issue is perhaps theoretical unless your code is to be widely distributed. Of perhaps more immediate concern is the possibility of your code crashing or behaving abnormally.
The problem is that the string is variable, and may at runtime contain formatting characters that cause it to attempt to read non-existent arguments. If for example the string is received from user input and the user entered "%s" it would attempt to read a string from some somewhere on the stack. That would at best place junk in temp, but worse if the memory read happened not to contain a nul character in the first 15 bytes, it would overrun temp, and corrupt the heap (in this case). Heap corruptions are probably worse than stack corruptions - the latent bug can remain unnoticed in your code for a long time only to start crashing after some unrelated change; and if it does crash, it is unlikely to be in any proximity to the cause.

single character c-style string full of junk

It's a shame I can't figure out such basic thing about c++, but c-style strings are acting as I wouldn't expect. For example, I create it like this:
char* cstr = new char[1];
It's initialized to: Íýýýýý««««««««îţ . Like normal, I can set just first char because others are not really existing (or I thought that they aren't). While working whit c-style strings all this junk is ingored and everything works fine.
Now I mixed std::string whit those c-stlye one and what I get is a mess. Whit this code:
std::string str = "aaa";
str += cstr;
I end up whit: aaaÍýýýýý««««««««îţ , but now those characters actually exist as string.size() returns length including this junk.
I can't find why is this happening, but it must be connected whit string creating, because something like char* cstr = "aaa" results in aaa without any additional junk, but trying to change string initialized this way results in memory access violation. Could someone explain me this behavior please? Thanks!
PS: My JavaScript Failed to load so if someone could format this post properly, I'd be glad!
Answer: Oh god! How could I forget on that... thanks to all for, well, immediate answer. Best one was from minitech so I'll mark this as answer as soon as my java script loads up :/
All C-style strings are null-terminated. So, a string initialized using new char[1] leaves you space for no characters. You can't set the first character to anything but \0, otherwise normal string operations will keep reading into memory until they find a zero. So use new char[2] instead.
When working with C-style strings you need to have a null terminator:
char* cstr = new char[2];
cstr[0] = 'X';
cstr[1] = '\0';
Having said all that, it is really bad code to do the above. Just use std::string unless you have a very good reason not too. It takes care of the memory allocations and deallocations for you.
C-style strings require a NUL ('\0') terminator; they don't have a length associated with them like C++ strings do. So your single-character string must be new char[2]; it will not be initialized; and you will need to make sure it's terminated with \0.
When you use new char[1], you request space for an array of characters. There is no request that said characters are initialized. Thus, the "junk" that you see is uninitialized memory. Before treating the array as a C-style string, you should do this:
cstr[0] = '\0';
c-style strings are NULL delimited. So, to ignore any junk in memory you need to place NULL byte('\0') in the string body. Otherwise, system library function will look at all bytes starting with your string start until they meet NULL byte in the memory (which will be at some random position).
This also mean that to have c-style string of one character you actually need to allocate 2 bytes: one for a meaningful character and second for '\0'.