I'm working on an Arduino project. I'm trying to pass a byte pointer to a function, and let that function calculate the size of the data that the pointer refers to. But when I let the pointer refer to a byte, sizeof() returns 2. I wrote the following snippet to try to debug:
byte b;
byte *byteptr;
byteptr = &b;
print("sizeof(b): ");
println(sizeof(b));
print("sizeof(*byteptr) pointing to byte: ");
println(sizeof(*byteptr));
print("sizeof(byteptr) pointing to byte: ");
println(sizeof(byteptr));
the printed result is:
sizeof(b): 1
sizeof(*byteptr) pointing to byte: 1
sizeof(byteptr) pointing to byte: 2
So the size of a byte is 1, but via the pointer it's 2??
It appears that on Arduino, pointers are 16 bit. I believe your confusion stems from what * means in this context.
sizeof(*byteptr) is equivalent to the sizeof(byte). The * does not indicate a pointer type, it indicates dereferencing the pointer stored in byteptr. Ergo, it is 1 byte, which you would expect from the type byte.
sizeof(byteptr) does not dereference the pointer, and as such, is the size of the pointer itself, which on this system seems to be 2 bytes/16 bits.
Consider the following:
#include "iostream"
using namespace std;
int main()
{
char a = 1;
char* aP = &a;
cout << "sizeof(char): " << sizeof(char) << endl;
cout << "sizeof(char*): " << sizeof(char*) << endl;
cout << "sizeof(a): " << sizeof(a) << endl;
cout << "sizeof(aP): " << sizeof(aP) << endl;
cout << "sizeof(*aP): " << sizeof(*aP) << endl;
}
Output (on a 64 bit OS/compiler):
sizeof(char): 1
sizeof(char*): 8
sizeof(a): 1
sizeof(aP): 8
sizeof(*aP): 1
#Maseb I think you've gotten a good discussion of the differences between the size of a dereferenced pointer and the actual size of the pointer itself. I'll just add that the sizeof(byte_pointer) must be large enough so that every address of memory space where a byte value could potentially be stored will fit into the pointer's memory width. For example, if there 32,000 bytes of storage on your Arduino then you could potentially have a pointer that needs to point to the address 32,000. Since 2^15 is about 32,000 you need 14 or 15 bits to create a unique address for each memory storage location. We set pointer address space length to blocks of four bits. Therefore, your Arduino has a 16bit address space for pointers and sizeof(byte_pointer) is 2 bytes, or 16 bits.
With that said, I'll go ahead an answer your other question too. If you need to pass an array and a size, just create your own struct that includes both of those data elements. Then you can pass the pointer to this templated struct which includes the size (This is the basic implementation for the C++ Array container).
I've written the short code sample below to demonstrate how to create your own template for an array with a size element and then use that size element to iterate over the elements.
template<int N>
struct My_Array{
int size = N;
int elem[N];
};
//create the pointer to the struct
My_Array<3>* ma3 = new My_Array<3>;
void setup() {
//now fill the array element
for(int i=0; i < ma3->size; i++) {
ma3->elem[0]=i;
}
Serial.begin(9600);
//now you can use the size value to iterate over the elements
Serial.print("ma3 is this big: ");
Serial.println(ma3->size);
Serial.println("The array values are:");
Serial.print("\t[");
for(int i=0; i<ma3->size; i++) {
Serial.print(ma3->elem[i]);
if(i < ma3->size-1) Serial.print(", ");
}
Serial.println("]");
}
void loop() {
while(true) { /* do nothing */ }
}
Related
I have come across a piece of example code that uses pointers and a simple subtraction to calculate the number of items in an array using C++.
I have run the code and it works but when I do the math on paper I get a different answer.
There explanation does not really show why this works and I was hoping someone could explain this too me.
#include <iostream>
using namespace std;
int main() {
int array[10] = {0, 9, 1, 8, 2, 7, 3, 6, 4, 5};
int stretch = *(&array + 1) - array;
cout << "Array is consists of: " << stretch << " numbers" << endl;
cout << "Hence, Length of Array is: " << stretch;
return 0;
}
From: https://www.educba.com/c-plus-plus-length-of-array/
When I run the code I get the number 10.
When I print the results of *(&array + 1) and array by
cout << *(&array+1) << endl; cout << array << endl;
I get of course two hex address's.
When I subtract these hex numbers I get 1C or 28???
Is it possible that C++ does not actually give the hex results or their translation to decimal but rather sees these numbers as addresses and therefore only returns the number of address slots remaining?
That is the closest I can come to an explanation if some one with more knowledge than I could explain this I would be very grateful.
Let's take one step back and take it step-by-step to see if it will help. Continuing from my comment, the problem you are having difficulty with is one of type.
Let's take the array iteself:
int array[10] = {0, 9, 1, 8, 2, 7, 3, 6, 4, 5};
On access, an array is converted to a pointer to the first element in the array (e.g. the address of the first element) subject to caveats not relevant here. So when you say array, you have type int *, a pointer to the first element in array.
Now what happens when I take the address of the array? (&array in)
int stretch = *(&array + 1) - array;
When you take the address of the array, the result is the same address as array, but has type int (*)[10] (a pointer-to-array-of int[10]). When you add 1 to that pointer (recall type controls pointer arithmetic), you get the address for the pointer to the next array of int[10] in memory after array -- which will be 10 int after the first element of array.
So *(&array + 1) gives you the address to the next array of int[10] after array, and then dereference is only needed for type compatibility. When you dereference an int (*)[10] you are left with int[10] -- which on access gives you the address of the first element of that array (one after the original)
Think through the types and let me know if you have further questions.
You forgot a small detail of how pointer addition or subtraction works. Let's start with a simple example.
int *p;
This is pointing to some integer. If, with your C++ compiler, ints are four bytes long:
++p;
This does not increment the actual pointer value by 1, but by 4. The pointer is now pointing to the next int. If you look at the actual pointer value, in hexadecimal, it will increase by 4, not 1.
Pointer subtraction works the same way:
int *a;
int *b;
// ...
size_t c=b-a;
If the difference in the hexadecimal values of a and b is 12, the result of this subtraction will not be 12, but 3.
When I subtract these hex numbers I get 1C or 28 ???
There must've been a mistake with your subtraction. Your result should be 0x28, or 40 (most likely you asked your debugger or compiler to do the subtraction, you got the result in hexadecimal and assumed that it was decimal instead). That would be the ten ints you were looking for.
I will try it with 5 items
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int array[] {1,2,3,4,5};
int items= sizeof(array)/sizeof(array[0]);
cout << items << endl;
int items2 = *(&array +1) - array;
cout << items2 << endl;
cout << array << endl;
cout << *(&array +1) << endl;
return 0;
}
root#localhost:~/Source/c++# g++ arraySize.cpp
root#localhost:~/Source/c++# ./a.out
5
5
0x7fe2ec2800
0x7fe2ec2814
using https://www.gigacalculator.com/calculators/hexadecimal-calculator.php to subtract the numbers from each other
I get
14 hex
20 decimal.
that fits with the 4 bytes to an integer.
thanx guys :)
this is an edit done on the 12th of december melbourne time ::
I have still had questions on this topic and something did not fit right with me about the entire route to counting array items via this code.
I found something I think is interesting and again would love to know why ( I shall try to explain it as best I can my self anyway)
*(&array + 1) is the question.
lets have a look at it.
as arrays are at there very nature in c and c++ only pointers to the first element in the array how can this work.
I shall use a small set of cout calls to see if I can find out whats happening.
#include <iostream>
using namespace std;
int main(int argc, char* argv[]){
int array[] {1,2,3,4,5,6,7,8,9,10};
int size {0};
size = *(&array + 1) - array;
cout << "size = *(&array + 1) - array = " << size << endl;
cout << "*(&array + 1) = " << *(&array + 1) << endl;
cout << "(&array + 1) = " << (&array + 1) << endl;
cout << "(array + 1) = " << (array + 1) << endl;
cout << "&array = " << &array << endl;
cout << "array = " << array << endl;
cout << "*(&array) = " << *(&array) << endl;
cout << "*(array) = " << *(array) << endl;
cout << "*array = " << *array << endl;
return 0;
}
again this is off proot in my phone so still under root with no systemd.
root#localhost:~/Source/c++# g++ arrayPointerSize.cpp
root#localhost:~/Source/c++# ./a.out
size = *(&array + 1) - array = 10
*(&array + 1) = 0x7ff6a51798
(&array + 1) = 0x7ff6a51798
(array + 1) = 0x7ff6a51774
&array = 0x7ff6a51770
array = 0x7ff6a51770
*(&array) = 0x7ff6a51770
*(array) = 1
*array = 1
we see that as a pointer array can be called with * too derefernce the pointer and give the variable held in position [0] in the array.
when calling &array or reference too array we get the return of the address at the first position in the array or [0].
when calling just array we also get the address for the first position in the array or [0].
when calling *array the * is working as it does for pointers and it is dereferencing the arrays first position [0] to give the variable.
now things get a little interesting.
*(array) also dereferences the array as is seen by its value being given as 1 in this instance.
yet *(&array) does not dereference the array and returns the address to the first position in the array.
in this instance memory address 0x7ff6a51770 is the first spot in the array array = 0x7ff6a51770
and &array (reference to the pointer of the position in memory that is the first spot in the array) gives the same address 0x7ff6a51770.
it is also of note in this instance to remind us of the fact that *(&array) is also returning the first possition in the array and *(array) is not
so we can not dereference a pointer too a position in memory as its variable is the position in memory.
if array and &array give the same answer as array is a pointer too the memory position in the first spot in our array and a reference to
this pointer.
why the different answer for (array + 1) and (&array + 1).
we get the memory address 0x7ff6a51774 for (array + 1) which is in line with an integer taking four bytes on my linux or
the addition of four bytes in memory past the first spot in the array (second array spot) but (&array + 1) gives a different answer.
if we follow the bytes and the code we see that (&array + 1) actually gives us the memory address four bytes after the end of the array.
so pointer too memory address add one gives the amount of bytes the variable type is past the memory address for the start of the array
and the reference to the pointer too the memory address add one gives the address the amount of bytes the variable type is after the last ?? spot in the array.
how then can array and &array return the same answer if (array + 1) and (&array + 1) do not.
it seems to me that the & reference when working with arrays overloads the + operator when doing arithmatic.
this would explain the difference in answers as straight &array has no operator too overload so returns the same answer as calling for
straight array
this small peice of code also shows that the use of pointers using *(&array + 1) is a very bad way to show a way to find array size with
pointers as really arrays are pointers and *(&array + 1) and (&array + 1) give the same result.
the heavy work was really being done by the reference operator &.
I may still be missing something here as I have used cout directly with the different experssions and being a stream it may
be limited in its ability to take advantage of what the reference operator is really doing when working with arrays.
I am still learning this language but I shall for sure keep this in mind as I dive deaper into c++.
I believe other than a few other trials with variables that the true answer will be found when reading the source for GCC g++.
I am not ready for that yet.
This is the code for testing my question.
#include <iostream>
#include <stack>
using namespace std;
int main(){
int num;
int Array[1];
stack<int> Stack;
cout << "Int size " << sizeof(num) <<endl; // Output: Int size 4
cout << "Array size " << sizeof(num) <<endl; // Output: Array size 4
cout << "Stack size " << sizeof(Stack) <<endl; // Output: Stack size 80
return 0;
}
I'm trying to understand about memory space allocation. Normally int memory size is 4 bytes. But, when I initialize an Stack of int data-type in std::stack then the Stack size is 80 bytes.
Should it 4? Why is std::stack taking 80 bytes? Or what is actually inside of stack for being the size 80 bytes?
sizeof gets the static size of the object/type. stack dynamically allocates memory for its elements. So, there is no correlation between size of the elements and size of stack in general. So, why is it 80 bytes? This is highly implementation specific. Size of stack is usually the same as the underlying container. By default, the underlying container is a std::deque, so that's where we must have a look. I checked libstdc++ specifically, and it seems to have 1 pointer, 1 size_t for size and 2 iterators like so:
struct _Deque_impl_data
{
_Map_pointer _M_map;
size_t _M_map_size;
iterator _M_start;
iterator _M_finish;
//...
(std::deque derives from _Deque_base which has a single member of type _Deque_impl_data)
Pointer and integer are 8 bytes, the iterators are 32 bytes. This adds up to 80 bytes. I didn't further investigate, but since deque is a more complex structure, it's only natural that it needs some memory for its own book-keeping.
You maybe confusing sizeof(Stack) with Stack.size() here. The sizeof operator returns the total size of the class object, which, in the case of std::stack includes (of necessity) a number of internal data and control variables (padding the size out to, in your case, 80 bytes). However, a call to Stack.size() will return the number of items currently on the stack.
These 'internal variables' will include such things as a pointer to the allocated memory (likely 8 bytes), a value recording the current element count (also likely to be 8 bytes) and a number of other pointers and counters, to aid in manipulation of the stack and optimization of access to the contained data, such as the current capacity of the allocated space, etc.
The following modified code shows the difference:
#include <iostream>
#include <stack>
using namespace std;
int main()
{
int num;
int Array[1];
stack<int> Stack;
cout << "Int size " << sizeof(num) << endl; // Int size 4
cout << "Array size " << sizeof(Array) << endl; // Array size 4 (1 "int" element)
cout << "Stack size " << sizeof(Stack) << endl; // Size of a "std::stack<int>" instance
cout << "Stack size " << Stack.size() << endl; // Size (# entries) of stack = 0 (empty)
return 0;
}
#include <iostream>
using namespace std;
int main() {
bool *a = new bool[10];
cout << sizeof(bool) << endl;
cout << sizeof(a[0]) << endl;
for (int i = 0; i < 10; i++) {
cout << a[i] << " ";
}
delete[] a;
}
The above code outputs:
1
1
112 104 151 0 0 0 0 0 88 1
The last line should contain garbage values, but why are they not all 0 or 1? The same thing happens for a stack-allocated array.
Solved: I forgot that sizeof counts bytes, not bits as I thought.
You have an array of default-initialized bools. Default-initialization for primitive types entail no initialization, thus they all have indeterminate values.
You can zero-initialize them by providing a pair of parentheses:
bool *a = new bool[10]();
Booleans are 1-byte integral types so the reason you're seeing this output is probably because that is the data on the stack at that moment that can be viewed with a single byte. Notice how they are values under 255 (the largest number that can be produced from an unsigned 1-byte integer).
OTOH, printing out an indeterminate value is Undefined Behavior, so there really is no logic to consider in this program.
sizeof(bool) on your machine returns 1.
That's 1 byte, not 1 bit, so the values you show can certainly be present.
What you are seeing is uninitialized values, different compilers generate different code. On GCC I see everything as 0 on windows i see junk values.
generally char is the smallest byte addressable- even though bool has 1/0 value- memory access wise it will be a char. Thus you will never see junk value greater than 255
Following initialization (memset fixes the things for you)
#include <iostream>
using namespace std;
int main() {
bool* a = new bool[10];
memset(a, 0, 10*sizeof(bool));
cout << sizeof(bool) << endl;
cout << sizeof(a[0]) << endl;
for (int i = 0; i < 10; ++i)
{
bool b = a[i];
cout << b << " ";
}
return 0;
}
Formally speaking, as pointed out in this answer, reading any uninitialized variable is undefined behaviour, which basically means everything is possible.
More practically, the memory used by those bools is filled with what you called garbage. ostreams operator<< inserts booleans via std::num_put::put(), which, if boolalpha is not set, converts the value present to an int and outputs the result.
I do not know why you put a * sign before variable a .
Is it a pointer to point a top element address of the array?
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.
I need to track my current location in a data buffer (which will be used as a packet), so I am using two variables, bufferLoc and dataBuffer.
char dataBuffer[8192];
char** bufferLoc;
I am pointing to the starting location of dataBuffer with bufferLoc. But incrementing bufferLoc does not affect its physical address in memory.
bufferLoc = (char**)&dataBuffer;
cout << &bufferLoc << endl;
bufferLoc++;
cout << &bufferLoc << endl;
These two prints will output the same location. Does my error have to do with type casting, with bufferLoc itself, or something completely different?
Thanks for your help.
If your intention is to scan through dataBuffer one byte at a time, then the second variable should be a pointer, not a pointer to a pointer.
char* bufferLoc;
then print it out without the ampersand:
cout << (unsigned int *)bufferLoc << endl;
note that cout will try to print your variable as text unless you cast to an unsigned int*
cout << &bufferLoc << endl;
prints the address of bufferLoc. This address is always the same. You can print the value stored in bufferLoc:
cout << bufferLoc << endl;
this value is the address of dataBuffer initially, when you increment it, it will be 4 bytes greater in the second print statement.
dataBuffer itself stores a pointer to a char array of 8192 bytes. What you want to do is to get this value:
char *bufferLoc = dataBuffer;
and increment this value. Note that type of bufferLoc is a pointer to a char array (just as dataBuffer). After assigning the address stored in dataBuffer to bufferLoc, you can print the first element: like this: cout << bufferLoc[0] << end.