This question already has answers here:
What happens if I define a 0-size array in C/C++?
(8 answers)
Closed 1 year ago.
Today I incidentally defined a two dimensional array with the size of one dimension being 0, however my compiler did not complain. I found the following which states that this is legal, at least in the case of gcc:
6.17 Arrays of Length Zero
However, I have two questions on this usage:
First, is this considered as good programming practice? If so, then when should we use it in real world?
Second, the array I defined was two dimensional, with 0 size for one dimension. Is this the same as the one dimensional case? For example,
int s[0]
int s[0][100]
int s[100][0]
Are they all the same in the memory and for the compiler?
EDIT: Reply to Greg: The compiler I am using is gcc 4.4.5. My intention for this problem is not compiler-dependent, however if there are any compiler specific quirks that would be helpful too:)
Thanks in advance!
In C++ it is illegal to declare an array of zero length. As such it is not normally considered a good practice as you are tying your code to a particular compiler extension. Many uses of dynamically sized arrays are better replaced with a container class such as std::vector.
ISO/IEC 14882:2003 8.3.4/1:
If the constant-expression (5.19) is present, it shall be an integral constant expression and its value shall be greater than zero.
However, you can dynamically allocate an array of zero length with new[].
ISO/IEC 14882:2003 5.3.4/6:
The expression in a direct-new-declarator shall have integral or enumeration type (3.9.1) with a non-negative value.
I ran this program at ideone.com
#include <iostream>
int main()
{
int a[0];
int b[0][100];
int c[100][0];
std::cout << "sizeof(a) = " << sizeof(a) << std::endl;
std::cout << "sizeof(b) = " << sizeof(b) << std::endl;
std::cout << "sizeof(c) = " << sizeof(c) << std::endl;
return 0;
}
It gave the size of all the variables as 0.
sizeof(a) = 0
sizeof(b) = 0
sizeof(c) = 0
So in the above example, no memory is allocated for a, b or c.
Compiling your example with gcc, all three of them have sizeof 0, so I would assume that all of them are treated equally by the compiler.
Your link explains everything. They are used as last field in a struct when the length of struct is not known at compile time. If you try using them on stack or in a middle of other declarations you will end up overwriting next elements.
Related
I'm playing with a function to get used to some C++ syntax.
Now I think, I might have misunderstood:
I'm writing to a static (?) array I had defined as myArray[0] for experimenting.
So it seems NOT to be static, but sizeof(myArray) always returns 0 (?)
but I can find mem address for each item (while I have no idea, how to get the number of items this way).
The other thing I don't understand, is why I can write myInt = myFloat?
So, what IS a static array? And should I better use <vector> for an array of undefined length?
(You could find the whole code here int2bin main.cpp)
#include <iostream>
//#include <regex>
int main()
{
while(true) {
//VARS
unsigned int arrBin[0], intNum; //working, if set [0]! NOT static???
unsigned int *pArr0 = &arrBin[0];
unsigned int *pArr1 = &arrBin[1];
std::cout << sizeof(arrBin) << '\n'; // 0 => sizeof() here items and not mem space?
std::cout << pArr0 << '\n';// 0x7fff12de6c38
std::cout << pArr1 << '\n';// 0x7fff12de6c3c
int i;
float refNum;
std::cout << "\n\nEnter a number to convert: ";
// GET INPUT
std::cin >> refNum; // float
intNum = refNum; // get int of the dec for comparing. Why does this "int = float" work???
unsigned int arrBin[0]
The size of an array variable must not be 0. The program is ill-formed. Don't do this.
unsigned int *pArr1 = &arrBin[1];
Here, you use subscript operator beyond the bounds of the array (beyond one past last element), so the behaviour of the program is undefined. Don't do this.
(while I have no idea, how to get the number of items this way).
The number of items is 0 (or would be if that was allowed in the first place).
The other thing I don't understand, is why I can write myInt = myFloat?
You haven't even declared such identifiers.
I'm writing to a static (?) array I had defined as myArray[0] for experimenting.
By 'static' you probably mean 'fixed-sized'. static means something totally different, see https://www.geeksforgeeks.org/static-keyword-cpp/.
So it seems NOT to be static
It is not static, hence, it's not surprising that it's not static.
but sizeof(myArray) always returns 0
Its size is 0, as the size of 0 was specified. While this is not supported by the standards, it's possible that some compilers allow it.
but I can find mem address for each item (while I have no idea, how to get the number of items this way).
&arr[i] yields the address.
The other thing I don't understand, is why I can write myInt = myFloat?
Integer numbers are always real numbers, but real numbers are not always integer numbers. So, how would you store 0.5 as an integer? You could cast it or you could round it.
So, what IS a static array?
In the link I have provided you, it is mentioned that static variables in a function are variables for whom memory is allocated for the whole duration of a program. Hence, a static array is an array declared with the static keyword for which space are allocated for the whole lifecycle of your program. No such array was declared in your function.
And should I better use for an array of undefined length?
This is opinionated. You could create a pointer and navigate to items using pointer arithmetics, achieving the same behavior as with arrays, but without the length being fixed and with a slightly different syntax. Or you could use a library, a vector or whatever fits your task and taste.
This question already has answers here:
sizeof() a vector
(6 answers)
Closed 1 year ago.
I was just experimenting with C++ and here is a code snippet that I executed:
int main() {
std::vector<int> data = { 1, 2, 3, 4, 5 };
std::cout << data.size() << " " << sizeof(data) << " " << sizeof(data[0]) << std::endl;
return 0;
}
The output I get is:
5 16 4
Now I know that size() returns the number of elements in vector ie. 5 here and sizeof() returns the number of bytes occupied by the variable. sizeof(data[0]) makes sense to be 4 bytes as it is an int and visual studio compiler assigns 4 bytes to it but I dont understand why sizeof(data) returns 16. I was calculating 20. Any explanation for this would be helpful.
std::vector<T> uses dynamic storage the size of which can be changed, as stated in documentation. unlike std::array<T, size> it's not an aggregate type and stored data isn't part of class's storage. sizeof returns the size of storage, which is a constant determined at time of compilation, according to C++ rules.
Ergo, you compare apples to oranges. sizeof returns size of vector's type in bytes, Member function size() returns number of created elements. Member function capacity() would return allocated memory, which can be larger than size()*sizeof(T).
This question already has answers here:
What is array to pointer decay?
(11 answers)
Closed 4 years ago.
So I've been searching on Stackoverflow for all the code that can find the size of a pointer to an array. I couldn't find it.
int main() {
int array[] = {6,3, 4, 6, 2};
int *sizes = array;
cout << sizeof(sizes); // output is 8
}
Using sizeof doesn't work. Can anyone suggest a good solution? Thanks a lot!
**EDIT:
I want to find the size of the array using the pointer "sizes". I know how to find the size using the "array" variable
You can read in c++ doc http://www.cplusplus.com/reference/array/array/size/
For example:
// array::size
#include <iostream>
#include <array>
int main ()
{
std::array<int,5> myints;
std::cout << "size of myints: " << myints.size() << std::endl;
std::cout << "sizeof(myints): " << sizeof(myints) << std::endl;
return 0;
}
If you want C level answer, why did you tag this question as c++?
int main() {
int array[] = {6,3, 4, 6, 2};
cout << sizeof(array) / sizeof(int);
return 0;
}
It might not be satisfy but it's impossible to find the array's size using a pointer to the array. Pointer unlike the array, can point to any type of variable with the right casting. It doesn't store a straight memory allocation places like the array. That's why you'll always get 8 bytes in 64bit OS architecture or 4 bytes in 32bit OS architecture of size when you do sizeof(pointer).
Read about the differences between pointers and arrays in c.
Within the scope that array was declared in, sizeof(array) is the number of bytes in the array.¹
If you want the number of elements in array, that’s (sizeof(array)/sizeof(array[0])).
Since sizes is declared as an int*, sizeof(sizes) is the size of a pointer. That will be 8 for a 64-bit program, 4 for a 32-bit program, or some other size on an unusual architecture.
There is one other wrinkle: if you pass array to a function, such as:
int* reverse_array( int a[], const size_t n )
{
assert( sizeof(a) == sizeof(int*) );
// ...
}
Then the array parameter, a, automatically degrades to a pointer, and the compiler forgets its actual size. This is for backward-compatibility with C.
To use an array within another function, you must pass the size as a separate parameter, in this case n, or use a type such as std::array<int>, std::vector<int>, or a struct. The latter is what Bjarne Stroustrup’s C++ guidelines recommend, although, if you use a STL template in the ABI of a library, you are introducing a dependency on a particular implementation of the STL.
¹ Since this community loves language-lawyering: some historical C compilers measured sizes in increments other than bytes. Some C++ compiler hypothetically might make char more than 8 bits wide (although not less!) and claim to be technically conforming to the standard. You don’t need to worry about that possibility right now. Seriously, you don’t.
#include <iostream>
using namespace std;
class Empty{
char omg[0];
};
int main()
{
Empty em1, em2;
Empty set[100];
cout << sizeof(Empty) << " " << sizeof(em1) << " " << sizeof(em2) << endl;
cout << (long*)&em1 << " " << (long*)&em2 << endl;
cout << "total numbers of element is: " << sizeof(set)/sizeof(*set) << endl;
return 0;
}
Its output is:
0 0 0
0xbff36ad0 0xbff36ac8
numbers of elements is: 4
The results are so surprising.
As shown above, Empty is a class, the size of it and its objects are all 0, why?
Maybe I guess, because a empty class's size is 1, and when the class is not empty, its size is decided by is members, but here its member is special, it is a Arrays of Length Zero, and this array's size is 0, so the size of class and objects are all 0.
It's just my guess. As the program running, we can see that two objects both have address, and the address is different.
Here is my question: if object of 0 size can be implemented, Why the C++ standard states that empty objects have sizeof() = 1, it is for "To ensure that the addresses of two different objects will be different"Why is the size of an empty class not zero? , but now, we do have different address as the output,how does this happen?
Further more, no matter what the size of the array set is, the last line output is always 4, why?
Thanks :)
PS: I run this program on MacOS, and the compiler is Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
I'll take a stab since no one more experienced has:
As shown above, Empty is a class, the size of it and its objects are all 0, why?
Zero-sized arrays are prohibited by the standard, therefore as far as the standard is concerned sizeof(Empty) is a meaningless expression, you are already in the realm of undefined behaviour.
Here is my question: if object of 0 size can be implemented, [...] Why is the size of an empty class not zero? , but now, we do have different address as the output,how does this happen?
As above, an object of size 0 cannot exist in a valid standard c++ program (with the exception of base class subobjects).
Your compiler allows this as an extension to the standard, and as long as you use this extension within the scope it was intended for (i.e. as a pre-flexible array member hack) you shouldn't have any problems, although your code is not portable. Your example above however is not how zero-sized arrays are meant to be used (not to mention there are better constructs in c++ for handling these situations anyway).
Your compiler is intelligent enough to provide separate addresses for em1 and em2, but you should find that all elements of set have in fact the same address.
Further more, no matter what the size of the array set is, the last line output is always 4, why?
Since your compiler considers sizeof(Empty) and arrays of Empty to be zero, you are dividing by zero, which is undefined behavior. You might find your program crashes if you disable optimizations, with GCC for instance your program crashes with -O0 but not with -O1.
const size_t size = 5;
int *i = new int[size]();
for (int* k = i; k != i + size; ++k)
{
cout << *k << endl;
}
Even though I have value initialized the dynamic array elements by using the () operator, the output I get is
135368
0
0
0
0
Not sure why the first array element is initialized to 135368.
Any thoughts ?
My first thought is: "NO...just say NO!"
Do you have some really, truly, unbelievably good reason not to use vector?
std::vector<int> i(5, 0);
Edit: Of course, if you want it initialized to zeros, that'll happen by default...
Edit2: As mentioned, what you're asking for is value initialization -- but value initialization was added in C++ 2003, and probably doesn't work quite right with some compilers, especially older ones.
I agree with litb's comment. It would appear to be a compiler bug.
Putting your code in a main function and prefixing with:
#include <iostream>
#include <ostream>
using std::cout;
using std::endl;
using std::size_t;
I got five zeros with both gcc 4.1.2 and a gcc 4.4.0 on a linux variant.
Edit:
Just because it's slightly unusual with array type: In a new expression an initializer of () means that the dynamically allocated object(s) are value initialized. This is perfectly legal even with array new[...] expressions. It's not valid to have anything other than a pair of empty parentheses as an initializer for an array new expression, although non-empty initializers are common for for non-array new epxressions.