Sign in to follow this  

passing reference to 2d arrays help

This topic is 4070 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Ive used pointers alot before and had no problems till now.... Im used to mallocing 2d arrays but decided for this purpose static is more efficient i could use a 1d array but its harder to debug. Id normally do it this way, float **m_Mat; //malloc yada yada Identity(m_Mat); void Indentity(float **m_Mat); I want to pass the array by reference so i can change it within the identity function without having to make another copy of the array. I can pass the array this way, float m_Mat[4][4]; Indentity(m_Mat); void Indentity(float In[][4]); But i thought if i do it that way any changes will be lost when i exit the function is this correct ? So i thought id need to pass it by reference like so, float m_Mat[4][4]; Indentity(&m_Mat); void Indentity(float *In[][4]); The compiler grumbles at me if i do it this way so have i got the wrong end of the stick or am i missing something daft ? Thx alot Fishy

Share this post


Link to post
Share on other sites
Hey fishleg003,

I have had to do the same thing with a one-dimensional array before but I'm not entirely sure whether it'd work for a two-dimensional array as well. Anyway, if it is the same, you can simply do this:


void Identity ( float *In )
{
// Modify 'In' as if it were an array
}

float m_Mat[4][4];
Identity ( m_Mat );



In a sense an array-variable can be seen as a pointer to the first index of said array. Therefore you should be able to pass the array to a function that requires a pointer as argument. Again, do not take my word for this as I'm sure a lot of hardcore C++ coders would object to this and say that arrays are special cases. They are, of course, but this way of looking at them has helped me in such situations so I'll present it to you anyway :P

Share this post


Link to post
Share on other sites
Quote:
But i thought if i do it that way any changes will be lost when i exit the function is this correct ?


No. The changes you make are directly made on the original array data.

Share this post


Link to post
Share on other sites
1st way proberly works aswell just be changing it into a 1d array i guess. Thanks Fruny still gets me in a muddle damn pointers gotta love em and hate them :).

One last thing tho when reseting big array is there a difference between these two ?
In[4][4];
memset(In, 0, sizeof(int) * 16);
ZeroMemory(In, sizeof(float) * 16);

would that reset the array or do i need to do a for loop and loop round each row ?

Share this post


Link to post
Share on other sites
one difference is that you're using sizeof(int) in one and sizeof(float) in the other (though, I'll assume that's a typo :smile:).

Anyway, no there's no difference between the two. ZeroMemory is a macro that is replaced my memset.

#define ZeroMemory(a,s) memset( a, 0, s )

Though you should probably prefer memset to ZeroMemory becuase memset is part of the standard library and ZeroMemory is not - it's just something that saves you from having to type a memory. You can actually create a template function that does it better (I'm assuming you've dabbled in the world of templates?):


template< class T >
void ZeroMem( T* object ) {
memset( object, 0, sizeof(T) );
}

// use
SomeClass a;
ZeroMem(&a);

Share this post


Link to post
Share on other sites
Quote:
Original post by IFooBar
You can actually create a template function that does it better (I'm assuming you've dabbled in the world of templates?):


template< class T >
void ZeroMem( T* object ) {
memset( object, 0, sizeof(T) );
}

// use
SomeClass a;
ZeroMem(&a);


Why on earth would you do that sort of thing, when you could use std::fill?


#include <algorithm> // in addition to whatever else

// Now we have the powerful std::fill, which is templated on a data type and
// also an iterator type. You can fill any kind of "range" with any kind of
// "value".

// Zero out an array of ints:
int foo[42];
std::fill(foo, foo + 42, 0);

// Or 'reset' an array of class instances:
Thing bar[42];
std::fill(bar, bar + 42, Thing());

// Or fill the array with copies of Thing constructed in a certain way:
std::fill(bar, bar + 42, Thing(1, 2, 3));

// Or do anything like that with a standard library container (though you really
// should only do this with sequential containers - i.e. list/vector/deque):
std::vector<std::string> greetings(42);
std::fill(greetings.begin(), greetings.end(), "hi mom!");
// Of course, std::vector already has a constructor that lets you specify the
// "default element", but you don't have to std::fill the whole thing :)


Now, if you're making class instances, it's a bad idea to "initialize them by zeroing them out". Instead, make a default constructor that initializes each member individually (via an initialization list where possible) to a proper default value (this is not always 0). In particular, you *cannot* just zero out the object if it has any virtual functions.

If you *really* wanted to, you could implement a "reset" in terms of std::fill, as follows:


template <typename T>
void reset(T& object) {
std::fill(&object, (&object)+1, T());
}


Of course, it would be a lot more idiomatic to just *assign* the default-constructed instance to the existing instance (and ensure that this works).

If you wanted to live really dangerously for absolutely no good reason, you could implement the "initialize by zeroing out" in terms of std::fill as well (instead of memcpy):


template <typename T>
void reset(T& object) {
char* data = reinterpret_cast<char*>(&object);
std::fill(data, data + sizeof(T), 0);
}


... but there really isn't any good reason for this.




To the OP: Arrays in C++ are evil in many ways. You're much better off with a structure that wraps an array. You don't have to write this yourself; the Boost library provides...


#include <boost/array.hpp>

const int mat_size = 4;

typedef boost::array<boost::array<float, mat_size>, mat_size> matrix;

// Change the provided matrix such that it now represents the identity.
void identity(matrix& m) {
for (int i = 0; i < mat_size; ++i) {
for (int j = 0; j < mat_size; ++j) {
m[i][j] = (i == j) ? 1.0 : 0.0;
}
}
}


Or more generally ;) :


#include <boost/array.hpp>

// C++ doesn't provide "templated typedefs"; here is a workaround

template <typename T, int size>
class matrix_traits {
typedef boost::array<boost::array<T, size>, size> matrix_t;
};

// Change the provided matrix such that it now represents the identity.
template <typename T, int size>
void identity(typename matrix_traits<T, size>::matrix_t& m) {
for (int i = 0; i < size; ++i) {
for (int j = 0; j < size; ++j) {
m[i][j] = (i == j) ? 1.0 : 0.0;
}
}
}

Share this post


Link to post
Share on other sites

This topic is 4070 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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