passing reference to 2d arrays help

Started by
4 comments, last by Zahlman 17 years, 6 months ago
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
Advertisement
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

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.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
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 ?
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) );}// useSomeClass a;ZeroMem(&a);
[size=2]aliak.net
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) );}// useSomeClass 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[j] = (i == j) ? 1.0 : 0.0;    }  }}


Or more generally ;) :

#include <boost/array.hpp>// C++ doesn't provide "templated typedefs"; here is a workaroundtemplate <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[j] = (i == j) ? 1.0 : 0.0;    }  }}

This topic is closed to new replies.

Advertisement