I am working with snmp and the requests->requestvb->val.string function returns me a u_char* and I am trying to store that into a char[255].
u_char newValue = *(requests->requestvb->val.string)
char myArray[255];
I have tried a few approaches to copy the contents of newValue into myArray but everything seems to segfault. What am I doing wrong?
I have tried
memcpy(myArray, newValue);
Another attempt strncopy(myArray, newValue, sizeof(myArray));
What am I doing wrong?
Your newValue is of type char, and for all intents and purposes, your myArray is of type char*.
First off, I'm going to assume that you're using memcpy correctly, and that you're passing in 3 parameters instead of 2, where the 3rd parameter is the same as the one you use in strncpy.
When you try using strncpy or memcpy, you're going beyond the one character "limit" in newValue when attempting to copy everything to myArray.
The fix should be quite simple:
u_char* newValue = requests->requestvb->val.string;
Once you've done that, this should work. Of course, that's assuming that the size of myArray is in fact greater than or equal to 255 :)
As a side note (and this should go without saying), please make sure that your myArray has a null terminating character at the end if you ever plan on printing it. Not having one after performing copy operations, and then trying to print is a very common mistake and can also lead to seg faults.
Related
The below code does not give any fault/error/warning(although I think there might be some illegal memory access happening). Strangely, the size of the string being printed using 2 different methods(strlen and std::string.size() is coming out differently.
strlen(l_str.c_str()-> is giving the size as 1500, whereas,
l_str.size()-> is giving the size as 0.
#include <string.h>
#include <string>
#include <stdio.h>
#include<iostream>
using namespace std;
void strRet(void* data)
{
char ar[1500];
memset(ar,0,1500);
for(int i=0;i<1500;i++)
ar[i]='a';
memset(data,0,1500); // This might not be correct but it works fine
memcpy(data,ar,1500);
}
int main()
{
std::string l_str;
cout<<endl<<"size before: "<<l_str.length();
int var=10;
strRet((void *)l_str.c_str());
printf("Str after call: %s\n",l_str.c_str());
cout<<endl<<"size after(using strlen): "<<strlen(l_str.c_str());
cout<<endl<<"Size after(using size function): "<<l_str.size();
printf("var value after call: %d\n",var);
return 0;
}
Please suggest, if I'm doing something which I'm not supposed to do!
Also, I wanted to know which memory bytes are being set to 0 when I do memset(data,0,1500);? What I mean to ask is that if suppose, my string variable's starting address is 100, then does memset command sets the memory range [100,1600] as 0? Or is it setting some other memory range?
memset(data,0,1500); // This might not be correct but it works fine
It isn't correct, and it doesn't "work fine". This is Undefined Behaviour, and you're making the common mistake of assuming that if it compiles, and your computer doesn't instantly catch fire, everything is fine.
It really isn't.
I've done something which I wasn't supposed to do!
Yes, you have. You took a pointer to a std::string, a non-trivial object with its own state and behaviour, asked it for the address of some memory it controls, and cast that to void*.
There's no reason to do that, you should very rarely ever see void* in C++ code, and seeing C-style casts to any type is pretty worrying.
Don't take void* pointers into objects with state and behaviour like std::string until you understand what you're doing and why this is wrong. Then, when that day comes, you still won't do it because you'll know better.
We can look at the first problem in some fine detail, if it helps:
(void *)l_str.c_str()
what does c_str() return? A pointer to some memory owned by l_str
where is this memory? No idea, that's l_str's business. If this standard library implementation uses the small string optimization, it may be inside the l_str object. If not, it may be dynamically allocated.
how much memory is allocated at this location? No idea, that's l_str's business. All we can say for sure is that there is at least one legally-addressable char (l_str.c_str()[0] == '\0') and that it's legal to use the address l_str.c_str()+1 (but only as a one-past-the-end pointer, so you can't dereference it)
So, the statement
strRet((void *)l_str.c_str());
passes strRet a pointer to a location containing one or more addressable chars, of which the first is zero. That's everything we can say about it.
Now let's look again at the problematic line
memset(data,0,1500); // This might not be correct but it works fine
why would we expect there to be 1500 chars at this location? If you'd documented strRet as requiring a buffer of at least 1500 allocated chars, would it look reasonable to actually pass l_str.c_str() when you know l_str has just been default constructed as an empty string? It's not like you asked l_str to allocate that storage for you.
You could start to make this work by giving l_str a chance to allocate the memory you intend to write, by calling
l_str.reserve(1500);
before calling strRet. This still won't notify l_str that you filled it with 'a's though, because you did that by changing the raw memory behind its back.
If you want this to work correctly, you could replace the entirety of strRet with
std::string l_str(1500, 'a');
or, if you want to change an existing string correctly, with
void strRet(std::string& out) {
// this just speeds it up, since we know the size in advance
out.reserve(1500);
// this is in case the string wasn't already empty
out.clear();
// and this actually does the work
std::fill_n(std::back_inserter(out), 1500, 'a');
}
I want to create a byte array out of an unknown struct and add a number additionally in the front of this byte array. How do I do this?
I currently have this code:
template <class T>
void CopterConnection::infoToByteArray(char *&bit_data, size_t *msglen,
T data) {
// Determine which kind of element is in the array, will change in the final code
char typeID = -1;
*msglen = sizeof(data);
*msglen += 1; // take in account of typeID
// Create the pointer to the byte representation of the struct
bit_data = new char[*msglen];
// copy the information from the struct into the byte array
memcpy(bit_data, &data+1, *msglen-1);
bit_data[1] = typeID;
}
But this is not working. I guess I use the memcpy wrong. I want to copy the unkown struct T into the positions bit_data[1] to bit_data[*end*]. What is the best way to achieve this?
One possible problem and one definitive problem:
The possible problem is that array indexing starts at zero. So you should copy to bit_data + 1 to skip over the first byte, and then of course use bit_data[0] to set the type id.
The definitive problem is that &data + 1 is equal to (&data)[1], and that will be out of bounds and lead to undefined behavior. You should just copy from &data.
Putting it all together the last to lines should be
memcpy(bit_data + 1, &data, *msglen-1);
bit_data[0] = typeID;
There is another possible problem, which depends on what you're doing with the data in bit_data and what T is. If T is not a POD type then you simply can not expect a bitwise copy (what memcpy does) to work very well.
Also if T is a class or structure with members that are pointers then you can't save those to disk or transfer to another computer or even to another process on the same computer.
There are a few bugs in there, in addition to the fact you are messing around with new.
The memcpy line itself you use &data + 1 as the source which here will be undefined behaviour. It will add sizeof(data) bytes to the address which is copied so in the stack somewhere and whilst "one past the end" is a valid pointer so this address is valid in pointer arithmetic, nothing you read from it will be, nor anything after it.
bit_data[1] is the 2nd character in your buffer.
This is a fairly basic question and I am pretty sure I know the answer, but seeing as the consequence for being wrong is a segfault I figure I should ask. I have been using strlen() and the new char[] operator in the following way for quite some time now and just noticed something that threw up a red flag:
void genericCopy(char *somestring, char *someOtherString) {
someOtherString = new char[strlen(somestring)];
strcpy(someOtherString,somestring);
}
My question is, seeing as a string should be null terminated, should I be doing this as such:
void genericCopy(char *somestring, char *someOtherString) {
someOtherString = new char[strlen(somestring)+1];
strcpy(someOtherString,somestring);
someOtherString[strlen(someOtherString)] = '\0';
}
So far I have never had a problem with the first method, but that doesn't mean I'm doing it right. Since the length being return by strlen()is the number of characters in the string without the null terminator so new isn't reserving space for '/0'... At least I don't think it is.
First of all, you should know that this function of yours is pointless to write, just use strdup (if available on your system).
But yes, you need an additional byte to store the \0, so always do something like new char[strlen(somestring)+1];. However, there is no need to manually add the \0; strcpy already does this.
You should use something like Valgrind to discover this and similar bugs in your code.
There is however an additional problem in your code; your code will always leak someOtherString; it will not be returned to where you called it from. You either need to change your method to something like:
char *genericCopy(char *something) {
char *copy = new char[strlen(somestring)+1];
strcpy(copy,somestring);
return copy;
}
and then get the copy as follows:
copy = genericCopy(something);
Or you need to change your method to something like:
void genericCopy(char *something, char **copy) {
*copy = new char[strlen(somestring)+1];
strcpy(*copy,somestring);
}
and call it as:
genericCopy(something, ©);
If you'll be using C++ you could also just change the method prototype to:
void genericCopy(char* somestring, char*& someOtherString)
and call it as:
genericCopy(something, copy);
Then someOtherString will be passed as a reference, and the new value you allocate to it will propagate outside of your method.
Yes, your suspicion is correct. You should be allocating an additional character, and making sure the copied string is null-terminated. (strcpy() itself will do this, but when someone advises to you that you switch to strncpy(), as they no doubt will (it's safer!) you'll need to be extra careful, because it is NOT guaranteed to copy the '/0'.)
If you're already using C++, though, you may be well-advised to switch to using std::string. It's often an easier, less error-prone method of manipulating character arrays.
However, here's the further problem that you need to address. You are assigning your new character array to a COPY of someOtherString. You need to make some changes:
void genericCopy(char *somestring, char **someOtherString) {
*someOtherString = new char[strlen(somestring)+1];
strcpy(*someOtherString,somestring);
(*someOtherString)[strlen(somestring)] = '\0';
}
This way you will get back the new character buffer outside your function call.
Could you please explain why, in order to convert a char array like this:
char strarr[5] = {65,83,67,73,73}; //ASCII
Into LPCSTR to be accepted by GetModuleHandleA() and GetProcAddress(), I have to first append 0 to the end ?
i.e. I have:
char strarr[6] = {65,83,67,73,73,0};
And only then convert as (LPCSTR)&strarr.
For some reason I don't get the first one works only sometimes (i.e. if I do not add 0 at the end), while if I do add zero at the end - this work all the time. Why do I have to add zero?
Oh and a side question - why in C++ do I have to explicitly state the size of array in [], when I am initializing it with elements right away? (If I don't state the size, then it does not work)
Thanks.
Those functions expect NULL terminated strings.
Since you only give them a pointer to a char array, they can't possibily know its size, hence the need for a particular value (the terminating NULL character) to indicate the end of the string.
I wrote the following code:
char *pch=new char[12];
char *f=new char[42];
char *lab=new char[20];
char *mne=new char[10];
char *add=new char[10];
If initially I want these arrays to be null, can't I do this:
*lab="\0";
*mne="\0";
and so on.....
And after that if I want to add some cstring to an empty array can't I check:
if(strcmp(lab,"\0")==0)
//then add cstring by *lab="cstring";
And if I can't do any of these things, please tell me the right way to do it...
In C++11, an easy way to initialize arrays is by using brace-initializers:
char * p = new char[100] { 0 };
The reasoning here is that all the missing array elements will be zero-initialized. You can also use explicit value-initialization (I think that's even allowed in C++98/03), which is zero-initalization for the primitive types:
char * q = new char[110]();
First of all, as DeadMG says, the correct way of doing this is using std:string:
std::string lab; // empty initially, no further initialization needed
if (lab.size() == 0) // string empty, note, very fast, no character comparison
lab += "cstring"; // or even lab = "cstring", as lab is empty
Also, in your code, if you insist in using C strings, after the initialization, the correct checking for the empty string would be
if (*lab == '\0')
First of all, I agree with everybody else to use a std::string instead of character arrays the vast majority of the time. Link for help is here: C++ Strings Library
Now to directly answer your question as well:
*lab="\0";
*mne="\0";
and so on.....
This is wrong. Assuming your compiler doesn't give you an error, you're not assigning the "null terminator" to those arrays, you're trying to assign the pointer value of where the "\0" string is to the first few memory locations where the char* is pointing to! Remember, your variables are pointers, not strings. If you're trying to just put a null-character at the beginning, so that strlen or other C-string functions see an "empty" string, do this: *lab='\0'; The difference is that with single-ticks, it denotes the character \0 whereas with double, it's a string literal, which returns a pointer to the first element. I hope that made sense.
Now for your second, again, you can't just "assign" like that to C-style strings. You need to put each character into the array and terminate it correctly. Usually the easiest way is with sprintf:
sprintf(lab, "%s", "mystring");
This may not make much sense, especially as I'm not dereferencing the pointer, but I'll walk you through it. The first argument says to sprintf "output your characters to where this pointer is pointing." So it needs the raw pointer. The second is a format string, like printf uses. So I'm telling it to use the first argument as a string. And the 3rd is what I want in there, a pointer to another string. This example would also work with sprintf(lab, "mystring") as well.
If you want to get into C-style string processing, you need to read some examples. I'm afraid I don't even know where to look on the 'net for good examples of that, but I wish you good luck. I'd highly recommend that you check out the C++ strings library though, and the basic_string<> type there. That's typedef'd to just std::string, which is what you should use.