Can I determine the size/length of an array in C++ without having to hardcode it? - c++

I am basically looking for some sort of "dynamic" way of passing the size/length of an array to a function.
I have tried:
void printArray(int arrayName[])
{
for(int i = 0 ; i < sizeof(arrayName); ++i)
{
cout << arrayName[i] << ' ';
}
}
But I realized it only considers its bytesize and not how many elements are on the array.
And also:
void printArray(int *arrayName)
{
while (*arrayName)
{
cout << *arrayName << ' ';
*arrayName++;
}
}
This has at least printed me everything but more than what I expected, so it doesn't actually work how I want it to.
I reckon it is because I don't exactly tell it how big I need it to be so it plays it "safe" and throws me some big size and eventually starts printing me very odd integers after my last element in the array.
So I finally got this work around, yet I believe there is something better out there!:
void printArray(int *arrayName)
{
while (*arrayName)
{
if (*arrayName == -858993460)
{
break;
}
cout << *arrayName << ' ';
*arrayName++;
}
cout << '\n';
}
After running the program a few times I realized the value after the last element of the array that I have input is always: -858993460, so I made it break the while loop once this value is encountered.
include <iostream>
include <conio.h>
using namespace std;
// functions prototypes
void printArray (int arrayName[], int lengthArray);
// global variables
//main
int main ()
{
int firstArray[] = {5, 10, 15};
int secondArray[] = {2, 4, 6, 8, 10};
printArray (firstArray,3);
printArray (secondArray,5);
// end of program
_getch();
return 0;
}
// functions definitions
void printArray(int arrayName[], int lengthArray)
{
for (int i=0; i<lengthArray; i++)
{
cout << arrayName[i] << " ";
}
cout << "\n";
}
Thank you very much.

TL;DR answer: use std::vector.
But I realized it [sizeof()] only considers its bytesize and not how many elements are on the array.
That wouldn't be a problem in itself: you could still get the size of the array using sizeof(array) / sizeof(array[0]), but the problem is that when passed to a function, arrays decay into a pointer to their first element, so all you can get is sizeof(T *) (T being the type of an element in the array).
About *arrayName++:
This has at least printed me everything but more than what I expected
I don't even understand what inspired you to calculate the size of the array in this way. All that this code does is incrementing the first object in the array until it's zero.
After running the program a few times I realized the value after the last element of the array that I have input is always: -858993460
That's a terrible assumption and it also relies on undefined behavior. You can't really be sure what's in the memory after the first element of your array, you should not even be accessing it.
Basically, in C++, if you want to know the size of a raw array from within a function, then you have to keep track of it manually (e. g. adding an extra size_t size argument), because of the way arrays are passed to functions (remember, they "decay into" a pointer). If you want something more flexible, consider using std::vector<int> (or whatever type of objects you want to store) from the C++ standard library -- it has a size() method, which does exactly what you want.

1st try
When arrays are passed into functions they decay to pointers. Normally, using sizeof on an array would give you its size in bytes which you could then divide by the size in bytes of each element and get the number of elements. But now, since you have a pointer instead of an array, calling sizeof just gives you the size of the pointer (usually 4 or 8 bytes), not the array itself and that's why this fails.
2nd try
The while loop in this example assumes that your array ends with a zero and that's very bad (unless you really did use a zero as a terminator like null-terminated strings for example do). If your array doesn't end with a zero you might be accessing memory that isn't yours and therefore invoking undefined behavior. Another thing that could happen is that your array has a zero element in the middle which would then only print the first few elements.
3rd try
This special value you found lurking at the end of your array can change any time. This value just happened to be there at this point and it might be different another time so hardcoding it like this is very dangerous because again, you could end up accessing memory that isn't yours.
Your final code
This code is correct and passing the length of the array along with the array itself is something commonly done (especially in APIs written in C). This code shouldn't cause any problems as long as you don't pass a length that's actually bigger than the real length of the array and this can happen sometimes so it is also error prone.
Another solution
Another solution would be to use std::vector, a container which along with keeping track of its size, also allows you to add as many elements as you want, i.e. the size doesn't need to be known at runtime. So you could do something like this:
#include <iostream>
#include <vector>
#include <cstddef>
void print_vec(const std::vector<int>& v)
{
std::size_t len = v.size();
for (std::size_t i = 0; i < len; ++i)
{
std::cout << v[i] << std::endl;
}
}
int main()
{
std::vector<int> elements;
elements.push_back(5);
elements.push_back(4);
elements.push_back(3);
elements.push_back(2);
elements.push_back(1);
print_vec(elements);
return 0;
}
Useful links worth checking out
Undefined behavior: Undefined, unspecified and implementation-defined behavior
Array decay: What is array decaying?
std::vector: http://en.cppreference.com/w/cpp/container/vector

