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.
Related
I am trying to convert an integer to a char pointer as shown below. The data results are different. I am not sure what is going wrong. Please help me in correcting the code.
int main(){
char *key1 = "/introduction";
std::ostringstream str1;
str1<< 10;
std::string data=str1.str();
std::cout <<"The data value="<<data<<std::endl; // The data value= 10
char *intro= new char[data.length()+1];
strcpy(intro, data.c_str());
std::cout <<"The data value="<<*intro <<std::endl; // The data value=1
return 0;
}
I am not sure why two data value are printed different i.e, 10 and 1.
In C++, when trying to print all the contents of a char * with cout, you should pass the pointer, i.e. cout << intro << endl.
What you've done here is dereferenced the char *, so cout << *intro << endl is equivalent to cout << intro[0] << endl, which is equivalent to printing the first character, 1.
I defined an struct based on bytes, with size of 3 bytes. (1 packetID and 2 packetSize) I checked the size with sizeof function, and it works well:
#pragma pack(1)
typedef struct ENVIRONMENT_STRUCT{
unsigned char packetID[1];
unsigned char packetSize[2];
}
I created a variable and reserved memory like this:
ENVIRONMENT_STRUCT * environment_struct = new ENVIRONMENT_STRUCT();
For now I want to initialize environment_struct.
The problem is about I am trying to initialize this struct by attribute, just like this:
*environment_struct->packetSize = 100;
But when I checked this value, using:
std::cout << "Packet Size: " << environment_struct->packetSize << endl;
Result: Packet Size: d
Expected result: Packet Size: 100
If i will work with numbers, Should I define the struct using csdint library? For example, u_int8 and this type of variable.
When you do
ENVIRONMENT_STRUCT * environment_struct = new ENVIRONMENT_STRUCT();
you initialize packetSize to be {0, 0}. Then
*environment_struct->packetSize = 100;
turns the array into {100, 0}. Since the array is a character array when you send it to cout with
std::cout << "Packet Size: " << environment_struct->packetSize << endl;
it treats it as a c-string and prints out the string contents. Since you see d that means your system is using ascii as the character 'd' has an integer representation of 100. To see the 100 you need to cast it to an int like
std::cout << "Packet Size: " << static_cast<int>(*environment_struct->packetSize) << endl;
Do note that since packetSize is an array of two chars you can't actually assign a single value that takes up that whole space. If you want this then you need to use fixed width types like
typedef struct ENVIRONMENT_STRUCT{
uint8_t packetID; // unsigned integer that is exactly 8 bits wide. Will be a compiler error if it does not exist
uint16_t packetSize; // unsigned integer that is exactly 16 bits wide. Will be a compiler error if it does not exist
};
int main()
{
ENVIRONMENT_STRUCT * environment_struct = new ENVIRONMENT_STRUCT();
environment_struct->packetSize = 100;
std::cout << "Packet Size: " << environment_struct->packetSize << std::endl;
}
Let's first consider what *environment_struct->packetSize = 100; does. It sets the first byte of ENVIRONMENT_STRUCT::packetSize to 100. A more conventional syntax to do this is: environment_struct->packetSize[0] = 100.
There's really no way to initialize the struct in a way for the expression std::cout << environment_struct->packetSize to result in the output of 100. Let us consider what that does. environment_struct->packetSize is an array, which in this case decays to a pointer to first element. Character pointers inserted into character streams are interpreted as null terminated character strings. Luckily, you had valueinitialized the second byte of environment_struct->packetSize, so your array is indeed null terminated. The value of the first byte is interpreted as an encoded character. On your system encoding, it happens that d character is encoded as value 100.
If you wish to print the numeric value of the first byte of environment_struct->packetSize, which you had set to 100, you can use:
std::cout << "Packet Size: " << (int)environment_struct->packetSize[0] << endl;
You get this result as you tries to print a character symbol not an integer.
To fix it just cast the value or declare it as integer depending on your needs.
Cast example:
std::cout << "Packet Size: " << static_cast<int>(*environment_struct->packetSize) << std::endl;
As packetSize is declared as char-type, it's being output as a character. (ASCII code of character 'd' is 100...)
Try casting it to an integer-type:
std::cout << "Packet Size: " << (int)environment_struct->packetSize << endl;
Alternatively, since you appear to want to store the number as a 2-byte type, you could avoid such casting and simply declare packetSize as unsigned short. This will be interpreted by cout as an integer-type.
I'm a student at university. I work mostly with Java, C++ is very new to me, so I probably make many silly mistakes and I have upcoming exams to cope with. Don't be too harsh with me.
Note: I can NOT use C++ std::string because I need to work with C-strings due to university tasks!
Referring to my studies and the question I asked about pointers and const arguments (which you find here) I tried messing around with memory management but it seems it has no effect, or I just misunderstood some aspects about sizeof or actual sizes of certain elements.
This is my class Person:
Person.cpp
using namespace std;
Person::Person()
{
Person::name = new (char[64]);
Person::adress = new (char[64]);
Person::phone = new (char[64]);
cout << "standard constructor called; object created, allocated " << sizeof(name) << "+" << sizeof(adress) << "+" << sizeof(phone) << "bytes" << endl;
}
Person::Person(const char *name, const char *adress , const char *phone)
{
Person::name = new (char[strlen(name)]);
Person::adress = new (char[strlen(adress)]);
Person::phone = new (char[strlen(phone)]);
setName(name);
setAdress(adress);
setPhone(phone);
cout << "general constructor called; object created, allocated " << sizeof(this->name) << "+" << sizeof(this->adress) << "+" << sizeof(this->phone) << "bytes" << endl;
};
Person::Person(Person const &other)
{
Person::name = new (char[strlen(other.getName())]);
Person::adress = new (char[strlen(other.getAdress())]);
Person::phone = new (char[strlen(other.getPhone())]);
setName(other.getName());
setAdress(other.getAdress());
setPhone(other.getPhone());
cout << "copy constructor called; object created, allocated " << sizeof(name) << "+" << sizeof(adress) << "+" << sizeof(phone) << "bytes" << endl;
};
Person::~Person()
{
delete [] name;
delete [] adress;
delete [] phone;
cout << "destructor called; object removed" << endl;
};
I tried to spare memory with creating a C-string with a string length of the given parameters.
Thinking that a C-string is a char array, sparing chars would result in sparing memory, e.g. a C-string of "John" takes up less memory than a C-string of "Jonathan".
So now I'm not sure if I just got the wrong concept of C-strings or char arrays, or my implementation is just faulty.
In my main I create the following objects:
int main()
{
Person t;
t.printPerson();
cout << "size of t: " << sizeof(t) << endl;
Person p("John", "some street", "0736182");
p.printPerson();
cout << "size of p: " << sizeof(p) << endl;
Person x(p);
x.printPerson();
cout << "size of x: " << sizeof(x) << endl;
Person y("Jonathan", "Lancaster Ave 53", "3584695364");
y.printPerson();
cout << "size of y: " << sizeof(y) << endl;
cin.get();
};
But I alwas get a size of 24 per object, so 8 for each member variable. Why is that?
Thanks in advance.
I think you are expecting the sizeof operator to behave differently than it actually does. Let's take this code, for example:
const char* str = new char[137];
Here, if you write sizeof(str) you'll probably either get 4 or 8, depending on your system, because sizeof(str) measures the number of bytes of the pointer str itself rather than the number of bytes in the array pointed at by str. So, on a 32-bit system, you'd probably get 4, and on a 64-bit system you'd probably get 8, independently of how many characters you allocated.
Unfortunately, C++ doesn't have a way for you to get the number of characters or the memory used up by a dynamically allocated array. You just have to track that yourself.
Similarly, in your main function, when you write sizeof(p), you're measuring the number of bytes used by the object p, not the total number of bytes used by p and the arrays it points at. You'll always get back the same value for sizeof(p) regardless of what strings it points at.
If you're planning on working with strings in C++, I strongly recommend using std::string over raw C-style strings. They're much easier to use, they remember their length (so it's harder to mix up strlen and sizeof), and if you have a class holding s bunch of std::strings you don't need a copy constructor or assignment operator to handle the logic to shuffle them around. That would significantly clean up your code and eliminate most of the memory errors in it.
sizeof gives you a number of bytes which c/c++ need to keep the object in memory. In you r case (though you have not shown it) it looks like name, address, and phone are pointers to char:
struct Person {
char *name, *address, *phone;
}
a pointer is a variable which keeps an address of another object. So, depending on the underlying system it could occupy 32 bits (4 bytes) or 64 bite (8 bytes) (or some other number). In this case the sizeof struct person will be for 64-bit system -- 24. (3 pointers per 8 bytes each). This corresponds to your results.
The sizeof provides you with a shallow size calculation. Your strings are pointed by the those pointers and their lengths are not included. So, potentially you need to create a member function which will calculate those for you, i.e.
struct Person {
char *name, *address, *phone;
int getSize() {
return strlen(name) + strlen(address) + strlen(phone);
}
};
And as mentioned in the comments before, every char *string in c/c++ must have a termination character ('\0') which tells the program where the string ends. So, if you allocate space for a string, you should provide space for it as well (+ 1 to the length). And you have to make sure that this character is written as '\0'. if you use library functions to copy strings, they will take car of it, otherwise you need to do it manually.
void setName(const char *n) {
name = new char[strlen(n) + 1]; // includes needed '0', if exists in 'n'
strcpy(name, n); // copies the string and adds `\0` to the end
}
If you use the loop to copy chars instead of strcpy you would need to add it manually:
name[strlen(n)] = 0;
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.
how can i print a char array such i initialize and then concatenate to another char array? Please see code below
int main () {
char dest[1020];
char source[7]="baby";
cout <<"source: " <<source <<endl;
cout <<"return value: "<<strcat(dest, source) <<endl;
cout << "pointer pass: "<<dest <<endl;
return 0;
}
this is the output
source: baby
return value: v����baby
pointer pass: v����baby
basically i would like to see the output print
source: baby
return value: baby
pointer pass: baby
You haven't initialized dest
char dest[1020] = ""; //should fix it
You were just lucky that it so happened that the 6th (random) value in dest was 0. If it was the 1000th character, your return value would be much longer. If it were greater than 1024 then you'd get undefined behavior.
Strings as char arrays must be delimited with 0. Otherwise there's no telling where they end. You could alternatively say that the string ends at its zeroth character by explicitly setting it to 0;
char dest[1020];
dest[0] = 0;
Or you could initialize your whole array with 0's
char dest[1024] = {};
And since your question is tagged C++ I cannot but note that in C++ we use std::strings which save you from a lot of headache. Operator + can be used to concatenate two std::strings
Don't use char[]. If you write:
std::string dest;
std::string source( "baby" )
// ...
dest += source;
, you'll have no problems. (In fact, your problem is due to the fact
that strcat requires a '\0' terminated string as its first argument,
and you're giving it random data. Which is undefined behavior.)
your dest array isn't initialized. so strcat tries to append source to the end of dest wich is determined by a trailing '\0' character, but it's undefined where an uninitialized array might end... (if it does at all...)
so you end up printing more or less random characters until accidentially a '\0' character occurs...
Try this
#include <iostream>
using namespace std;
int main()
{
char dest[1020];
memset (dest, 0, sizeof(dest));
char source[7] = "baby";
cout << "Source: " << source << endl;
cout << "return value: " << strcat_s(dest, source) << endl;
cout << "pointer pass: " << dest << endl;
getchar();
return 0;
}
Did using VS 2010 Express.
clear memory using memset as soon as you declare dest, it's more secure. Also if you are using VC++, use strcat_s() instead of strcat().