Iterating over multi-dimensional arrays - c++

Suppose I want to do something for every number in a multi-dimensional array. I've found that you can get a pointer for the first number and then use use pointer addition. For example, the following code prints the numbers 1 through 12:
double a[2][3][2] = {{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}};
double *p = &a[0][0][0];
for (int i = 0; i < 12; i++)
cout << *(p + i) << endl;
Is it unidiomatic to consider a multi-dimensional array as being flat in this way? If so, what is the preferred way of doing it? Also, is there a simpler way to write double *p = &a[0][0][0]; to get a pointer for the first number in a multi-dimensional array (in the same way that you can just write double *p = a; for a one-dimensional array)?

Yes, a multidimensional array is guaranteed to be flat. However, it may be best to kind this sort of thing. If you want to flatwise iterate over a multidimensional array, I think it'd be better to introduce a range view into it:
template <typename T>
struct Flat {
auto begin() { return first(arr); }
auto end() {
return begin() + sizeof(arr)/sizeof(*begin());
}
template <typename X> X* first(X& val) { return &val; }
template <typename X, size_t N> auto first(X(&val)[N]) { return first(*val); }
T& arr;
};
template <typename T>
Flat<T> flatten(T& arr) {
return Flat<T>{arr};
}
And simply use that one:
for (double d : flatten(a)) {
std::cout << d << std::endl;
}
Otherwise, the only other way of declaring p is something like double *p = &***a; I'm not sure if becoming a three star programmer is high on your life achievement list.

While it can be very useful to know that a multidimensional array is actually flat, it would usually be unidiomatic to refer to it using pointers and pointer arithmetic, because it introduces more potential for error and is harder to read than the idiomatic solution, subscript notation. Because of that, I would recommend using this:
double a[2][3][2] = {{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}};
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 2; k++)
{
cout << a[i][j][k] << endl;
}
}
}

Yes, a multi-dimensional array can always be treated as flat. Also, same as a one dimensional array you can say double *p = reinterpret_cast<double*>(a) which is the same as double *p = &a[0][0][0].
A multi-dimensional array, if dynamically allocated, may not be flat. But then that would be obvious as the allocation will be done by you.

Related

How to safely insert an element into an array c++?

I have a simple program to add an element to an array:
void printArray(int inp[], int size)
{
cout << "[";
for (int i = 0; i < size - 1; i++)
{
cout << inp[i] << ", ";
}
cout << inp[size - 1] << "]" << endl;
}
int addElement(int inputArray[], int inputSize, int element, int atIndex)
{
int cur = inputSize;
while (cur >= 0)
{
if (cur == atIndex)
{
inputArray[cur] = element;
return inputSize + 1;
}
inputArray[cur] = inputArray[cur - 1];
cur--;
}
return inputSize + 1;
}
int arr1[] = {1, 5, 9, 2};
int arr2[] = {1, 5, 9, 2};
int main()
{
int arraySize = sizeof(arr1) / sizeof(arr1[0]);
addElement(arr1, arraySize, 7, 0);
printArray(arr1, arraySize + 1);
printArray(arr2, arraySize);
return 0;
}
This outputs:
[7, 1, 5, 9, 2] [2, 5, 9, 2]
Even though I haven't touched arr2 it is modified. I think because arr1 and arr2 are allocated contiguously in memory, and naively adding an element to arr1 overwrites arr2[0].
How should I handle this case and add only if the next space is unused, otherwise move the entire array to another location?
You can achieve this easily by using std::vector.
It has a method called insert, where you just pass a position and a number as arguments and it will handle the reallocation by itself.
For example: if you write:
vector<int> vec = { 1, 2, 3, 4, 5 };
vec.insert(vec.begin() + 2, 100);
Now elements in your vector are 1, 2, 100, 3, 4, 5.
I don't know if this will help you, but you can also add multiple elements at once:
vector<int> vec = { 1, 2, 3, 4, 5 };
vec.insert(vec.begin() + 3, { 100, 101 });
Now elements in your vector are: 1, 2, 3, 100, 101, 4, 5.
As you can see, the first argument is the position of the first inserted element and the second one is element or list of elements that you want to insert.
You can read more about std::vector here and about std::vector::insert here
Hope this helps.
As what the comments mentioned by #StoryTeller, you can use a std::vector.
But you have to pick on which function of the container you wanna use, there are 2 types.
::insert, which inserts data on the specific location in the
container. This is iterator based.
::push_back, which inserts at the back/last of the container
You can use any of them, depending on your purpose, just be sure of ::insert that you are pointing to the correct position(iterator wise).
Also, as of C++11 you can use ::emplace and ::emplace_back, which constructs and inserts data. You can find more at,
http://www.cplusplus.com/reference/vector/vector/
Hope this helps.
I have a simple program to add an element to an array:
Impossible. An array's size is fixed at compile time. In other words,
int arr1[] = {1, 5, 9, 2};
is a lot like:
int arr1_1 = 1;
int arr1_2 = 5;
int arr1_3 = 9;
int arr1_4 = 2;
I think it is helpful, for learning purposes, to view an array like this, and not like a container which can shrink and grow while the program is running. Adding an element to an array at runtime would be like asking to add a variable at runtime. C++ arrays don't work like that.
You can use new[] to set an array's initial size at runtime, but even then you cannot "add" anything. In fact, don't use new[], ever.
Go to cppreference.com, learn about std::vector and relearn everything from scratch. Start with the example code at the bottom of the page.