As all the other answers say, you should use std::vector or, as you already did, pass the number of elements of the array to the printing function.
Another way to do is is by putting a sentinel element (a value you are sure it won't be inside the array) at the end of the array. In the printing function you then cycle through the elements and when you find the sentinel you stop.

A possible solution: you can use a template to deduce the array length:
template <typename T, int N>
int array_length(T (&array)[N]) {
return N;
}
Note that you have to do this before the array decays to a pointer, but you can use the technique directly or in a wrapper.
For example, if you don't mind rolling your own array wrapper:
template <typename T>
struct array {
T *a_;
int n_;
template <int N> array(T (&a)[N]) : a_(a), n_(N) {}
};
You can do this:
void printArray(array<int> a)
{
for (int i = 0 ; i < a.n_; ++i)
cout << a.a_[i] << ' ';
}
and call it like
int firstArray[] = {5, 10, 15};
int secondArray[] = {2, 4, 6, 8, 10};
printArray (firstArray);
printArray (secondArray);
The key is that the templated constructor isn't explicit so your array can be converted to an instance, capturing the size, before decaying to a pointer.
NB. The wrapper shown isn't suitable for owning dynamically-sized arrays, only for handling statically-sized arrays conveniently. It's also missing various operators and a default constructor, for brevity. In general, prefer std::vector or std::array instead for general use.
... OP's own attempts are completely addressed elsewhere ...

Using the -858993460 value is highly unreliable and, in fact, incorrect.
You can pass a length of array in two ways: pass an additional parameter (say size_t length) to your function, or put a special value to the end of array. The first way is preferred, but the second is used, for example, for passing strings by char*.

In C/C++ it's not possible to know the size of an array at runtime. You might consider using an std::vector class if you need that, and it has other advantages as well.

When you pass the length of the array to printArray, you can use sizeof(array) / sizeof(array[0]), which is to say the size in bytes of the whole array divided by the size in bytes of a single element gives you the size in elements of the array itself.
More to the point, in C++ you may find it to your advantage to learn about std::vector and std::array and prefer these over raw arrays—unless of course you’re doing a homework assignment that requires you to learn about raw arrays. The size() member function will give you the number of elements in a vector.

In C/C++, native arrays degrade to pointers as soon as they are passed to functions. As such, the "length" parameter has to be passed as a parameter for the function.
C++ offers the std::vector collection class. Make sure when you pass it to a function, you pass it by reference or by pointer (to avoid making a copy of the array as it's passed).
#include <vector>
#include <string>
void printArray(std::vector<std::string> &arrayName)
{
size_t length = arrayName.size();
for(size_t i = 0 ; i < length; ++i)
{
cout << arrayName[i] << ' ';
}
}
int main()
{
std::vector<std::string> arrayOfNames;
arrayOfNames.push_back(std::string("Stack"));
arrayOfNames.push_back(std::string("Overflow"));
printArray(arrayOfNames);
...
}

Related

Pointers vs vectors for arrays c++

In the case I am creating an 'array' on stack in c++, is it better to initialise an empty vector with a reserved number of elements and then pass this to a function like foo() as a reference as below. Or is it better to set an array arrb of size nelems, then using a pointer p_arrb to the address of the first element increment the pointer and assign some value?
#include <iostream>
#include <vector>
void foo(std::vector<int>& arr){
int nelems = arr.capacity();
for (int i = 0; i < nelems; i++){
arr[i] = i;
}
}
int main()
{
int nelems;
std::cout << "Type a number: "; // Type a number and press enter
std::cin >> nelems;
std::vector<int> arr;
arr.reserve(nelems); // Init std lib vector
foo(arr);
int arrb[nelems];
int* p_arrb = &(arrb[0]); // pointer to arrb
for (int i = 0; i < nelems; i ++){
*(p_arrb++) = i; // populate using pointer
}
p_arrb -= nelems; // decrement pointer
return 0;
}
It seems people prefer the use of vector as it is standardised and easier to read? Apart from that, is there any performance benefit to using vector instead of a basic pointer in this case where I do not need to change the size of my vector/array at any point in the code?
What you should use depends on the exact goal you have. In general the best approach is to avoid using "raw arrays" (both dynamic and static) wherever possible.
If you need dynamic array, use std::vector. If you need static array, use std::array.
You can't use the arrb variant because the size of an array must be a compile-time constant in C++, but you are trying to use a runtime size here.
If your compiler is compiling this, then it is doing so only because it supports these so-called variable-length arrays as a non-standard extension. Other compilers will not support them or have differing degree of support or behavior. These arrays are optionally-supported in C, but even there they are probably not worth the trouble they cause.
There is no way to allocate a runtime-dependent amount of memory on the stack in C++ (except if you misuse recursive function calls to simulate it).
So yes, you should use the vector approach. But as discussed in the comments under the question, what you are doing is wrong and causes undefined behavior. You need to either reserve memory and then emplace_back/push_back elements into the vector or you need to resize the vector to the expected size and then you may index it directly. Indexing a vector outside the the range of elements already created in it causes undefined behavior.

Is it possible to initialize a vector of strings from an array? If so, how?

So for example, on GeeksForGeeks.org, contributing user "Kartik" offers the following example for initializing a vector of integers:
// CPP program to initialize a vector from
// an array.
#include <bits/stdc++.h>
using namespace std;
int main()
{
int arr[] = { 10, 20, 30 };
int n = sizeof(arr) / sizeof(arr[0]);
vector<int> vect(arr, arr + n);
for (int x : vect)
cout << x << " ";
return 0;
}
If I understand what I'm reading correctly, sizeof(arr) is some number (which I assume is the length of the array arr; i.e. 3, please correct me if I'm wrong) divided by sizeof(arr[0]) (which I assume to be 1) -- basically just being a roundabout way of saying 3/1 = 3.
At this point, vector<int> vect(arr, arr + n) appears to be a vector of size 3, with all values initialized to arr + n (which I'm assuming is a way of saying "use the 3 items from arr to instantiate; again, please correct me if I'm wrong).
Through whatever sorcery, the output is 10 20 30.
Now, regardless of whether or not any of my above rambling is coherent or even remotely correct, my main question is this: can the same technique be used to instantiate some example vector<string> stringVector such that it would iterate through strings designated by some example string stringArray[] = { "wordA", "wordB", "wordC" }? Because, as I understand it, strings have no numeric values, so I imagine it would be difficult to just say vector<string> stringVector(stringArray, stringArray + n) without encountering some funky junk. So if it is possible, how would one go about doing it?
As a rider, why, or in what type of instance, would anyone want to do this for a vector? Does instantiating it from an array (which as I understand it has constant size) defeat the purpose of the vector?
Just as a disclaimer, I'm new to C++ and a lot of the object-oriented syntax involving stuff like std::vector<_Ty, _Alloc>::vector...etc. makes absolutely no sense to me, so I may need that explained in an answer.
To whoever reads this, thank you for taking the time. I hope you're having a good day!
Clarifications:
sizeof(arr): returns the size in bytes of the array, which is 12 because it has 3 ints, and each int in most implementations has a size of 4 bytes, so 3 bytes x 4 = 12 bytes.
sizeof(arr[0]): returns the size in bytes of the first element of the array, which is 4 because it is an int array.
vector<int> vect(arr, arr + n): the vector class has multiple constructors. Here we are not using the constructor you are thinking of. We are using a constructor that takes begin and end iterators for a range of elements, making a copy of those elements. Pointers can be used as iterators, where in this case arr is the begin iterator and arr + n is the end iterator.
Note: int* + int returns int*.
Note: We should also consider that the "end" of an array is a pointer to the next space after the last item in the array, and the constructor will copy all the items except the item past the end.
Answer:
Yes, remember that here, the constructor is taking iterators, not any item of the array, so we can do it easily like this with little changes:
#include <bits/stdc++.h>
using namespace std;
int main()
{
// changed int to string and the array values
string arr[] = { "one", "two", "three" };
int n = sizeof(arr) / sizeof(arr[0]);
// changed int to string
vector<string> vect(arr, arr + n);
// changed int to string
for (string x : vect)
cout << x << " ";
return 0;
}
sizeof(arr)
sizeof gets the size of an object in bytes. The size of an object is the total number of bytes required by the object. Note that I'm using "object" in the C++ context, not the OOP context (an instance of a class).
The size of an object of a given type is always the same. A std::string containing "a" is the same size as a string containing the unabridged text of War and Peace. Any object that appears to have a variable size really contains a reference to variable length data stored elsewhere. In the case of std::string at its most basic, it is a pointer to a dynamically allocated array and an integer keeping track of how much of the dynamically allocated array is actually in use by the string. std::vector is similar, typically it's a pointer to the start of its data, a pointer to the end of its data, and a pointer to the first empty position in the data. No matter how big the vector is, sizeof(vector) will return the size of the pointers, any other book-keeping variables in the vector implementation, and any padding needed to guarantee correct memory alignment.
This means every item in an array is always the same size and thus the same distance from one another.
Through whatever sorcery...
The above means that the total size of the array divided by the size of one element in the array, sizeof(arr) / sizeof(arr[0]), will always provide the number of elements in the array. It doesn't matter what the array contains, numerical or otherwise. There are of course prettier ways like
template <class T, size_t N>
size_t getsize (const T (&array)[N])
{
return N;
}
and later
size_t n = getsize(arr);
As a rider, why, or in what type of instance, would anyone want to do this for a vector?
In the old days one could not directly construct a vector pre-loaded with data. No one wants to write some arbitrary number of lines of push_back to pound all the values in manually, It's boring as hell, a programmer almost always has better things to do, and the odds of injecting an error are too high. But you could nicely and easily format an array and feed the array into the vector, if you needed a vector at all. A lot of the time you could live off the array by itself because the contents were unchanging or at worst would only be shuffled around.
But if the number of contents could change, it could be time for a vector. If you're going to add items and you don't know the upper limit, it's time for vector. If you're calling into an API that requires a vector, it's time for a vector.
I can't speak for everybody, but I'm going to assume that like me a lot of people would have loved to have that easy-peasy array-style initialization for vectors, lists, maps, and the rest of the usual gang.
We were forced to write programs that generated the appropriate code to fill up the vector or define an array and copy the array into the vector much like the above example.
In C++11 we got our wish with std::initialzer_list and a variety of new initialization options1 that allowed
vector<string> vect{"abc","def","ghi"};
eliminating most cases where you would find yourself copying an array into a library container. And the masses rejoiced.
This coincided with a number of tools like std::size, std::begin and std::end to make converting an array into a vector a cakewalk. Assuming you don't pass the array into a function first.
1 Unfortunately the list of initialization options can get a lil' bewildering
Yes, you can do so - you just need to define something that the constructor for String will take (which is a 'const char')
const char * arr[] = { "abc","def","ghi" };
int n = sizeof(arr) / sizeof(arr[0]);
vector<string> vect(arr, arr + n);
for (string &x : vect)
cout << x << " ";
What this is effectively doing is creating the vector from two iterators (a pointer is, loosely, an iterator):
https://en.cppreference.com/w/cpp/container/vector/vector
Constructs the container with the contents of the range [first, last).
This constructor has the same effect as vector(static_cast<size_type>(first), static_cast<value_type>(last), a) if InputIt is an integral type.
And as #MartinYork pointed out, it's much more readable to use the C++ syntax:
const char * arr[] = { "abc","def","ghi" };
vector<string> vect(std::begin(arr), std::end(arr));
So if it is possible, how would one go about doing it?
Simply use vector constructor number 5, which accepts iterators to start and end of range
Constructs the container with the contents of the range [first,
last).
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::string arr[] = { "wordA", "wordB", "wordC" };
std::vector<std::string> v {std::begin(arr), std::end(arr)};
for (auto& str : v)
std::cout << str << "\n";
return 0;
}
Here's how you'd do it. Note that it's a tad awkward to get the length of the array, but that's just because arrays don't carry that information around with them (use a vector!).
#include<string>
#include<vector>
#include<iterator>
#include<iostream>
int main()
{
std::string arr[] = {"abc", "def", "ghi"};
std::vector<std::string> tmp;
std::copy(arr, arr + sizeof(arr)/sizeof(arr[0]), std::back_inserter(tmp));
for(auto str : tmp) {
std::cout<<str<<"\n";
}
}
Update: Yes good point about using std::begin and std::end for the array.

