I have this program that reads data from a serial port. For each line, I'm trying to concatenate the current time with the line of data. For some reason, it crashes when around the second print (it seems like at the end of the brackets?). The weird part is, that if I comment the print out, it'll still crash
char * cdata;
{
if( BINARY_ASCII == 1 ) //right now this is just set to 0, please ignore
{
cdata = convertBSTRToByteArray(data , numChars);
}
else
{
cdata = convertBSTRToString(data);
//prints the original output
cout << "before timestamp concat is: " << cdata << "\n";
//this is supposed to concatenate each output line with the associated time
std::stringstream ss;
ss << currentDateTime() << "," << cdata;
std::string s = ss.str();
std::strcpy(cdata,s.c_str());
cout << "after timestamp concat is: " << cdata << "\n"; //around here it crashes
}
cout << "after the thing" << "\n"; //does not even get here
I thought that the char * data would be the issue, but I've tried initializing it like
char *cdata = 0;
and
char *cdata = new char [100];
to no change...
That makes me think that I did something wrong in the concatenation?
I think it's important to highlight the difference between arrays and pointers, here.
char * cdata;
This creates a pointer named cdata. It's uninitialized, so it contains some useless memory address. A pointer is just a memory address, which means it takes up 32 (or 64) bits, and that's it.
char *cdata = 0;
This creates a pointer named cdata, and initializes it to all zeros, which means it points to the 0th location in memory. This is usually used to indicate that you should not follow this pointer.
char *cdata = new char [100];
This creates a block (array) of 100 characters, but gives that array no name. Then it creates a pointer named cdata and sets it to the memory address of the unnamed 100-byte block. I.e.:
cdata [ 0x3Ad783B2 ] --------\
\
\
|
V
[ unnamed 100-byte block ]
The reason I'm stressing this distinction is that the next line obliterates it all:
cdata = convertBSTRToString(data);
That line sets cdata to point to whatever memory address is returned by convertBSTRToString. It does not matter what value cdata had before this line -- uninitialized, null, pointing to an unnamed block of memory -- now it is pointing to the block of memory created by convertBSTRToString.
Abusing more ASCII-art:
cdata [ 0x64ADB7C8 ] --------\
\
\
|
V
[ unknown size, created by convertBSTRToString ]
// hey, look over here! it still exists,
// but we just don't point to it anymore.
[ unnamed 100-byte block ]
Now that that's covered, here's why it matters. This line:
std::strcpy(cdata,s.c_str());
strcpy will take the data pointed to by the second parameter, and copy it, byte-by-byte, to the location pointed to by the first parameter. It does not pay attention to buffer size. It's a really stupid copy. No safety whatsoever - that's up to you to provide.
I'm not sure what you're trying to accomplish with this line anyway, because s holds the full string data you wanted to concatenate:
cout << "after timestamp concat is: " << s << "\n";
convertBSTRToString probably allocates a new buffer that's sized exactly right to hold the BSTR you passed in. That means you cannot expand its size.
In your code, you are trying to add currentDateTime()'s result into that buffer (in addition to its existing content). The data won't fit. Thus, bad things happen.
You would need to first allocate a buffer big enough to contain both the convertBSTRToString plus the currentDateTime then strcpy the convertBSTRToString and then strcat the currentDateTime. strcpy won't append, strcat does.
Related
I am new to c++ and am still figuring out file streams. I am trying to put a character array into a file that I will be viewing with a hex editor.
I have done different strings, but whenever I put in a null byte, the file ends.
ofstream stream;
char charArray[256];
for (int i = 0; i <= 255; i++)charArray[i] = i;
stream.open("C:\\testfile.myimg");
if (!stream.is_open()) exit(1);
stream << charArray << endl;
return 0;
I want to output bytes with ascending values, but if I start with the null byte, then c++ thinks the character array ends before it starts
Instead of:
stream << charArray << endl;
use:
stream.write(charArray, sizeof(charArray));
stream.write("\n", 1); // this is the newline part of std::endl
stream.flush(); // this is the flush part of std::endl
The first one assumes that you are sending a null-terminated string (because you're passing a char* - see the end of the answer why). That's why when the code encounters the very first char with value 0, which is '\0' (the null-terminator), it stops.
On the other hand, the second approach uses an unformatted output write, which will not care about the values inside charArray - it will take it (as a pointer to its first element) and write sizeof(charArray) bytes starting from that pointer to the stream. This is safe since it's guaranteed that sizeof(char) == 1, thus sizeof(charArray) will yield 256.
What you need to consider is array decaying. It will work in this case (the sizeof thing), but it will not work if you simply pass a decayed pointer to the array's first element. Read more here: what's array decaying?
With reference to the code below: After calling the function CheckSMS and passing the struct * DB1, the fields are updated according the the strtok call. This function reads and parses a text message, storing its contents into char* fields of the DB struct.
In the main loop, I have called Serial.println(DB1.last_order) before and after calling the CheckSMS function. If I have received a text, the order is printed appropriately in the main loop, however on the next call to CheckSMS, DB1.last_order is cleared, replaced with a \n or a NULL or something. I cannot figure out why DB1.last_order does not retain its value, and rather, it is overwritten with every call to CheckSMS. Thanks for any help.
Note - All text messages contain "CMT+", therefore writing to DB1 only happens when a text is received. Calling CheckSMS when no text is received should simply skip through.
int CheckSMS(Robot *DB1) {
int j = 0;
char response[100];
char *pch;
unsigned long previous;
memset(response, '\0', 100);
while(Serial2.available()>0){
response[j] = Serial2.read();
j++;
Serial.println("inc");
}
delay(100);
if (strstr(response, "CMT:") != NULL){
DB1->new_message = strtok(response, " ,");
DB1->last_phone = strtok(NULL, " ,");
pch = strtok(NULL, " ,");
DB1->last_date = strtok(NULL, " ,");
DB1->last_time = strtok(NULL, " ,\n");
DB1->last_order = strtok(NULL," ,\n");
new_message = 1;
}
else{
}
return 0;
}
The strtok function returns pointers to the string you're tokenizing, the local array response in your case. When the function returns the response array goes out of scope and disappears, leaving your structure with pointers to a string that no longer exists, and giving you undefined behavior.
You have a couple of solutions:
Allocate the string dynamically using malloc, but then you must save it in the structure so you can free it when you're done with the structure
Make the response array static, but then the next call to the function will have the same array leading the old data to be updated
Pass in a string to store the response and use that string, the string must have a lifetime at least as long as the structure and don't change contents. The string can of course be a member of the structure itself
The answer Joachim gave is correct, I just want to add that you could also change the Robot structure to contain char arrays (like this: char new_message[MAX_BUF_CHARS]; and so on). Be sure to have enough space in them. Then instead of assigning the pointers returned from strtok, copy the strings in there.
I need to write class which contains char pointer to text line and constructor which retrieves text line from the list of arguments, dynamically allocates memory and copies the text of the line to the component class.
Writed programm doesn't works correctly. Example Error.
What is wrong? Please help!
class A
{
char* text;
public:
A(char *line);
};
A::A(char *line) {
int length = strlen(line);
text = new char[length];
if (strlen(line) <= sizeof(text))
strcpy_s(text, length, line);
else
{
cout << text << endl;
cout << "Too long string" << endl;
}
}
int main()
{
A ob("aaaaaa");
system("PAUSE");
return 0;
}
The sizeof operator returns the size of the object (not the size of a string). So in this case
sizeof(text)
It returns the size of the object text. You declare text as
char* text;
So it returns the size of a char*. The exact size of this will depend on the system, but lets guess its 4. So any string that has a length greater than 4 will result in the output of:
Too long string
If we look at the string: "aaaaaa" is longer than 4 so you get the expected output.
I expect you are trying to check that the previous line succeded.
text = new char[length];
But in C++ the new will either work or throw an exception (causing program termination for this program). So either that line works or the program will exit. So there is no need to check the result of new (unlike C where you should check the result of malloc())
Also note: You should check the result of strcpy_s() as it will return an error on failure. Since you do not provide enough space in the destination it will indicate an error (you don't provide space for the null terminator).
I'm trying to split up data into little packets. I'm not exactly sure how this read method is suppose to work but I've given a buffer size of 512 to read from the file.
But instead of getting 512 i just get 5 in my first packet. Others vary from 0 to above 512 ( which shouldn't happen).
It's a zip file I'm trying to split up:
In text the first few bytes look like this
(de bucket like characters are actually 2 characters)
It seems to grab the first 5 bytes as it should but afterwards just stops and goes to the next read block.
Since it's a buffer of 512 everything after the first 5 bytes is garbage.
I'm using an ifstream. And the mode is set to Binary.
Any suggestions?
void FileProcessor::send()
{
//If no file is opened return
if(!_file.is_open()) return;
//Reset position to beginning
_file.seekg(0, ios::beg);
//Result buffer
char * buffer;
char * partBytes = new char[_bufferSize];
//Read the file and send it over the network
while (_file.read(partBytes, _bufferSize))
{
buffer = Packet::create(Packet::FILE,partBytes);
Packet *p = Packet::create(buffer);
//cout << strlen(partBytes);
//p->PrintHex(buffer,_bufferSize+Packet::HeaderSize);
//break;
cout << "Normal size : \t" << strlen(partBytes)<< "\tPacketSize: \t" << p->getLength()<<"\n";
//cout << strcmp(p->getData().c_str(),partBytes) << "\n";
writeToFile(p->getData().c_str(),p->getData().length());
delete p;
}
//Write final bytes if any
if(_file.gcount())
{
//writeToFile(partBytes, _file.gcount());
buffer = Packet::create(Packet::FILE,partBytes);
Packet *p = Packet::create(buffer);
writeToFile(p->getData().c_str(),p->getData().length());
//cout << p->getLength() << "\n";
delete p;
}
//cout<< *p << "\n";
delete [] partBytes;
}
Im just testing a direct read write right now.
Inside your loop, instead of assuming it always reads a full buffer of data, use gcount() to find how many it actually read, and transmit that many.
I feel obliged to add that this:
buffer = Packet::create(Packet::FILE,partBytes);
Packet *p = Packet::create(buffer);
looks quite strange to me. Not sure it's wrong, but it's not immediately obvious that it's right either (and if it is right, the design seems a bit odd).
I'd also skip the dynamic allocation and deletion:
char * partBytes = new char[_bufferSize];
// ...
delete [] partBytes;
and use a std::vector<char> instead.
I have a small school assignment. My output is not correct. Can you see if I'm doing anything wrong?
//1. Create a char pointer named cp
char *cp;
//2. Dynamically allocate a char and store its address in cp
char dynamicChar = 'A';
cp = &dynamicChar;
//3. Write the character 'x' into the char
*cp = 'x';
//4. Print out the value of the char using cout
cout << cp << endl;
The print out statement prints A## instead of just A. I'm not sure what I'm doing wrong.
Try
cout << *cp << endl;
You want to print the character, not the pointer to it. When you hand it the pointer, cout thinks you're telling it to print out a character array starting there.
Sadly, from its origins of the C programming language, char * (i.e. pointers to characters) are not treated as just a pointer to a type like int * (pointer to int) or float * (pointer to a float), but many library functions treat these as NUL-character terminated strings. By "string" we mean text.
Therefore, there are lots of library functions that treat char* as special case and treats them as a "nul-terminated string", meaning it's gonna treat that pointer as an ARRAY of (i.e. multiple contiguous) charactes, until it reaches a NUL character (i.e. numeric value 0, not the character '0' which has a numeric byte value of 48 or 0x30).
So, if in your code you have
char *sz = "123";
this will allocate 4 characters, the 3 you see plus the NUL character
Addr:0x00050014 0x31 // ASCII char '1'
Addr:0x00050015 0x32 // ASCII char '2'
Addr:0x00050016 0x33 // ASCII char '3'
Addr:0x00050017 0x00 // ASCII char nul
sz (a pointer to a character, representing an address) will have the value 0x00050014 (note that the starting address value is determined by your computer via multiple steps via the compiler, then the linker, then the loader, then possibly the progrma itself).
When you do
cout << sz << endl;
the program will interpret the pointer to a character as a pointer to a nul-terminated buffer of characters and dump the character string
123
to the output stream cout. It looks at the value at address 0x00050014 and sees if its NUL (i.e. 0), if not, it dumps out the character, then looks at the next address. If 0x00050015 is not a NUL, it dumps IT out. Then the value at 0x00050016, sees its not a NUL, dumps it out, then it gets to 0x00050017 and sees that it IS NUL, and does NOT dump it out, and stops looking at addresses and returns to YOUR code just after where you did the output of sz, specifically in this code it will return to the point where it will dump the endl (end of line) to cout;
You will eventually learn better ways to represent text than the old C-style char* mechanism, but for now, you just need to understand the legacy behavior that exists.
C++ (or, more specificaly, ostream in this case), will automatically treat a char* as a (C style) string. You need to explicitly cast it to the type you want, such as:
cout << (void*)cp << endl;
if you want the pointer value, or
cout << *cp << endl;
if you want the character itself (as your question seems to indicate).