Create a two 2d array of pointers based on the same data

I was trying create a 2d array of pointers based on other. Here is a base 2d array:
double **a = new double*[3];
a[0] = new double[3]{ 1, 2, 3 };
a[1] = new double[3]{ 4, 5, 6 };
a[2] = new double[3]{ 7, 8, 9 };
And I want create a 2x2 matrix which should look like this:
5,6
8,9
Finally, I was trying resolve the problem as follow:
double **b = &a[1];
b[0] = a[1];
b[1] = a[2];
Unfortunately, this code does not work as I expect. In addition, I would like to get access to data using negative indices eg. b[-1][-1] should return 1 value.
With:
double a0[] = { 1, 2, 3 };
double a1[] = { 4, 5, 6 };
double a2[] = { 7, 8, 9 };
double* b0[3] = {&a0[1], &a1[1], &a2[1]};
double** b = &b0[1];
you can access with negative index and do:
for (int i = -1; i != 2; ++i) {
for (int j = -1; j != 2; ++j) {
std::cout << b[i][j] << std::endl;
}
}
This approach cannot work. One property of this kind of 2d array is that &A[k+1] = &A[k]+1, but that relationship does not hold between your desired B[0] and B[1], because those are actually &A[1][1] and &A[2][1], which could be miles apart.
What your code actually does is:
double **b = &a[1]; // all right, b points to part of a[]
b[0] = a[1]; // this assignment does nothing, they're already equal
b[1] = a[2]; // this assignment does nothing, they're already equal
This might help you out some and get you on the right track.
#include <conio.h>
#include <iostream>
struct Vec3 {
union {
double d3[3];
struct {
double x;
double y;
double z;
};
};
double& operator[]( int idx );
};
double& Vec3::operator[]( int idx ) {
return d3[idx];
}
typedef Vec3 Row;
struct Matrix {
union {
Row r[3];
struct {
Row row1;
Row row2;
Row row3;
};
};
Row& operator[]( int idx );
};
Row& Matrix::operator[]( int idx ) {
return r[idx];
}
int main() {
Matrix m;
m.row1.x = 1;
m.row1.y = 2;
m.row1.z = 3;
m.row2.x = 4;
m.row2.y = 5;
m.row2.z = 6;
m.row3.x = 7;
m.row3.y = 8;
m.row3.z = 9;
for ( int i = 0; i < 3; i++ ) {
for ( int j = 0; j < 3; j++ ) {
m[i][j] += 10;
std::cout << m[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << "Press any key to quit" << std::endl;
_getch();
return 0;
}
I did not add any error checking or bounds checking into the overloaded operator I just allowed the user to pass any value into it. This you would have to design to your specific needs. I'm just demonstrating an easy way to create a 2D Array or a Matrix like object using unions to have quick access to the subscript or bracket operator. I show a sample use of creating a 3x3 matrix with each value ranging from 1-9 then I use a double for loop to add 10 to each value then print out the new value within the array using the double brackets. This is all done on the stack which is better then using pointers and creating new memory for each place. If you need to use the heap then you could just assign this matrix class its own pointer and create it on the heap instead of every individual element. Another thing that can be done with this is if you need to use this for say int, float or some other data type you can easily template this class or structure.
As for indexing by a negative value; I have not heard of anyone doing so. This isn't to say that it can not be done, but from what I recall on how pointers & arrays behave with indexing according to their association with memory addressing they are 0 based index. This usually means that if we have a memory block a pointer to a double type variable, this usually means that each block of memory in most cases is 8 bytes wide. The very first element resides in the very first memory address location that is assigned to this variable for both the stack and the heap. If you try to use negative numbers which involve pointer arithmetic you begin to traverse memory that doesn't belong to this declared variable. To try and pull off what you are suggesting might require more than just basic C/C++ code can do, you might have to dive into asm to get something like this to work, especially if you want to avoid using if statements within the overloaded operators.

Sorting one array based on another in place [duplicate]

This question already has answers here:
Sorting zipped (locked) containers in C++ using boost or the STL
(5 answers)
Closed 7 years ago.
I'm coding in C++ (with c++11 standards) and I have two big arrays of built-in type that I want to sort the second one based on the first.
here is an example:
A = {1, 5, 4, 3, 6, 2};
B = {1, 2, 3, 4, 5, 6};
after sorting:
A = {1, 2, 3, 4, 5, 6};
B = {1, 6, 4, 3, 2, 5};
It's as if each element B[i] is attached to element A[i] and you just sort array A. So elements in B move according the corresponding element in A. I know this questions has been asked over and over, yet the only solution I've come across with is to use pair<type 1, type 2>. But considering the arrays are big, it takes quite a while to allocate the memory for pairs array and copy arrays back and forth.
But I believe the sorting can be done in-place, i.e., using only O(1) memory. In fact if std::sort allowed for costume swap it would have been fine. Because I assume that's the only thing beyond comparator that sorting algorithms use.
A = vector<double>(1e6); // some random numbers
B = vector<double>(1e6); // some random numbers
Comp comp(&A,&B);
Swap swap(&A,&B);
costume_sort(A,B,comp,swap); // some sort function that can take costume swap and compare
class Comp {
vector<double> *A;
vector<double> *B;
Comp(vector<double> *A, vector<double> *B) : A(A),B(B) {};
bool compareTo(size_t i, size_t j) { return A->at(i) < A->at(j); };
};
class Swap {
vector<double> *A;
vector<double> *B;
Swap(vector<double> *A, vector<double> *B) : A(A),B(B) {};
void swapFnc(size_t i, size_t j) { swap(A->at(i), A->at(j));swap(B->at(i), B->at(j)); };
};
Is there any function in STL or other libraries available that can do that? This is a sort of pseudo-code of the idea I'm trying to explain here. Obviously it's not precise but I hope it's clear what I mean.
You can sort based on indices similar to the related post: std::sort and custom swap function.
It is not a custom swap function and allocateds some more memory, but should perform well.
If you are defining the types, then you can overload std::swap to do what you want: How to overload std::swap().
No there is not an std:: function that meets your requirements.
Although it's possible to provide its custom comparison (so Q&A) and swap (so Q&A) functor, those take a (constant) reference to the items to compare or swap, not an index on an hypothetical container. Indeed those functors should have meaning for comparisons and swaps of non-contained objects.
Example of reorder a[] and b[] in place according to a sorted array of pointers to a[]. Since an array of pointers is used, the compare function only needs to know the type of elements being compared. The reorder in place code time complexity is O(n), every store places a value in its sorted location. Note that the array of pointers is restored to it's original state (&a[0] ... &a[n-1]) during the reorder.
bool compare(const int *p0, const int *p1)
{
return *p0 < *p1;
}
int main()
{
int a[8] = {7,5,0,6,4,2,3,1};
char b[8] = {'h','f','a','g','e','c','d','b'};
int *pa[8];
size_t i, j, k;
int ta;
char tb;
// create array of pointers to a[]
for(i = 0; i < sizeof(a)/sizeof(a[0]); i++)
pa[i] = &a[i];
// sort array of pointers to a[]
std::sort(pa, pa+sizeof(a)/sizeof(a[0]), compare);
// reorder a[] and b[] according to the array of pointers to a[]
for(i = 0; i < sizeof(a)/sizeof(a[0]); i++){
if(i != pa[i]-a){
ta = a[i];
tb = b[i];
k = i;
while(i != (j = pa[k]-a)){
a[k] = a[j];
b[k] = b[j];
pa[k] = &a[k];
k = j;
}
a[k] = ta;
b[k] = tb;
pa[k] = &a[k];
}
}
for(i = 0; i < sizeof(a)/sizeof(a[0]); i++)
std::cout << a[i] << ' ';
std::cout << std::endl;
for(i = 0; i < sizeof(b)/sizeof(b[0]); i++)
std::cout << b[i] << ' ';
std::cout << std::endl;
return 0;
}

c++ pointer/array distinction

I am practicing for a c++ midterm, and I can't see why the following code is incorrect.
int ip[] = {6, 7, 2, 4, -5};
for (int i = 0; i < 5; ++i, ++ip)
cout << *ip;
My suspicion is that is it something to do with the -5, but I'm lost, and I'd really like to get this resolved.
You cannot increase ip, since it is an array, and not a pointer - so its value [ip] is fixed.
So, the problem is with the expression ++ip
The error is that you can't increment the value of a static pointer, aka an array.
The easy solution is to simply use the indexing operator [].
int ip[] = {6, 7, 2, 4, -5};
for (int i = 0; i < 5; i++)
cout << ip[i];
You can access these elements directly by using index:
int ip[] = {6, 7, 2, 4, -5};
for (int i = 0; i < 5; ++i)
cout << ip[i];
or if you want to use pointer arithmetic for this purpose, you could use temporary variable - pointer that will point to first element of this array:
int ip[] = {6, 7, 2, 4, -5};
int* myPtr = ip;
for (int i = 0; i < 5; ++i, ++myPtr)
cout << *myPtr;
Note that int* myPtr = ip; is equal to int* myPtr = &ip[0].
The reason for this is:
when it comes to an array ip[],ip is pointing to the first element
of array and it is fixed and it cannot be changed(it is like a
constant pointer i.e pointing to a fixed memory location.)
2.so when you are incrementing it you are violating the condition that's why you are getting an error
try this instead
int ip[] = {6, 7, 2, 4, -5};
for (int i = 0; i < 5; ++i)
cout << ip[i];
ip is a static array.. you cannot increase it!
eventually you can create another pointer that points to ip:
int* p = ip;
then increment p.
you need to increase each value of the array ip[] separately
Pointers and arrays are distinct things.
Pointers decay to arrays, but it doesn't work the other way around.
The operator++ is not defined on arrays, so ip decays to a pointer, the pointer (unnamed temporary) is incremented, but you can't store it back into ip, because ip is an array.
The code below should work, as you expect.
#include <iostream>
int main(){
int ip[] = {6, 7, 2, 4, -5};
int *p=ip;
for (int i = 0; i < 5; ++i, ++p)
std::cout << *p;
}
Just to formalize somewhat what others are saying: ip is an array, not
a pointer. It converts implicitly to a pointer, but the results of an
implicit conversion are an rvalue, and the ++ operator requires an
lvalue. Other than the implicit conversion (which doesn't occur in all
contexts), there is no real relationship between arrays and pointers.
Note too that in C++, [] is not defined for array types, only for
pointers (or for types with user defined overloads). It only works with
arrays because of the implicit conversion.

Returning array

How to return a pointer to array and get values from that?
int * getChange(int first[], int second[], int SIZE) {
int i = 0;
int * change = new int[2];
for (i = 0; i < SIZE; i++) {
if (first[i] != second[i]) {
change[0] = first[i];
change[1] = second[i];
}
break;
}
return change;
}
function main() {
int myNumbers[] = {1, 0, 2, 3};
int possibilities[] = {0, 1, 2, 3};
int * change;
change = getChange(possibilities, myNumbers, 4);
printf("%i / %i\n", (change), (change+1));
}
Unfortunately the function seems to return addresses, not values...
Try to change
printf("%i / %i\n", (change), (change+1));
to
printf("%i / %i\n", *(change), *(change+1));
In the printf function you need to use an int as parameters, not an int*. the change variable is a pointer. You must use *change and, using pointers arithmetics, *(change + 1)
Obviously, don't forget to free the allocated memory.
In C++, you would not be using arrays (int[] or int*), because they are annoying in several ways: you have to pass around the SIZE, they're usually exception-unsafe (you have to catch the exception, delete the array, then re-throw the exception), and they're hard to use as class members properly. Either use a standard library container, or an iterator range.
The idiomatic way to do what you're trying to do would be to use iterators and pairs:
template <typename IT_1, typename IT_2>
std::pair<int,int> getChange(IT1 begin, IT1 end, IT2 begin2)
{
for (; begin != end; ++begin, ++begin2)
{
if (*begin != *begin2) return std::make_pair(*begin,*begin2);
}
return std::make_pair(0,0);
}
void main() {
int myNumbers[] = {1, 0, 2, 3};
int possibilities[] = {0, 1, 2, 3};
std::pair<int,int> change = getChange(possibilities, possibilities + 4,
myNumbers);
printf("%i / %i\n", change.first, change.second);
}
Note that the second sequence (myNumbers) is expected to be as least as long as the first sequence. If you're not comfortable with iterators and function templates yet, you can always use vectors instead:
std::pair<int,int> getChange(std::vector<int> a, std::vector<int> b) {
for (int i = 0; i < a.size() && i < b.size(); ++i)
{
if (a[i] != b[i]) return std::make_pair(a[i],b[i]);
}
return std::make_pair(0,0);
}
void main() {
int _myNumbers[] = {1, 0, 2, 3};
int _possibilities[] = {0, 1, 2, 3};
std::vector<int> myNumbers(_myNumbers,_myNuymbers+4),
possibilities(_possibilities,_possibilities+4);
std::pair<int,int> change = getChange(possibilities, myNumbers);
printf("%i / %i\n", change.first, change.second);
}
While the latter may seem rather more verbose than the array version (after all, it's creating two arrays and then copying their values into the vectors), keep in mind that initializing an array from a constant is a fairly rare occurence: most of the time, arrays (and vectors) are initialized dynamically by a piece of code dedicated to just that. Such code can usually be used for both arrays and vectors with only minimal changes.
And, of course, you can typedef both std::pair<int,int> and std::vector<int> to shorter names if you end up using them a lot.
As it has been said, your code is very wrong in very many levels. I'll try to explain.
First of all, if you want to return the same array, why are you creating a new one? What is it you want to do, exactly?
Second, that new you make is never getting free'd. After main() exits, all the memory of your application is going to be claimed by the OS, but you shouldn't rely on that.
The code that Chowlett wrote is correct (+1 for being nice and pointing out the allocation problem ;), so I'll just go through your code and point out stuff
for(int i = 0 ; i < size i++)
{
if(first[i] != second[i])
{
change[0] = first[i];
change[1] = second[i];
}
break;
}
that doesn't do what you want. It checks if first[0] is different from second[0], then hits the break whether this holds true or not. You want the break inside the if statement block.
then if you want to use an array's content, you have to index it with [], otherwise you refer to the memory address of the array and it's indexes. This means which's been said, that you want to do
printf("%d / %d", changed[0], change[1])
While what's been said above that using C++ vectors is "better" for this case than arrays, I don't think this is the right answer to your question. You seem to be learning how to use arrays, and arrays are a most important part of C and even C++ real life coding. You'll use them a lot, they are WAY faster than vectors, and many many many libraries that you'll deal with are written in plain C, so you'll have to use them.
Learn yourself a little bit of pointer arithmetics, and you'll be fine. Remember to free the memory you allocate, this isn't Java. remember that a in
int a[3];
is more like a
int *a;
than like a
int a;
which explains why you can also do
printf("%d / %d", *changed, *(changed + 1));
Read the kernighan and ritchie.
Happy hacking
I think I'd write it a bit differently (and note that I'm sticking to C-only concepts here - in C++ I would almost certainly do things a bit differently):
void getChange(int *first, int *second, int SIZE, int *change) {
int i = 0;
for (i = 0; i < SIZE; i++) {
if (first[i] != second[i]) {
change[0] = first[i];
change[1] = second[i];
break;
}
}
return;
}
function main() {
int myNumbers[] = {1, 0, 2, 3};
int possibilities[] = {0, 1, 2, 3};
int change[2];
getChange(possibilities, myNumbers, 4, change);
printf("%i / %i\n", change[0], change[1]);
}
If you allocate change outside of getChange you solve potential memory leak problems.
printf("%i / %i\n", (change), (change+1));
This should be:
printf("%d / %d\n", *change, *(change + 1));
int* functionReturningArray( int *inputArray, int size)
{
int*outputArray = new int[20];
return outputArray;
}
But it is much better to use vector in c++ then c style arrays. Because it protect you from a lot of errors and it is faster to write code using vector.
Also such functionReturningArray is not very good because it returns just a pointer t othe first element of array but don't return size. You can return size and a pointer (two arguments) by predefining them and passing pointers to them to your function like this:
void f(int**outputArray, int *size)
{
*outPutArray = new int[20];
*size = 20;
}
And how it looks with a vector:
std::vector<int> func(const std::vector<int> &input)
{
std::vector<int> output;
output.push_back(5);
return output;
}
You can also create the vector on a heap and return a pointer to it.
But avoid using std::vector - use std::string instead