Why do we specify arrays size as a parameter when passing to function in C++?

I searched this question, most of them says the same thing. Since we only pass the arrays address in a function, compiler can not know the arrays size by looking at the address, they say. I tried to test this by using this code, and both functions gave the same results. So, how does specifying the arrays size as a function parameter help me in a practical way?. In which conditions does specifying the size help us?.
class ArrayTest
{
public:
void say(int ar[])
{
cout<<ar[1]<<endl;
cout<<ar[7]<<endl;
}
void say(int ar[],int sizeAn)
{
cout<<ar[1]<<endl;
cout<<ar[7]<<endl;
}
};
int main()
{
ArrayTest test;
int anAr[5] = {1,2,3,4,5};
test.say(anAr);
test.say(anAr,5);
return 0;
}
This is about you as a programmer having the chance to boundary check, not whether the compiler can do it.
Just try to print out all the elements in the array, with the size:
void say(int ar[],int sizeAn)
{
for(int i=0; i< sizeAn; ++i)
cout<<ar[i]<<endl;
}
now without the size:
void say(int ar[])
{
for(int i=0; i< /*HOW DO I KNOW NOW?*/; ++i)
cout<<ar[i]<<endl;
}
Passing array size as a function parameter is a bad idea, because if you need an array as an array in function passing its size won't have any effect. The array you passed will be decayed to a pointer. So you need to maintain array as is.
Templates provide a simple and effective way to prevent array decay while passing them as function arguments.
template<std::size_t N>
void foo(int (&your_array)[N])
{
for(int i = 0; i < N; i++)
//process array, N will be your array size.
}
//simply pass array when calling the function. N be taken automatically.
//somewhere else
int main()
{
int arr[10];
foo(arr);
}
hope this helps.
Note that your code is invoking undefined behavior because you're accessing element 7 of an array that is only 5 elements big. Using the size parameter, you could for instance check if the index is past its size and not do that call instead.
In your example, you get the same results becaue you aren't actually using the parameter:
void say(int ar[],int sizeAn)
{
cout<<ar[1]<<endl;
cout<<ar[7]<<endl;
}
sizeAn is unused, so it's not making any difference. But consider for instance the following code:
void say(int ar[],int sizeAn)
{
for (int i = 0; i < sizeAn; i++){
cout<<ar[i]<<endl;
}
}
Here, it's printing all the items in the array, so it needs to know how big the array is. If you used an std::vector, for instance, you wouldn't need to pass the size as you can just call the size function, but you can't do that with C style arrays, so you need to pass that size as a parameter if you want to write a function that behaves differently depending on the size).
Or here's a more practical example of your code where the size parameter is used to avoid the undefined behavior:
void say(int ar[],int sizeAn)
{
cout<<ar[1]<<endl;
if (sizeAn >= 8){
cout<<ar[7]<<endl;
}
}
Now it's the same as your code with the change that it's only printing the element 7 if it actually exists.
As you say, compilers can't tell how big an array is if passed to a function. Your first say function tries to reference past the end of the array (ar[7] is beyond the size of 5). Your second say function means you can length check to make sure you don't make this error.
void say(int ar[], int sizeAn)
{
if(sizeAn>1)
cout<<ar[1];endl;
if(sizeAn>7)
cout<<ar[7];endl;
}
This way, YOU know the length and the function can check it before accessing invalid memory locations.
Why do we specify arrays size as a parameter when passing to function in C++?
Do we?
Well, sometimes. The canonical way to pass a range in C++ is using an iterator-pair though, even if I can see it evolve to using ranges when the Range-TS is finally used everywhere.
Anyway, there are other ways to convey what (sub-)range we want to work with. So, let's take a look:
In-band-signalling, like NUL-terminator for c-strings.
An implicit part of the functions contract, like "it will always be exactly 12 elements".
Passing a view of the part we want. Unfortunately, until the ranges-TS is fully incorporated, standard-library-support for that is severely anemic, being restricted to std::string_view in C++17 and extended with std::span for contiguous ranges (like arrays) in C++20 (look at the guideline-support-library for now).
Using an iterator-pair. The full flexibility of iterators, though calculating the length might be costly, or impossible without consuming the range. This is the preferred way in the standard-library.
Using start-iterator and length. Also quite common, but not to the same degree, and does not allow iterators determining the length as you iterate, not that that is an issue here.
Using a (constant where appropriate) reference to the whole container or range, probably templated for generality. This might be combined with point 3, but need not.
Of those, if you know the element-type, and restrict to contiguous arrays, pointer+length is the most comfortable and flexible to use for now, which does not need different code for different lengths, so that's that.

