Using memcpy trying to copy one struct into a char[] buffer - c++

#define ECHOMAX 100
struct tDataPacket
{
int iPacket_number;
char sData[ECHOMAX];
};
int main () {
tDataPacket packet;
packet.iPacket_number=10;
strcpy(packet.sData,"Hello world");
char buffer[sizeof(tDataPacket)];
memcpy(buffer,&packet.iPacket_number,sizeof(int));
memcpy(buffer+sizeof(int),packet.sData,ECHOMAX);
std::cout<<"Buffer = "<<buffer<<"END";
return 0;
}
In the above code I am trying to pack my structure in a char[] buffer so that I can send it to a UDP socket. But the output of the program is "" string. So nothing is getting copied to 'buffer'. Am I missing anything??

When you copy the int, at least one of the first "n" characters of the buffer will be zero (where "n" is the size of an int on your platform). For example for a 4-byte int:
x00 x00 x00 x0a or x0a x00 x00 x00
Depending on the endianness of your processor.
Printing out the zero will have the effect of terminating the output string.

You have no code to sensibly print the contents of the buffer, so you are expecting this to work by magic. The stream's operator << function expects a pointer to a C-style string, which the buffer isn't.

It's "" because int iPacket_number is probably laid out in memory as:
0x00 0x00 0x00 0x0a
which is an empty string (nul-terminator in the first character).
Firstly you probably want some sort of marshalling so that the on-the-wire representation is well established and portable (think endian differences between platforms).
Secondly you shouldn't need to "print" the resulting string; it makes no sense.
Thirdly you want unsigned char, not (signed) char.

You can't print an integer as text, because it's not text.

You will need to do a loop (or something like that) to print the actual contents of the buffer:
std::cout << "Buffer=";
for(size_t i = 0; i < sizeof(tDataPacket); i++)
{
std::cout << hex << (unsigned int)buffer[i] << " ";
if ((i & 0xf) == 0xf) std::cout << endl; // Newline every 16.
}
std::cout << "END" << endl;

You can do this but it's not really relevant to display binary data like that:
std::cout<<"Buffer = "; for each (auto c in buffer)
{
std::cout<< c;
}
std::cout <<"END";

Related

Read into std::string using scanf

