This question already has answers here:
getting size of array from pointer c++
(6 answers)
Closed 3 years ago.
I am trying to make a function that can return the size of an array that can be different data types. I believe the expression (sizeof(z)/sizeof(*z))) returns the memory allocated to z divided by the memory size of the data type. The following code is my attempt to overload the function and return the size of the array as an integer. When I run the expression in the main function it works, but when I try to pass the array to the function I do not get the correct values and not sure what I am doing wrong. 68 / 4 = 17 which is the correct size of the array.
(1) outputs sizeof(z) and sizeof(*z) in the size function
(2) expression in main function
(3) outputs sizeof(z) in the main function
(4) outputs sizeof(*z) in the main function
#include <iostream>
using namespace std;
//
int size(int *data){
cout << sizeof(data) << ", " << sizeof(*data) << ", ";
return((sizeof(data))/(sizeof(*data)));
}
int size(char *x){return(sizeof(x)/sizeof(*x));}
int size(float *x){return(sizeof(x)/sizeof(*x));}
int size(double *x){return(sizeof(x)/sizeof(*x));}
int size(short int *x){return(sizeof(x)/sizeof(*x));}
int size(long int *x){return(sizeof(x)/sizeof(*x));}
int main(){
double x[9];
int z[17];
char k[29];
cout << "(1) Size : " << size(z) << endl;
cout << "(2) Size : " << (sizeof(z)/sizeof(*z)) << endl;
cout << "(3) Size : " << sizeof(z) << endl;
cout << "(4) Size : " << sizeof(*z) << endl;
cout << "(5) Size : " << size(z) << endl;
cout << "(6) Size : " << size(k) << endl;
return 0;
}
Terminal Output:
(1) Size : 8, 4, 2
(2) Size : 17
(3) Size : 68
(4) Size : 4
(5) Size : 8, 4, 2
(6) Size : 8
An array decays to a pointer when you pass it to another function, so sizeof(arr) will give you the actual amount of memory allocated, only in the scope of the function in which arr was declared.
There's a common mistake:
char* a // is a pointer
char b[] // is an array
when using:
char b[5]; // is an array of 5 bytes
sizeof(b); // 5
// but
char* a = b;
sizeof(a); // 8 (x64)
the last sizeof(a) is giving you the sizeof char * which is a pointer.
You can pass the name of an Array as a Pointer to the size() function, but in that function, the argument is treated as Pointer.
Related
I am trying to compile the following code:
#include <iostream>
using namespace std;
void show1(string text1[]) {
cout << "Size of array text1 in show1: " << sizeof(text1) << endl;
}
int main() {
string text1[] = {"apple","melon","pineapple"};
cout << "Size of array text1: " << sizeof(text1) << endl;
cout << "Size of string in the compiler: " << sizeof(string) << endl;
show1(text1);
return 0;
}
And the output is shown below:
Size of array text1: 96
Size of string in the compiler: 32
Size of array text1 in show1: 8
I am not able to understand, why is the sizeof operator working on the same array giving two different outputs at two different points? Please explain.
The sizeof() operator returns the compile time size of the objects. It means that if your type allocates a memory chunk at run time from heap, that memory is not taken into account by sizeof().
For your first case, i.e.
string text1[] = {"apple","melon","pineapple"};
You have an array of 3 strings, so sizeof should return 3*sizeof(std::string). (3*32 = 96 in your case)
For your second case:
sizeof(string)
It should simply print the size of an string. (32 in your case).
Finally for your last case, do not forget that arrays are passed using a pointer in C/C++. So, your parameter is simply a pointer and sizeof() should print the size of a pointer on your machine.
Edit: As #ThomasMatthews has mentioned in the comments, if you are interested in getting the real size of an string (i.e. the number of characters inside it), you can use std::string::length() or std::string::size().
Try with member function 'size'.
Write this code:
#include <iostream>
using namespace std;
void show1(string text1[])
{
cout << "Size of array text1 in show1: " << text1->size() << endl;
}
int main()
{
string text1[] = {"apple","melon","pineapple"};
cout << "Size of array text1: " << text1->size() << endl;
cout << "Size of string in the compiler: " << sizeof(string) << endl;
show1(text1);
return 0;
}
Description:
std::vector has a member function size(). And std::string too. In std::vector return size of vector(all elements). In std::string returns all elements in array.
I had the online coding interview today and I really struggled while trying to calculate the size of the array.
Could you please help me with how can I measure the sizeof array here? I tried my best but no luck please help here.
#include<iostream>
#include<map>
#include<vector>
using namespace std;
void arraysize(int* a) {
cout << "size1: "<<sizeof(a) << endl;
cout << "size2: " << sizeof(a[0]) << endl;;
}
int main()
{
int array1[] = { 1,2,3,4,5,6,7,8 };
arraysize(array1);
return 0;
}
Result:
size1: 4
size2: 4
In most cases, when you pass an array to a function, the array will be converted to a pointer. This is called an array-to-pointer decay. Once this decay happens, you lose the size information of the array. That is, you can no longer tell the size of the original array from the pointer.
However, one case in which this conversion / decay will not happen is when we pass a reference to the array. We can take advantage of this property to get the size of an array.
#include<iostream>
template<typename T, size_t N>
size_t asize(T (&array)[N])
{
return N;
}
int main()
{
int array1[] = { 1,2,3,4,5,6,7,8 };
std::cout << asize(array1) << std::endl; // 8
return 0;
}
In the above case, to the template function asize, we pass a reference to an array of type T[N], whose size is N. In this case, it is array type int[8]. So the function returns N, which is size 8.
C style array's decay to pointer's when passed to a function like this.
The first cout statement is printing the size of a pointer on your machine.
The second cout statement is printing the size of an integer.
Use one of the following solutions in order to pass the size of the array to the function.
template<std::size_t N>
void ArraySize( int ( &array )[ N ] )
{
std::cout << "Array size: " << N << '\n';
}
void ArraySize( int* array, std::size_t size )
{
std::cout << "Array size: " << size << '\n';
}
template<std::size_t N>
void ArraySize( std::array<int, N>& array )
{
std::cout << "Array size: "<< array.size( ) << '\n';
}
sizeof(a) returns the number of bytes in array,
sizeof(int) returns the number of bytes in an int,
ergo
sizeof(a)/sizeof(int) returns the array length
Easiest way to get the size of an array:
#include <iostream>
using namespace std;
int main(void) {
int ch[5], size;
size = sizeof(ch) / sizeof(ch[0]);
cout << size;
return 0;
}
Output: 5
simply divide sizeof(array1) by sizeof(int). it will give you total element in array. because sizeof(array1) will give total bytes in the array. for example sizeof(array1) = int * 8 because your array is int so int is 4 byte answer is 4*8 = 32.Now you have to divide it again by 4 cause its in byte.
cout << "Size of the Array is : " << sizeof(array1)/sizeof(int) << endl;
put above code in your main function to get result
The following code:
#include<iostream>
int main (void) {
int lista[5] = {0,1,2,3,4};
std::cout << lista << std::endl;
std::cout << &lista << std::endl;
std::cout << lista+1 << std::endl;
std::cout << &lista+1 << std::endl;
std::cout << lista+2 << std::endl;
std::cout << &lista+2 << std::endl;
std::cout << lista+3 << std::endl;
std::cout << &lista+3 << std::endl;
return (0);
}
Outputs:
0x22ff20
0x22ff20
0x22ff24
0x22ff34
0x22ff28
0x22ff48
0x22ff2c
0x22ff5c
I understood that an array is another form to express a pointer, but we cannot change its address to point anywhere else after declaration. I also understood that an array has its value as the first position in memory. Therefore, 0x22ff20 in this example is the location of the array's starting position and the first variable is stored there.
What I did not understand is: why the other variables are not stored in sequence with the array address? I mean, why lista+1 is different from &lista+1. Should not they be the same?
In pointer arithmetic, types matter.
It's true that the value is the same for both lista and &lista, their types are different: lista (in the expression used in cout call) has type int* whereas &lista has type int (*)[5].
So when you add 1 to lista, it points to the "next" int. But &lista + 1 points to the location after 5 int's (which may not be a valid).
Answering the question as asked:
std::cout << &lista+1 << std::endl;
In this code you take the address of array lista and add 1 to obtained answer. Given the sizeof of the array is sizeof(int) * 5, which means when you increment a pointer to it by 1 you add sizeof(int) * 5 to the pointer address, you end up with a number you see.
I have this code:
int main()
{
char ch[15];
cout<<strlen(ch)<<endl; //7
cout<<sizeof(ch)<<endl; //15
return 0;
}
Why does strlen(ch) give different result even if it is empty char array?
Your code has undefined behavior because you are reading the uninitialized values of your array with strlen. If you want a determinate result from strlen you must initialize (or assign to) your array.
E.g.
char ch[15] = "Hello, world!";
or
char ch[15] = {};
sizeof will give the size of its operand, as the size of char is one by definition the size of a char[15] will always be 15.
strlen gives the length of a null terminated string which is the offset of the first char with value 0 in a given char array. For a call to strlen to be valid, the argument to must actually point to a null terminated string.
ch is a local variable and local variables are not initialized. So your assumption that it is an empty string is not correct. Its filled with junk. It was just a co-incidence that a \0 character was found after 7 junk characters and hence strlen returned 7.
You can do something like these to ensure an empty string-
char ch[15]={0};
ch[0]='\0`;
strcpy(ch,"");
Here's a similar thread for more reading
Variable initialization in C++
The problem is in
strlen(ch);
strlen counts the number of chars, untill hitting the \0 symbol. Here, ch is non-initialized, so strlen could return anything.
As for the result from strlen, in your case you have an uninitialized char array, and so strlen only happens to yield 7: there must be a null character at array element 8, but this code could give different results for strlen every time.
Always initialize strings, it's easy enough with an array: char str[15] = {0};
sizeof is an operator used to get the size of a variable or a data type, or the number of bytes occupied by an array, not the length of a C string; don't expect strlen and strcpy to be interchangeable, or even comparable in any useful way.
For instance:
int main()
{
char str[15] = "only 13 chars";
cout << "strlen: " << strlen(str) << endl;
cout << "sizeof: " << sizeof(str) << endl;
}
The output is:
strlen: 13
sizeof: 15
Returns the length of str.
The length of a C string is determined by the terminating
null-character: A C string is as long as the amount of characters
between the beginning of the string and the terminating null
character.
sizeof returns number of bytes (15). Your array is filled by garbage, so, strlen can returns any number. Correct example is
int main()
{
char ch[15] = {0};
cout<<strlen(ch)<<endl; //0
cout<<sizeof(ch)<<endl; //15
return 0;
}
The difference between sizeof and strlen in C++:
1) sizeof is a operator, strlen is a function;
2) The return type of sizeof is size_t,and it is defined (typedef) as unsigned int in its header; It gets the byte size of the memory allocation which can maximize to accommodate this object to be created in memory;
3) sizeof can use type as a parameter, while strlen can only use char pointer (char*) as a pointer, and it must be ended as '\0';
sizeof can also use function as a parameter, for instance:
short f() {return 100;}
std::cout << "sizeof(f()): " << sizeof(f()) << std::endl;
//The result will be sizeof(short), which is 2.
4) If char array is a parameter, it will not be degraded by sizeof, while strlen will degrade it as a char pointer;
5) The result of strlen will be calculated in the run time, not compilation time, strlen is used to get the real size of the content of a string (string, char array, char pointer) until the '\0', not the real size of memory allocation. Most of the compiler will calculate the result of sizeof in the compilation time, no matter the parameter is type or variable, that is why sizeof(x) can be used to decide the dimension of an array:
char str[20]="0123456789";
int a=strlen(str); //a=10;
int b=sizeof(str); //while b=20;
7) If the parameter of sizeof is a type, then parentheses are mandatory, while if the parameter is a variable, parentheses are optional, because sizeof is an operator not a function;
8) When you use a structured type or variable as a parameter, sizeof will return its real size, when you use a static array, sizeof will return the array size. But sizeof operator cannot return the size of an array which is created dynamically or externally. Because sizeof is a compilation time operator.
Here is an example of sizeof and strlen:
#include <iostream>
#include <cstdlib>
#include <string>
#include <cstring>
short f1 ()
{
return 100;
}
int f2 ()
{
return 1000;
}
int main()
{
char* char_star = "0123456789";
// char_star is a char pointer, sizeof will return the pointer size allocated in memory: depends on your machine
std::cout << "sizeof(char_star):" << sizeof(char_star) << std::endl;
// *char_star is the first element of the string, it is a char, sizeof will return the char size allocated in memory: depends on your machine, normally is 1
std::cout << "sizeof(*char_star):" << sizeof(*char_star) << std::endl;
// char_star is a char pointer, strlen will return the real size of the string until '\0': 10
std::cout << "strlen(char_star):" << strlen(char_star) << std::endl;
std::cout << std::endl;
char char_array[] = "0123456789";
// char_array is a char array, sizeof will return the array size allocated in memory, with a '\0' at the end: 10 + 1
std::cout << "sizeof(char_array):" << sizeof(char_array) << std::endl;
// *char_array is the first element of the array, it is a char, sizeof will return the char size allocated in memory: depends on your machine, normally is 1
std::cout << "sizeof(*char_array):" << sizeof(*char_array) << std::endl;
// char_array is a char array, strlen will return the real size of the string until '\0': 10
std::cout << "strlen(char_array):" << strlen(char_array) << std::endl;
std::cout << std::endl;
char_array_fixed[100] = "0123456789";
// char_array_fixed is a char array with fixed size, sizeof will return the array size allocated in memory: 100
std::cout << "sizeof(char_array_fixed):" << sizeof(char_array_fixed) << std::endl;
// *char_array_fixed is the first element of the array, it is a char, sizeof will return the char size allocated in memory: depends on your machine, normally is 1
std::cout << "sizeof(*char_array_fixed):" << sizeof(*char_array_fixed) << std::endl;
// *char_array_fixed is a char array with fixed size, strlen will return the real content size of the string until '\0': 10
std::cout << "strlen(char_array_fixed):" << strlen(char_array_fixed) << std::endl;
std::cout << std::endl;
int int_array[100] = {0,1,2,3,4,5,6,7,8,9};
// int_array is a int array with fixed size, sizeof will return the array size allocated in memory: 100
std::cout << "sizeof(int_array):" << sizeof(int_array) << std::endl;
// *int_array is the first element of the array, it is an int, sizeof will return the int size allocated in memory: depends on your machine, normally is 4
std::cout << "sizeof(*int_array):" << sizeof(*int_array) << std::endl;
// int_array is a int array with fixed size, strlen will throw exception
//std::cout << "strlen(int_array):" << strlen(int_array) << std::endl;
std::cout << std::endl;
char char_array2[] = {'a', 'b', '3'};
// char_array2 is a char array, sizeof will return the array size allocated in memory: 3
std::cout << "sizeof(char_array2):" << sizeof(char_array2) << std::endl;
// *char_array2 is the first element of the array, it is a char, sizeof will return the char size allocated in memory: depends on your machine, normally is 1
std::cout << "sizeof(*char_array2):" << sizeof(*char_array2) << std::endl;
// *char_array2 is a char array, strlen will return the real content size of the string until '\0': 3
std::cout << "strlen(char_array2):" << strlen(char_array2) << std::endl;
std::cout << std::endl;
char char_array3[] = {"abc"};
// char_array3 is a char array, sizeof will return the array size allocated in memory, with a '\0' at the end : 3 + 1
std::cout << "sizeof(char_array3):" << sizeof(char_array3) << std::endl;
// *char_array3 is the first element of the array, it is a char, sizeof will return the char size allocated in memory: depends on your machine, normally is 1
std::cout << "sizeof(*char_array3):" << sizeof(*char_array3) << std::endl;
// *char_array3 is a char array, strlen will return the real content size of the string until '\0': 3
std::cout << "strlen(char_array3):" << strlen(char_array3) << std::endl;
std::cout << std::endl;
std::string str = {'a', 'b', '3', '\0', 'X'};
// str is a string, sizeof will return the string size allocated in memory (string is a wrapper, can be considered as a special structure with a pointer to the real content): depends on your machine, normally is 32
std::cout << "str:" << str << std::endl;
std::cout << "sizeof(str):" << sizeof(str) << std::endl;
// *str means nothing, sizeof will throw exeption
//std::cout << "sizeof(*str):" << sizeof(*str) << std::endl;
// str is a string, strlen will return the real content size of the string until '\0': 3
std::cout << "strlen(str):" << strlen(str.c_str()) << std::endl;
std::cout << std::endl;
// sizeof is an operation, if the parameter is a type, parentheses are mandatory
std::cout << "sizof(int):" << sizeof(int) << std::endl;
// sizeof is an operation, if the parameter is a variable, parentheses are optional
std::cout << "sizof char_star:" << sizeof char_star << std::endl;
std::cout << "sizof char_array:" << sizeof char_array << std::endl;
// sizeof is an operation, can take a function as parameter
std::cout << "sizeof(f()): " << sizeof(f1()) << std::endl;
std::cout << "sizeof(f()): " << sizeof(f2()) << std::endl;
}
#include <iostream>
using namespace std;
struct test
{
int i;
double h;
int j;
};
int main()
{
test te;
te.i = 5;
te.h = 6.5;
te.j = 10;
cout << "size of an int: " << sizeof(int) << endl; // Should be 4
cout << "size of a double: " << sizeof(double) << endl; //Should be 8
cout << "size of test: " << sizeof(test) << endl; // Should be 24 (word size of 8 for double)
//These two should be the same
cout << "start address of the object: " << &te << endl;
cout << "address of i member: " << &te.i << endl;
//These two should be the same
cout << "start address of the double field: " << &te.h << endl;
cout << "calculate the offset of the double field: " << (&te + sizeof(double)) << endl; //NOT THE SAME
return 0;
}
Output:
size of an int: 4
size of a double: 8
size of test: 24
start address of the object: 0x7fffb9fd44e0
address of i member: 0x7fffb9fd44e0
start address of the double field: 0x7fffb9fd44e8
calculate the offset of the double field: 0x7fffb9fd45a0
Why do the last two lines produce different values? Something I am doing wrong with pointer arithmetic?
(&te + sizeof(double))
This is the same as:
&((&te)[sizeof(double)])
You should do:
(char*)(&te) + sizeof(int)
You are correct -- the problem is with pointer arithmetic.
When you add to a pointer, you increment the pointer by a multiple of that pointer's type
Therefore, &te + 1 will be 24 bytes after &te.
Your code &te + sizeof(double) will add 24 * sizeof(double) or 192 bytes.
Firstly, your code is wrong, you'd want to add the size of the fields before h (i.e. an int), there's no reason to assume double. Second, you need to normalise everything to char * first (pointer arithmetic is done in units of the thing being pointed to).
More generally, you can't rely on code like this to work. The compiler is free to insert padding between fields to align things to word boundaries and so on. If you really want to know the offset of a particular field, there's an offsetof macro that you can use. It's defined in <stddef.h> in C, <cstddef> in C++.
Most compilers offer an option to remove all padding (e.g. GCC's __attribute__ ((packed))).
I believe it's only well-defined to use offsetof on POD types.
struct test
{
int i;
int j;
double h;
};
Since your largest data type is 8 bytes, the struct adds padding around your ints, either put the largest data type first, or think about the padding on your end! Hope this helps!
&te + sizeof(double) is equivalent to &te + 8, which is equivalent to &((&te)[8]). That is — since &te has type test *, &te + 8 adds eight times the size of a test.
You can see what's going on more clearly using the offsetof() macro:
#include <iostream>
#include <cstddef>
using namespace std;
struct test
{
int i;
double h;
int j;
};
int main()
{
test te;
te.i = 5;
te.h = 6.5;
te.j = 10;
cout << "size of an int: " << sizeof(int) << endl; // Should be 4
cout << "size of a double: " << sizeof(double) << endl; // Should be 8
cout << "size of test: " << sizeof(test) << endl; // Should be 24 (word size of 8 for double)
cout << "i: size = " << sizeof te.i << ", offset = " << offsetof(test, i) << endl;
cout << "h: size = " << sizeof te.h << ", offset = " << offsetof(test, h) << endl;
cout << "j: size = " << sizeof te.j << ", offset = " << offsetof(test, j) << endl;
return 0;
}
On my system (x86), I get the following output:
size of an int: 4
size of a double: 8
size of test: 16
i: size = 4, offset = 0
h: size = 8, offset = 4
j: size = 4, offset = 12
On another system (SPARC), I get:
size of an int: 4
size of a double: 8
size of test: 24
i: size = 4, offset = 0
h: size = 8, offset = 8
j: size = 4, offset = 16
The compiler will insert padding bytes between struct members to ensure that each member is aligned properly. As you can see, alignment requirements vary from system to system; on one system (x86), double is 8 bytes but only requires 4-byte alignment, and on another system (SPARC), double is 8 bytes and requires 8-byte alignment.
Padding can also be added at the end of a struct to ensure that everything is aligned properly when you have an array of the struct type. On SPARC, for example, the compile adds 4 bytes pf padding at the end of the struct.
The language guarantees that the first declared member will be at an offset of 0, and that members are laid out in the order in which they're declared. (At least that's true for simple structs; C++ metadata might complicate things.)
Compilers are free to space out structs however they want past the first member, and usually use padding to align to word boundaries for speed.
See these:
C struct sizes inconsistence
Struct varies in memory size?
et. al.