Assign a pointer to an array

I am trying to create an array that generates random values, then assign a pointer to that array in order to use it in other functions.
Question 1: Is this the right approach?
Question 2: When I run the code below, my pointer function generates values inconsistent with what the actual array's value is. What am I doing wrong?
int size = 100;
int theray[size];
for(int i=0; i<size; i++)
{
theray[i] = (rand()%100);
}
//Output array
cout<<"The array: ";
for(int j=0; j<size; j++)
{
cout<<theray[j]<<" ";
}
cout<<endl;
int (*parray)[100] = &theray;
cout<<"The array pointer: ";
for(int k=0; k<size; k++)
{
cout<<*parray[k]<<" ";
}
Question 1: is this the right approach?
No. The right approach is to use std::vector<int> if size is not known at compile time1, and std::array<int, size> if it is2. There is no need for pointers here.
void foo(const std::vector<int>& v)
{
// do stuff with v
}
...
std::vector<int> v(size); // vector with size elements
// do something with v
// pass v to a function
foo(v);
Question 2: when I run the code below, my pointer function generates values inconsistent with what the actual array's value is. What am I doing wrong?
If you use C++ idioms you won't even encounter this problem, so I consider the question moot. However, in your case you have a problem of operator precedence: be explicit about applying de-reference * before access []:
cout<< (*parray)[k] << " ";
1 As shown in the example, you can use an std::vector as a fixed size array, where the size need not be known at runtime. Just bear in mind that it is possible to change it's size after construction.
2In your example, size is not a compile time constant so you cannot use std::array. However, if you had declared it as const int size = 100; then it would be considered a compile time constant.
Your code is a bit off in three ways. First, there is no need to use &theray. Array names already reference a memory address. You can simply assign the pointer to theray. Second, you're declaring an array of 100 pointers. Based on your description, it sounds like you just want one pointer that points to the array. Your declaration should just be int *parray instead of int *parray [100]. Finally, once you have a pointer to the array, you can access elements of the array the same way you would with the original array, only with the name of the pointer, instead of the name of the array. Try changing your last block of code (starting with the pointer declaration to this:
int *parray;
parray = theray;
cout<<"The array pointer: ";
for(int k=0; k<size; k++)
{
cout<<parray[k]<<" ";
}
Question 1
Is this the right approach?
Usually not. It depends on what you are trying to achieve.
For high level semantics you'd in most cases use std::vector<int> or, if the size is fixed and you are using C++11, std::array<int, size>. If you actually have to go down to the pointer level, you'd usually write it like this:
int *parray = theray;
cout<<"The array pointer: ";
for(int k=0; k<size; k++)
{
cout<<parray[k]<<" ";
}
This works because arrays will degrade to pointers, and the […] subscripts work on these pointers just like they work on the original arrays.
Question 2
When I run the code below, my pointer function generates values inconsistent with what the actual array's value is, what am I doing wrong?
*parray[k] gets interpreted as *(parray[k]) while you intend to use it as (*parray)[k].
Question 1: is this the right approach?
No. Use std::vector<> for arrays whose size can change dynamically (at run-time). Prefer avoiding pointers and manual memory management.
Question 2: when I run the code below, my pointer function generates values inconsistent with what the actual array's value is. What am I doing wrong?
First of all, the fact of creating pointers so you can pass the array to a function. This is not necessary. Here is how I would use classes from the C++ Standard Library to write that program (in C++11):
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
// Sample function that prints the vectors's content
void foo(std::vector<int> const& v)
{
copy(begin(v), end(v), std::ostream_iterator<int>(std::cout, " "));
}
int main()
{
// Populate the vector...
size_t sz = 10;
std::vector<int> v(sz);
generate(begin(v), end(v), [] () { return rand() % 100; });
// Pass it to a function...
foo(v);
}