As the title said, I'm curious if there is a way to read a C++ string with scanf.
I know that I can read each char and insert it in the deserved string, but I'd want something like:
string a;
scanf("%SOMETHING", &a);
gets() also doesn't work.
Thanks in advance!
this can work
char tmp[101];
scanf("%100s", tmp);
string a = tmp;
There is no situation under which gets() is to be used! It is always wrong to use gets() and it is removed from C11 and being removed from C++14.
scanf() doens't support any C++ classes. However, you can store the result from scanf() into a std::string:
Editor's note: The following code is wrong, as explained in the comments. See the answers by Patato, tom, and Daniel Trugman for correct approaches.
std::string str(100, ' ');
if (1 == scanf("%*s", &str[0], str.size())) {
// ...
}
I'm not entirely sure about the way to specify that buffer length in scanf() and in which order the parameters go (there is a chance that the parameters &str[0] and str.size() need to be reversed and I may be missing a . in the format string). Note that the resulting std::string will contain a terminating null character and it won't have changed its size.
Of course, I would just use if (std::cin >> str) { ... } but that's a different question.
Problem explained:
You CAN populate the underlying buffer of an std::string using scanf, but(!) the managed std::string object will NOT be aware of the change.
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.reserve(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: '" << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
Outputs:
Managed string: (size = 0)
Underlying buffer: Daniel (size = 6)
So, what happened here?
The object std::string is not aware of changes not performed through the exported, official, API.
When we write to the object through the underlying buffer, the data changes, but the string object is not aware of that.
If we were to replace the original call: token.reseve(64) with token.resize(64), a call that changes the size of the managed string, the results would've been different:
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.resize(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: " << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
Outputs:
Managed string: Daniel (size = 64)
Underlying buffer: Daniel (size = 6)
Once again, the result is sub-optimal. The output is correct, but the size isn't.
Solution:
If you really want to make do this, follow these steps:
Call resize to make sure your buffer is big enough. Use a #define for the maximal length (see step 2 to understand why):
std::string buffer;
buffer.resize(MAX_TOKEN_LENGTH);
Use scanf while limiting the size of the scanned string using "width modifiers" and check the return value (return value is the number of tokens scanned):
#define XSTR(__x) STR(__x)
#define STR(__x) #x
...
int rv = scanf("%" XSTR(MAX_TOKEN_LENGTH) "s", &buffer[0]);
Reset the managed string size to the actual size in a safe manner:
buffer.resize(strnlen(buffer.data(), MAX_TOKEN_LENGTH));
The below snippet works
string s(100, '\0');
scanf("%s", s.c_str());
Here a version without limit of length (in case of the length of the input is unknown).
std::string read_string() {
std::string s; unsigned int uc; int c;
// ASCII code of space is 32, and all code less or equal than 32 are invisible.
// For EOF, a negative, will be large than 32 after unsigned conversion
while ((uc = (unsigned int)getchar()) <= 32u);
if (uc < 256u) s.push_back((char)uc);
while ((c = getchar()) > 32) s.push_back((char)c);
return s;
}
For performance consideration, getchar is definitely faster than scanf, and std::string::reserve could pre-allocate buffers to prevent frequent reallocation.
You can construct an std::string of an appropriate size and read into its underlying character storage:
std::string str(100, ' ');
scanf("%100s", &str[0]);
str.resize(strlen(str.c_str()));
The call to str.resize() is critical, otherwise the length of the std::string object will not be updated. Thanks to Daniel Trugman for pointing this out.
(There is no off-by-one error with the size reserved for the string versus the width passed to scanf, because since C++11 it is guaranteed that the character data of std::string is followed by a null terminator so there is room for size+1 characters.)
int n=15; // you are going to scan no more than n symbols
std::string str(n+1); //you can't scan more than string contains minus 1
scanf("%s",str.begin()); // scanf only changes content of string like it's array
str=str.c_str() //make string normal, you'll have lots of problems without this string

The sizeof several casts

Why does the function sizeof not return the same size when its getting used on the struct itself?
I need to cast it because of a winsock program that im working on.
Thanks for any help, true.
#include <iostream>
#include <string>
using namespace std;
struct stringstruct
{
string s1;
string s2;
};
int main()
{
stringstruct ss = {"123","abc"};
char *NX = (char*)&ss;
cout << sizeof(NX) << endl << sizeof(*NX) << endl;
cout << sizeof(&ss) << endl << sizeof(ss) << endl;
getchar();
return 0;
}
the example above outputs
4
1
4
64
sizeof will tell you the size of the given expression's type. In both the sizeof(NX) and sizeof(&ss), the result is 4 because pointers on your machine take up 4 bytes. For sizeof(*NX), you are dereferencing a char*, which gives you a char, and a char takes up 1 byte (and always does), so you get the output 1. When you do sizeof(ss), ss is a stringstruct, so you get the size of a stringstruct, which appears to be 64 bytes.
stringstruct ss = {"123","abc"};
char *NX = (char*)&ss;
cout << sizeof(NX) << endl << sizeof(*NX) << endl;
cout << sizeof(&ss) << endl << sizeof(ss) << endl;
I'm pretty sure that any of these casts are pretty meaningless. NX will point at the beginning of your struct. Inside the struct are two objects of type string, which in turn have pointers pointing to the data they were initialized with "123" and "abc" respectively. sizeof(*NX) is just that - size of a char, and sizeof(NX) is indeed the size of a pointer. sizeof(ss) is the size of your two string members (and any padding added by the compiler) - and sizeof(&ss) is the size of a pointer to a stringstruct.
Now, I expect what you REALLY want is a way to send your data, "123" and "abc" as two separate strings over a network. None of the above will help you do that, since even if sizeof(ss) gives you the size of the data structure you want to send, the string values are not within that structure [1]. What you really need is something calls serialization - something that writes out your strings as separate elements as text/string.
Something like this would work:
struct stringstruct {
string s1;
string s2;
string to_string()
}
string stringstruct::to_string()
{
string res = s1 + " " + s2;
return res;
}
Then use to_string like this:
string temp = ss.to_string();
const char *to_send = temp.c_str();
int send_len = temp.length();
... send the string `to_send` with number of bytes `send_len`.
[1] There is an optimization where std::string is actually storing short strings within the actual class itself. But given a sufficiently long strong, it won't do that.
A pointer is of size 4(in your case seems to be 32 bit) no matter what it points. Size of the object itself on the other hand returns the real number of bytes that an object of that structure takes.

std::copy : copy is happening only for 1 byte and not for specified length

Please see the code snippet below :
#include <iostream>
using namespace std;
int main()
{
uint32_t len, x;
char abc[] = "12345678";
uint8_t *ptr = (uint8_t *)abc;
copy(ptr, ptr + 4, reinterpret_cast<uint32_t*>(&len));
cout << " len: " << len << endl;
}
The output is 49! I would want the output to be 1234. Am I missing something
Your target is a “container” of length 1 (namely, a single object, len).
You are copying four subsequent byte values into this container, which of course fails – in particular, it causes an overflow since the target only has space for a single element.
Other errors in your code (not an exhaustive list):
You are confusing character codes and their string representation
You are performing redundant casts
The first point in particular is relevant since what you actually want to do is parse the number encoded in the first four characters of the string as a decimal number. But what you actually do is copy its character codes.
To parse a number in C++, use as std::stringstream or, since C++11, std::stoi
std:copy doesn't work as you're expecting. It copies the source 'element-wise' to the destination. So it copies the first uint8 (= char '1' == 0x49 in hex) to 'len', and then proceeds to trample on three random uint32 values following on in memory.
This this instead to see what's actually happening.
#include <iostream>
using namespace std;
int main()
{
uint32_t len[4];
char abc[] = "12345678";
copy(abc, &abc[4], &len[0]);
cout << " len: " << len[0] << " " <<len[1] << " " << len[2] << " " << len[3] << endl;
}
First of all, std::copy does roughly this:
template <typename InputItr, typename OutputItr>
void copy(InputItr begin, InputItr end, OutputItr obegin)
{
while (begin != end)
*obegin++ = *begin++;
}
Your output iterator is uint32_t*, which would actually cause you to overwrite 4 32-bit words! (buffer overflow). You are seeing 49 because the first character that is copied ('1') has the ASCII value 49.

Printing hexadecimal values to console in C++

#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
char array[10];
for(int i = 0; i<10;i++)
{
array[i] = 'a' + i;
}
char* test = array;
printf("%x\n", test);
cout << hex << test << endl;
}
The output for this is:
bffff94e
abcdefghijN???
Why is it not printing the same thing?
cout << hex << test << endl;
It prints the string, not the address. It is because there is an overload of operator<< which takes char const* as argument and this overload treats the argument as string.
If you want to print the address, cast the argument to void* so that other overload of operator<< will be invoked which will print the address.
cout << hex << static_cast<void*>(test) << endl;
will print the address, in hexadecimal format.
Note that hex stream-manipulator is not needed here, as the address will be printed in hexadecimal format anway. So
cout << static_cast<void*>(test) << endl;
is enough.
Because your program has undefined behavior. And because you ask it to
print different things.
Your invocation of printf is illegal, and results in undefined
behavior (and is a good example of why you should never use printf).
Your format specifier says to extract an unsigned int from the
argument list, and output that in hexadecimal. Passing it anything but
an unsigned int is undefined behavior. As it happens, given the way
varargs are generally implemented, if you're on a machine where
unsigneds and pointers have the same size, you'll probably output the
value of the pointer, treating its bits as if it were an unsigned.
Other behaviors are certainly possible, however. (If I'm not mistaken,
g++ will warn about this construct; it's also possible that on some
platforms, it will crash.)
In the case of std::cout, you're passig it a char*. By definition,
the char* is treated as a '\0' string, not as a pointer (and
certainly not as an unsigned int). And again, you have undefined
behavior, since your char* doesn't point to a '\0' terminated string;
you never put a '\0' at the end. (This probably explains the "N???"
you see at the end of your output. But again, undefined behavior is,
well, undefined. The code could just as easily have crashed.)
Finally, you're using both printf and std::cout; the results are not
really specified unless you do a flush of the stream between the two.
(In practice, if you're outputting to an interactive device, the flush
should occur when you output the '\n' character. If you redirect the
output to a file, however, you're likely to get something different.)
It's not clear what you want. If you want to output the address of
array, it would be:
printf( "%p\n", test );
std::cout << static_cast<void*>( test ) << std::endl;
If you want to output the string you've generated, then append a '\0' to
the end of it (without overflowing the buffer), and then:
printf( "%s\n", test );
std::cout << test << std::endl;
I'm not sure what you're trying to make "hex"; there is no such thing as
a hex representation of a string, and the representation of a pointer is
implementation defined, and not required to take into account any
formatting parameters in iostream. (Typically, on most modern machines,
it will be hex. But I've worked on more than a few where it would be
octal, and at least one where it wouldn't be just a number, regardless
of the base.) If you want a hex dump of array, you'll have to loop,
outputting each value as an unsigned in hex:
for ( int i = 0; i < 10; ++ i ) {
printf( "%x", static_cast<unsigned char>( test[i] ) );
}
printf( "\n" );
std::cout.setf( std::ios_base::hex, std::ios::basefield );
for ( int i = 0; i < 10; ++ i ) {
std::cout << static_cast<unsigned>( static_cast<unsigned char>( test[i] ) );
}
std::cout.setf( std::ios_base::dec, std::ios::basefield );
std::cout << std::endl;
Finally: a word about the casts: plain char may be either signed or
unsigned; if it is signed, converting it to an int or an
unsigned, might produce either a negative value (int) or a very
large positive value (unsigned). Thus, the first conversion to
unsigned char, which guarantees a result in the range [0, UINT_MAX].
Second, of course, we have to convert the unsigned char to unsigned:
in the case of printf, because we would otherwise have undefined
behavior, but the conversion is implicit, since passing an unsigned
char as a vararg automatically promotes it to unsigned; and
in the case std::cout, because the rules are that any character
type be output as a character, not as a numerical value (and since the
type is used here in function overload resolution, and is not being
passed to a vararg or an unsigned, there is no implicit conversion).
test itself is a pointer, i.e. it stores an address. Your printf statement prints the hexadecimal value of that address.
The cout << statement then prints the entire string, because the std::hex manipulator does not affect the way strings are printed. It only affects the way integers are printed.
What you can do is
Loop through the characters of the array
Convert each to an integer and print using the std::hex manipulator
That would look like this:
for (int i = 0 ; i < 10 ; ++i)
std::cout << std::hex << static_cast<int>(array[i]) << '\n';
cout << HEX <<
can't be used to a char* to print a hex char string,
but you can use it for int ,double,float,etc.
And, as you second print, why the string has some garbled strings is that you haven't gived
a '\n' to the string which means the end of string

C++ File Operations

As part of an assignment, I need to read data from a binary file which consists of int, char datatypes of data. This binary file is divided into records 96 bytes each. I am trying to reading these 96 bytes into a char buffer and then trying to split them according to info I have. But I am getting nothing when trying to get int values from the buffer. Can you help me in this?
#include<iostream>
#include<fstream>
#include<cstdio>
using namespace std;
int main()
{
char buffer[100];
char *p;
char temp[10];
int val;
fstream ifs,ofs;
ifs.open("write.bin",ios::binary);
if(ifs.read(buffer,96))
{
cout << "READ" << endl;
}
p = buffer;
memcpy(temp,buffer,4);
cout << temp << endl;
val = atoi(temp);
cout << val << endl;
}
I used strncpy also in place of memcpy.
The output is 0 for val and blank for temp.
atoi transforms strings (char arrays) into integers. So something like "42" would return the integer 42. The way your question is written, it sounds like the integers are simply stored as binary in the textfile.
A simple cast of the buffer pointer to the desired type plus a dereference should do:
/* read 96 bytes into char array buffer */
uint32_t your_number = *(uint32_t*)buffer;
cout << your_number << endl;
If you want to use memcpy, there's no need to copy to a char array, you can copy directly to an integer address:
uint32_t your_number;
memcpy(&your_number, buffer, 4);
cout << your_number << endl;
With plain C (not C++) this would be:
uint32_t your_number;
FILE *f = fopen("write.bin", "r");
fread(&your_number, sizeof(uint32_t), 1, f); /* uint32's size is 4 bytes */
fclose(f);
printf("%d\n", your_number);
I chose uint32_t as a data type, because it is guaranteed to have 32 bits/4 bytes – int might, on some platforms/compilers, be of different size.
Unlike C-style functions, read does not return number or bytes read, instead, it returns istream&. So to check the result, call ifs.gcount() after ifs.read().