Sign in to follow this  
Just Chris

Pop and push 2D arrays

Recommended Posts

I have a 2D array that I want to discard and add rows to, but at the end, the dimensions of the array will remain the same. So how I can I do the following steps for example:
int grid[rows][4] =
{{ 1, 7, 4, 3 }    ==>  {{ 5, 0, 0, 7 }   ==> {{ 5, 0, 0, 7 }
 { 5, 0, 0, 7 }          { 3, 8, 9, 2 }}       { 3, 8, 9, 2 }
 { 3, 8, 9, 2 }};                              { 4, 2, 6, 1 }} // new row of random values 
Guess I have to pop and push the values row by row, but for 2D arrays not exactly sure. Do I need to use vectors instead, or can this be done with simple arrays?

Share this post


Link to post
Share on other sites
Can be done with normal arrays, but all the ways I can think of include dynamic memory and it'll get very sticky.

I recommend using a vector of vectors.

vector< vector<int> > row_stack;

Share this post


Link to post
Share on other sites
im new to C++ so sorry if im a mile wide of the mark with this or the code could be iffy.

BUT could you not make a pointer to an array of 4 ints and move them around like so:

int (*ptr1)[4];
int (*ptr2)[4];
ptr1 = grid; //point at first element
ptr2 = grid[1]; //point at second element
int NewLine[4]{4, 2, 6, 1} // line to be added at the bottom.


for(int i = 0; i <= rows; i++)
{
if(i == rows)//If the loops on the last row insert the NewLine
ptr2 = NewLine;// point at the new line

prt1 = ptr2;// shift data up one line
prt1++;
prt2++;
}




like i said sorry if this is bad, or wrong or not the right way, just thought i would try and apply somthing i (thought i'd) learnt.

Though im also intrested in the answer to this :)

Share this post


Link to post
Share on other sites
Your code didn't seem to work, JDUK (and I did check for typos). It shows an error with the way you set up ptr1 and ptr2.

Endar, tried using vectors but even that caused errors, and I was just initializing them. Using

std::vector<int> row_stack;

compiles fine but not

std::vector< vector<int>> row_stack;

Which give me the error "'vector' undeclared".

Share this post


Link to post
Share on other sites
sorry that code was full of error it should have looked like this:

int grid [3][4] = {{0,0,0,0} , {1,1,1,1} , {2,2,2,2}};
int NewLine[1][4] = {3,3,3,3};
int (*ptr1)[4];
int (*ptr2)[4];
ptr1 = grid; //point at first element
ptr2 = grid;
ptr2 ++;//point at second element

for(int i = 0; i <= rows; i++)
{
if(i == rows)//If the loops on the last row insert the NewLine
ptr2 = NewLine;// point at the new line

ptr1 = ptr2;// shift data up one line
ptr1++;
ptr2++;
}
[coruse]



Share this post


Link to post
Share on other sites
Don't know if i realy get your problem, but can't you do something like this:


int grid[3][4] = { {1, 7, 4, 3}, { 5, 0, 0, 7 }, { 3, 8, 9, 2 }};
int newline[4] = {4, 2, 6, 1};

for(int i=0; i<2; i++)
{
for(int j=0; j<4; j++)
{
grid[i][j] = grid[i+1][j];
}
}
for(int k=0; k<4; k++)
{
grid[2][k] = newline[k];
}



Share this post


Link to post
Share on other sites
Your pops and pushes occur in pairs? That's no problem then - what you need to do, at least conceptually, is move every element not in the first row, up one row (that overwrites the first row, but you don't care), starting with the first element of the second row and going forward (such that you don't overwrite a value that does need to be moved), then writing in the new row over the last row (overwriting a useless copy of the previous last row).

However, depending on your circumstances, you may find that what you really want is a circular queue. In this scheme, we keep an index that represents the "first" row, which may not necessarily actually be first in the memory layout. To perform this push/pop, we overwrite the current first row, and then cycle our index forward (looping when we hit the end). That way, the data we just wrote is now in the "last" row, and the previous "second" row is now "first".

To avoid mistakes and simplify the interface for other users, it is best to wrap up access to the resulting array. Here is a simple C++ implementation; translation to plain C, should it be needed, is left as an exercise. Also, if any kind of resizing of the array is needed or even useful, please don't do this, but instead work with some library container (a vector, or possibly a list of 'row' objects as illustrated below, or possibly boost::multi_array).


// WARNING! Nothing tested!

// First, we'll make a 'row' structure to represent that abstraction.

struct row {
int data[4];
int& operator[](size_t index) {
return data[index];
}
const int& operator[](size_t index) const {
return data[index];
}
}
// Simple, yeah? But trust me, this is much nicer than trying to pass arrays
// around between functions and having it work.

// Now our grid...
class grid {
int rowCount;
row* rows;
int firstIndex;

public:
grid(int size) : rowCount(size), rows(new row[size]), firstIndex(0) {}
grid(const grid& other) : rowCount(other.rowCount), rows(new row[other.rowCount]), firstIndex(other.firstIndex) {
std::copy(other.rows, other.rows + rowCount, rows);
}
grid& operator=(const grid& rhs) {
grid other(rhs);
std::swap(rows, other.rows);
rowCount = other.rowCount;
firstIndex = other.firstIndex;
}
~grid() { delete[] rows; }

// We should be able to index this...
row& operator[] (size_t index) {
return rows[(index + firstIndex) % rowCount];
// make sure you understand how that works!
}
const row& operator[] (size_t index) const {
return rows[(index + firstIndex) % rowCount];
}

// And here the magic happens:
void insert(const row& newValue) {
rows[firstIndex++] = newValue;
// We don't need to loop the firstIndex around because it will be reduced
// modulo rowCount anyway; again make sure you understand the modulo
// arithmetic there. Also, watch the post-increment. If it bothers you,
// then go ahead and do the increment in a second statement. Writing it this
// way is NOT an optimization, but just having a compact style. :)
}
}


Share this post


Link to post
Share on other sites
Wow, a lot of different solutions for this one. Well, I'm gonna try the vector approach first because it does look like I might have to add rows as the program runs, and right now it looks to be the simplest approach right now. This particular program has a variable that keeps incrementing while it's running, and it needs to test the value of this variable to see if pushing an extra row is needed.

Share this post


Link to post
Share on other sites
The standard library also provides a 'queue' class which sounds like what you want. (It is actually an adapter for other containers, which is used for the storage while it presents a queue interface. It defaults to using std::deque for the storage, which in turn is a sort of vector/list hybrid that is a good choice when you don't otherwise know what you're doing). A std::queue<row> should meet your needs quite elegantly - and expressively; the queue wrapper will prevent you from doing things you shouldn't with the container. (Unless, of course, you also *need* random access to the rows for some reason.)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this