Element count of an array in C++

Let's say I have an array arr. When would the following not give the number of elements of the array: sizeof(arr) / sizeof(arr[0])?
I can thing of only one case: the array contains elements that are of different derived types of the type of the array.
Am I right and are there (I am almost positive there must be) other such cases?
Sorry for the trivial question, I am a Java dev and I am rather new to C++.
Thanks!
Let's say I have an array arr. When
would the following not give the
number of elements of the array:
sizeof(arr) / sizeof(arr[0])?
One thing I've often seen new programmers doing this:
void f(Sample *arr)
{
int count = sizeof(arr)/sizeof(arr[0]); //what would be count? 10?
}
Sample arr[10];
f(arr);
So new programmers think the value of count will be 10. But that's wrong.
Even this is wrong:
void g(Sample arr[]) //even more deceptive form!
{
int count = sizeof(arr)/sizeof(arr[0]); //count would not be 10
}
It's all because once you pass an array to any of these functions, it becomes pointer type, and so sizeof(arr) would give the size of pointer, not array!
EDIT:
The following is an elegant way you can pass an array to a function, without letting it to decay into pointer type:
template<size_t N>
void h(Sample (&arr)[N])
{
size_t count = N; //N is 10, so would be count!
//you can even do this now:
//size_t count = sizeof(arr)/sizeof(arr[0]); it'll return 10!
}
Sample arr[10];
h(arr); //pass : same as before!
Arrays in C++ are very different from those in Java in that they are completely unmanaged. The compiler or run-time have no idea whatsoever what size the array is.
The information is only known at compile-time if the size is defined in the declaration:
char array[256];
In this case, sizeof(array) gives you the proper size.
If you use a pointer as an array however, the "array" will just be a pointer, and sizeof will not give you any information about the actual size of the array.
STL offers a lot of templates that allow you to have arrays, some of them with size information, some of them with variable sizes, and most of them with good accessors and bounds checking.
There are no cases where, given an array arr, that the value of sizeof(arr) / sizeof(arr[0]) is not the count of elements, by the definition of array and sizeof.
In fact, it's even directly mentioned (§5.3.3/2):
.... When applied to an array, the result is the total number of bytes in the array. This implies that the size of an array of n elements is n times the size of an element.
Emphasis mine. Divide by the size of an element, sizeof(arr[0]), to obtain n.
Since C++17 you can also use the standardized free function:
std::size(container) which will return the amount of elements in that container.
example:
std::vector<int> vec = { 1, 2, 3, 4, 8 };
std::cout << std::size(vec) << "\n\n"; // 5
int A[] = {40,10,20};
std::cout << std::size(A) << '\n'; // 3
No that would still produce the right value because you must define the array to be either all elements of a single type or pointers to a type. In either case the array size is known at compile time so sizeof(arr) / sizeof(arr[0]) always returns the element count.
Here is an example of how to use this correctly:
int nonDynamicArray[ 4 ];
#define nonDynamicArrayElementCount ( sizeof(nonDynamicArray) / sizeof(nonDynamicArray[ 0 ]) )
I'll go one further here to show when to use this properly. You won't use it very often. It is primarily useful when you want to define an array specifically so you can add elements to it without changing a lot of code later. It is a construct that is primarily useful for maintenance. The canonical example (when I think about it anyway ;-) is building a table of commands for some program that you intend to add more commands to later. In this example to maintain/improve your program all you need to do is add another command to the array and then add the command handler:
char *commands[] = { // <--- note intentional lack of explicit array size
"open",
"close",
"abort",
"crash"
};
#define kCommandsCount ( sizeof(commands) / sizeof(commands[ 0 ]) )
void processCommand( char *command ) {
int i;
for ( i = 0; i < kCommandsCount; ++i ) {
// if command == commands[ i ] do something (be sure to compare full string)
}
}
_countof(my_array) in MSVC
I can thing of only one case: the array contains elements that are of different derived types of the type of the array.
Elements of an array in C++ are objects, not pointers, so you cannot have derived type object as an element.
And like mentioned above, sizeof(my_array) (like _countof() as well) will work just in the scope of array definition.
It seems that if you know the type of elements in the array you can also use that to your advantage with sizeof.
int numList[] = { 0, 1, 2, 3, 4 };
cout << sizeof(numList) / sizeof(int);
// => 5
First off, you can circumvent that problem by using std::vector instead of an array. Second, if you put objects of a derived class into an array of a super class, you will experience slicing, but the good news is, your formula will work. Polymorphic collections in C++ are achieved using pointers. There are three major options here:
normal pointers
a collection of boost::shared_ptr
a Boost.Pointer Container
Let's say I have an array arr. When would the following not give the number of elements of the array: sizeof(arr) / sizeof(arr[0])?
In contexts where arr is not actually the array (but instead a pointer to the initial element). Other answers explain how this happens.
I can thing of only one case: the array contains elements that are of different derived types of the type of the array.
This cannot happen (for, fundamentally, the same reason that Java arrays don't play nicely with generics). The array is statically typed; it reserves "slots" of memory that are sized for a specific type (the base type).
Sorry for the trivial question, I am a Java dev and I am rather new to C++.
C++ arrays are not first-class objects. You can use boost::array to make them behave more like Java arrays, but keep in mind that you will still have value semantics rather than reference semantics, just like with everything else. (In particular, this means that you cannot really declare a variable of type analogous to Foo[] in Java, nor replace an array with another one of a different size; the array size is a part of the type.) Use .size() with this class where you would use .length in Java. (It also supplies iterators that provide the usual interface for C++ iterators.)
Use the Microsoft "_countof(array)" Macro. This link to the Microsoft Developer Network explains it and offers an example that demonstrates the difference between "sizeof(array)" and the "_countof(array)" macro.
Microsoft and the "_countof(array)" Macro
If you can not use C++17, which allows to use std::size(container), you can easily implement your own generic sizeofArray template function as a one-liner:
#include <cstddef>
#include <cstdio>
template< typename T, std::size_t N >
inline constexpr std::size_t sizeofArray( const T(&)[N] ) noexcept { return N; }
int x[10];
void* y[100];
long z[1000];
struct {int x; char y; long z;} s[123];
static_assert( sizeofArray(x) == 10, "error" );
static_assert( sizeofArray(y) == 100, "error" );
static_assert( sizeofArray(z) == 1000, "error" );
static_assert( sizeofArray(s) == 123, "error" );
int main() {
puts( "ok" );
}
test it here: http://cpp.sh/8tio3
It will work if and only if arr is a C-Array (type[size]; except for function parameters!), a reference to a C-Array (type(&)[size]) or a pointer to a C-Array (type(*)[size]).
Note you should use std::size or std::ssize instead with current C++-Standards!
In C++17 you can use std::size:
int arr[] = {1, 2, 3};
auto count = std::size(arr); // type std::size_t, value == 3
In C++20 you can additionally get a signed value by using std::ssize:
int arr[] = {1, 2, 3};
auto count = std::ssize(arr); // type std::ptrdiff_t, value == 3
https://en.cppreference.com/w/cpp/iterator/size
Also note that C++ unfortunately inherited from C that C-Arrays are never passed by value (deep copy) to functions.
void f(int a[3]);
is the same as
void f(int* a);
so you loose the information that a is an array and with this, how much elements it had. The 3 is completely ignored by the compiler!
If you want to preserve the datatype (including the array element count), you can use a pointer or a reference to an C-Array:
void f(int (&a)[3]); // reference to C-Array with 3 elements
void f(int (*a)[3]); // pointer to C-Array with 3 elements
void f(int a[3]); // pointer to int
void f(int* a); // pointer to int
If you want to call functions with Arrays call-by-value, you can use C++-Arrays (std::array) from the C++ standard library:
f(std::array<int, 3> a);
std::array<int, 3> arr = {1, 2, 3};
f(arr); // deep copy
https://en.cppreference.com/w/cpp/container/array
Determine how many numbers are in your array.
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n[10] ;
int l = sizeof(n)/sizeof(n[0]);
cout << l;
return 0;
}
I know is old topic but what about simple solution like while loop?
int function count(array[]) {
int i = 0;
while(array[i] != NULL) {
i++;
}
return i;
}
I know that is slower than sizeof() but this is another example of array count.