Question
I do not want to pass the size of the array as an index parameter.
For my merge_sort, I want to optimize my parameters using the iterator range concept. I can't seem to figure out how to deference the iterator range and access my array. I can deference to access the indices like low and high in recursive_merge_sort, but there does not seem to be an intuitive way to access the array itself. I've been using this great guide on C++ Pointers and Arrays as a starting point.
My Merge Sort C++11 C++17 question brought this concept to light and I like the idea of using iterator ranges to reduce the number of parameters for my sort.
Code
void recursive_merge_sort(int* low, int* high) {
// deference to get starting index "low" and ending index "high"
if(*(low) >= *(high) - 1) { return; }
int mid = *(low) + (*(high) - *(low))/2;
// what's the correct syntax to access my array from the iterator range
// int* d = some how deference low or how to get the data array they iterate on
recursive_merge_sort_v(d + low, d + mid);
recursive_merge_sort_v(d + mid, d + high);
merge(d + low, mid, d + high);
// delete d;
}
void merge_sort(int* data) {
// what's the correct syntax to access my array from the passed in iterator range
// is this event possible? incorrect syntax below
recursive_merge_sort(data + 0, data + std::size(*(data)));
}
int main()
{
int data[] = { 5, 1, 4, 3, 65, 6, 128, 9, 0 };
int num_elements = std::size(data);
std::cout << "unsorted\n";
for(int i=0; i < num_elements; ++i) {
std::cout << data[i] << " ";
}
merge_sort(data);
std::cout << "\nsorted\n";
for(int i=0; i < num_elements; ++i) {
std::cout << data[i] << " ";
}
}
Comment section Solution from the bayou
Remy Lebeau: "When you pass an array by pointer, you lose all information about it. You can't get back to the original array given only a pointer/iterator, as dereferencing will only give you a single element of the array, not the array itself. When passing an array by pointer, you have no choice but to pass the array size as another parameter. Otherwise, pass the array by reference instead, and if you need to support arrays of different sizes then use a template so the compiler can deduce the array size for the reference."
Iterators are modeled to act like pointers. They have the same type of overloaded operators: dereferencing and increment at the very least (some also have decrement, random access, etc.).
The most advanced iterator interface is random access, which functions exactly like a raw pointer (by design).
So all (raw) pointers are basically random access iterators into a C-style (contiguous) array. Look at the following to visualize begin/end iterators for a C-style array:
int vals[] = { 0, 1, 2, 3, 4 };
int *begin = vals;
int *end = vals + 5;
v vals[]
0 1 2 3 4 ...
^ begin ^ end (1 past the end of array)
vals[2] == begin[2]
vals[4] == begin[4]
etc.
So basically, you just treat the begin iterator as the front of the array, and you just don't dereference anywhere before the begin iterator, nor at or past the end iterator, as standard C++ convention dictates the end iterator is 1 past the end of the range.
Here's an example of using pointers like iterators:
void print(int *begin, int *end)
{
// for each element in the range (starting at begin, up to but not including end)
for (; begin != end; ++begin)
{
// print the element
std::cout << *begin << '\n';
}
}
int main()
{
// declare a C-style array
int arr[] = { 10, 5, 2, 6, 20 };
// for the sake of example, print only the middle 3 elements
// begin = arr + 1
// end = arr + 4
print(arr + 1, arr + 4);
return 0;
}
I have an array initialized to 17 that is storing a certain number of elements. The issue is that when I try to find the size using the sizeof() method or a loop and counter for each element, I get 17, but that is not the number of elements stored in the array, just the size. Does anyone know how to find the actual number of elements in an array, not just its initialized size?
The code I have tried so far:
Method 1:
int arr[17];
//after reading in the data from the file
cout << sizeof(arr)/sizeof(arr[0])<< endl;
//this just prints 17
Method 2:
int arr[17]
int counter = 0;
for (int i: arr)
{
counter++;
}
cout << counter << endl;
//just prints 17
sizeof() is evaluated at compile-time, not at runtime. Taking the size of a fixed array will be a constant value, regardless of how many values you store in it.
You have three options:
define a sentry value that will never appear in the actual data, pre-fill the array with that value, and then count the number of elements that do not equal that value:
#include <algorithm>
bool isNotSentry(int value) { return (value != -1); }
...
int arr[17];
std::fill(arr, arr+17, -1);
...
//when adding a value to the array...
arr[index] = ...;
...
//after reading in the values from the file
int count = std::count_if(arr, arr+17, isNotSentry);
std::cout << count << std::endl;
Or, if using C++11 or later:
#include <array>
std::array<int, 17> arr;
arr.fill(-1);
...
//when adding a value to the array...
arr[index] = ...;
...
//after reading in the values from the file
int count = std::count_if(arr.cbegin(), arr.cend(), [](const int value){ return (value != -1); });
std::cout << count << std::endl;
manually keep track of how many values you put in the array:
int arr[17];
int count = 0;
...
//when adding a value to the array...
arr[count++] = ...;
...
//after reading in the values from the file
std::cout << count << endl;
The above approaches assume the data will never be more than 17 values max. But if you don't know up front how many values may actually be present, then simply don't use a fixed length array to begin with. Use a std::vector instead, which resizes itself dynamically as needed:
#include <vector>
std::vector<int> arr;
arr.reserve(17); // <-- optional
...
//when adding a value to the vector...
arr.push_back(...);
...
//after reading in the values from the file
std::cout << arr.size() << std::endl;
Is there? for example:
unsigned long long myarray[4];
myarray <<= (8*sizeof(unsigned long long));
myarray[3] = my_new_value_at_front;
would be equivalent to:
unsigned long long myarray[4];
myarray[0] = myarray[1];
myarray[1] = myarray[2];
myarray[2] = myarray[3];
myarray[3] = 0;
myarray[3] = my_new_value_at_front;
if not are there any containers which support a constant N elements and when you push a new one at [N-1] then everithing will be shifted?
No. There is not. But I can recommend something better. Try std::deque.
std::deque<unsigned long long> mydeque {0, 1, 2, 3};
for (const auto& x : mydeque )
std::cout << x << " ";
std::cout << std::endl;
mydeque.pop_front();
mydeque.push_back(4);
for (const auto& x : mydeque )
std::cout << x << " ";
std::cout << std::endl;
With std::deque, you can use memeber function pop_front to remove the first element, and push_back to insert at the back.
There's no operator but you can do:
std::rotate(myarray, myarray + N, myarray + 4);
where N is the index of the element that should be moved to the start, and the other arguments are the begin and end. You could overwrite later elements afterwards if you wanted.
In your case:
std::rotate(myarray, myarray + 1, myarray + 4);
myarray[3] = my_new_value_at_front;
This is not possible with naked arrays but considering you are using an integral type you can use std::valarray which includes shift and circular shift functions that should meet your requirements. It provides random access much like a naked array but with additional functionality thrown in.
I'm trying to write a function that will print out the contents of a multidimensional array. I know the size of the columns, but not the size of the rows.
EDIT: Since I didn't make this clear, the arrays passed to this function are NOT dynamically allocated. The sizes are known at compile time.
I am testing it using a 3x2 array. Here is the function as it stands:
void printArrays(int array1[][2], int array2[][2]) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
cout << "\narray1[" << i << "][" << j << "] = "
<< setfill('0') << setw(2) << array1[i][j]
<< "\tarray2[" << i << "][" << j << "] = "
<< setfill('0') << setw(2) << array2[i][j];
}
}
}
Obviously, this only works if I know the size of "i" is 3 (it is in this case). Ideally, however, I would like the function to work no matter what the size of the first dimension.
I thought I would be able to do this using the sizeof() function, e.g.
int size = sizeof(array1);
... and do some math from there.
Here's the odd part. If I use the sizeof() function inside the array, it returns a value of 4. I can use pointer notation to dereference the array:
int size = sizeof(*array1);
... but this actually returns a value of 8. This is odd, because the total size should be rows(which = 3) * columns(= 2) * sizeof(int)(= 4), or 24. And, indeed, this is the result, when I use sizeof(*array1) outside of the function.
Does anyone know what is going on here? More importantly, does anyone have a solution?
The answer is that you can not do this. You must pass the number of rows as an argument to the function, or use an STL container such as std::vector or std::array.
sizeof is computed compile time; sizeof is never useful in determining dynamic size of objects in C/C++. You (yourself, the programmer) can always calculate sizeof(x) just from looking at code and header files since sizeof counts the number of bytes used to represent the object. sizeof(*array1) will always be 8 since array1[i] is an array of two ints and 4==sizeof(int). When you declare int array1[][2] this is equivalent to int *array1[2]. That is, array1 is a pointer to arrays of two integers. sizeof(array1) is therefore 4 bytes, since it takes 4 bytes on your machine to represent a pointer.
You can accomplish this, to some degree, by using templated functions. The caveats are:
You will need to include the function definition (not just declaration) anywhere it is used
It will only work when array size is fixed at compile time
You will generate a separate function for every call to the function, resulting in some code bloat
I am working form the code on this blog post by Kevin Heifner.
template <typename T>
struct array_info
{
};
template <typename T, size_t N, size_t M>
struct array_info<T[N][M]>
{
typedef T type;
enum { size1 = N, size2 = M };
};
template <typename A1>
void printArrays(A1 array1, A1 array2) {
size_t A1_i = array_info<A1>::size1;
size_t A1_j = array_info<A1>::size2;
for (size_t i = 0; i < A1_i; i++) {
for (size_t j = 0; j < A1_j; j++) {
cout << "\narray1[" << i << "][" << j << "] = "
<< setfill('0') << setw(2) << array1[i][j]
<< "\tarray2[" << i << "][" << j << "] = "
<< setfill('0') << setw(2) << array2[i][j];
}
}
}
You can get the size of both arrays with some template magic:
template< typename T, std::size_t n, std::size_t m >
void foo( T(&)[n][m] ) {
std::cout << n << " " << m << std::endl;
}
int main() {
int a[3][3];
int b[2][5];
foo(a); foo(b);
}
This only works for arrays whose bounds are known at compile time and not for dynamically allocated arrays.
In any case: You should use std::vector or boost::multiarray.
The size is 8 outside the function because you're dereferencing the first array, which gives you the column size (2) times the size of an int (4). If you wanted 24, you'd do sizeof(array) (outside the function). The answer is 4 inside the function because it treats array like a pointer, the size of which is 4 bytes.
However, to reliably get the size of arrays that have been passed to functions, you either have to pass the size or use something like vector.
A very simple way to do it, without needing vectors, templates, classes, or passing the size of the array, is to have a last row of data that contains something unique such as the following example, where a -1 is used in the last row, first column:
#define DATA_WIDTH 7
const float block10g[][DATA_WIDTH] = {
{0, 15, 25, 50, 75, 100, 125},
{2.12, 0, 1.000269, 3.000807, 4.24114056, 5.28142032, 6.001614},
{6.36, 0, 1.2003228, 3.84103296, 6.24167856, 8.16219504, 10.08271152},
{10.6, 0, 1.2003228, 4.4011836, 7.2019368, 9.2024748, 11.8031742},
{21.2, 0, 2.000538, 6.001614, 8.002152, 10.4027976, 14.4038736},
{ -1}
};
const float block10g[][DATA_WIDTH] = {
{0, 20, 50, 100, 150, 200, 250},
{2.12, 0, 2.88077472, 5.04135576, 5.84157096, 6.08163552, 5.84157096},
{6.36, 0, 3.84103296, 7.92213048, 11.52309888, 13.56364764, 14.4038736},
{10.6, 0, 3.8010222, 8.8023672, 13.003497, 16.4044116, 18.4049496},
{21.2, 0, 4.4011836, 9.2024748, 14.003766, 18.4049496, 22.4060256},
{ -1}
};
printArrays(block10g,block20g);
Then just break out of the loop(s) when you reach that unique value:
void printArrays(float array1[][DATA_WIDTH], float array2[][DATA_WIDTH]) {
for (int i = 0; array1[i][0]!=-1 && array2[i][0]!=-1 ; i++) {
for (int j = 0; j < DATA_WIDTH; j++) {
cout << "\narray1[" << i << "][" << j << "] = "
<< array1[i][j]
<< "\tarray2[" << i << "][" << j << "] = "
<< array2[i][j];
}
}
}
Simply use better arrays!
What I mean by that is you can make your own array class which wraps an array, or use some common libraries with such classes (e.g. boost). This is much more reliable, and likely is easier to reason about that straight-up C++ arrays.
One reason for this is if your write the function
void foo( int a[][2] )
{
// etc.
}
you don't actually have as many guarantees on the array as you might think. For example, it is not guaranteed that the second dimension of the array is two elements wide (I could be wrong about this point, as I don't have references on hand, but I'm pretty confident about it). This is because that actual signature for the function is
void foo( int ** );
This is because arrays degenerate to pointers when used in function declarations (which is why you're sizeof(array) returns 4, since 4 bytes is the size of a pointer type on your machine). Also, you clearly have no guarantee on the size of the first dimension, so assuming it is going to be 3 is dangerous, and potentially the result of confusing bugs in the future.
This is where a custom array class would be great, especially if it were templated. For example, a two dimensional array class could be declared like
template<typename T, int length1, int length2>
class Array2D
{
// Array2D's gutsy stuff to make it act kind of like T[length1][length2]
};
Using such an approach allows you to maintain all the information about the array in any situation, e.g.
void foo( Array2D<int, 3, 2> &array ) {}
Now you can decide the sizes every dimension in the array.
An added benefit, is that you can add bounds checking to your Array2D class, which C++ array do not have. E.g. in a 3x2 array, you are able to access the fourth element in the first row, even though it's not conceptually valid. Such a common source of bugs can easily be eradicated by using an array class like Array2D.
There are some drawbacks, which is normal when using templates. The big one is that, because of the way template are instantiated, you have to define any templated classes in your header files, not in separate source files (technically, you can use the "export" keyword to do split the class up as normal, but this has limited support on major compilers).
As a last note (if you're interested, as I am), the situation becomes even better in C++0x (comming soon!) with the advent of variadic templates:
template<typenameT, int... lengths>
class Array
{
// etc...
};
Now all array types can be defined by a single class template. Never been easier.
For a 4-D array, I'm trying to average the values using compact pointer notation. Using examples from my text, it says I can use something like this:
void DisplayAverage(double (*set)[DIM1][DIM2][DIM3])
double *ptr;
double subTotal2 = 0;
for (ptr = (double *)set; ptr < (double *)set + DIM0 * DIM1 * DIM2 * DIM3; ptr++) {
subTotal2 += *ptr;
subTotal2 /= (DIM0 * DIM1 * DIM2 * DIM3);
cout << "Using compact pointer operations, total: " << subTotal2 << "\n";
}
}
That code works. However, if I try to use another notation from the text:
for (ptr = (double *)set; ptr < (double *)(&set + 1); ptr++) {
to access the array, I get no output. Any thoughts? Thanks.
You have one address-of too much:
// notice: "set" instead of "&set"
for (ptr = (double *)set; ptr < (double *)(set + DIM0); ptr++) {
You were adding one to the address of your parameter (and thus were pointing to nowhereland), instead of DIM0 to the value of your parameter (which will bring you to after the array data, which is your goal).
Notice that the parameter is a pointer to an array of dimensions [DIM1][DIM2][DIM3]. In other words, the argument you pass to the function can be an array of type double[DIM0][DIM1][DIM2][DIM3], which will decay to the pointer type of that parameter. You have DIM0 rows, so you add DIM0 to that pointer to reach the position after the last cell.
What you were probably having in mind was adding one to the pointer to the whole array. This will work if you have the following declaration, instead.
void DisplayAverage(double (*set)[DIM0][DIM1][DIM2][DIM3]);
You now need to pass the argument using &arg instead of just arg, to actually pass the address of the array, instead of letting it decay to its inner dimension type. The loop can then be written as
for (ptr = (double *)set; ptr < (double *)(set + 1); ptr++) {
Your expression (&set + 1) would point to one-past the array if set was an array, but it's not. The variable set is a pointer in disguise (not an array), as are all arrays that look like they were passed by value.
Better example of this:
void g(int a[3]);
// exactly the same as:
void g(int* a);
// note the 3 is ignored by the compiler here! it serves as documentation when
// reading the code, but nothing else, and for this reason you should pretty much
// always drop it, preferring:
void g(int a[]); /*or*/ void g(int* a); // (which are also identical)
void f() {
int a[3] = {0, 1, 2};
int* end = (int*)(&a + 1); // &a has type int (*)[3] (that's pointer to array
// of 3 ints so &a + 1 has the same value as &a[2] + 1 ("one past" the last
// valid item in a)
int* p = a; // this is how a is passed "by value" to a function such as g
end = (int*)(&p + 1); // even though this "looks" the same, &p has type int**
// and adding 1 to that has no correlation with what p points to.
// to make matters worse, the cast (and C++-style casts have the same problem
// here) hides this type error and makes the compiler believe we know what
// we're doing
// pointers are not arrays, even though they mostly behave similarly:
std::cout << sizeof(a) << ", " << sizeof(p) << ", " << sizeof(void*) << '\n';
// compare the int* size to void* size
}
And example applying it to pointers-to-arrays:
typedef int T[3];
void g(T a[3]);
// same as:
void g(T a[]); /*and*/ void g(T* a);
// that T happens to be an array type doesn't change anything, these are
// also declaring the same function:
void g(int a[][3]); /*and*/ void g(int (*a)[3]);
void f() {
int a[3][3] = {};
int* end = (int*)(&a + 1);
// note that end - &a[0][0] is 9
int* p = &a[0][0];
std::cout << sizeof(a) << ", " << sizeof(p) << ", " << sizeof(void*) << '\n';
}
I would recommend against using static multidimensional arrays in C++. See my response in How to initialize 3D array in C++