Google Answers Logo
View Question
 
Q: C question/passing multi-arrays ( Answered 5 out of 5 stars,   0 Comments )
Question  
Subject: C question/passing multi-arrays
Category: Computers > Programming
Asked by: jimmyjrosu-ga
List Price: $5.00
Posted: 14 Feb 2004 19:03 PST
Expires: 15 Mar 2004 19:03 PST
Question ID: 306889
I need to know how to pass a Multi-demensional array in c that allows
me to access and change the values of the i and j variables---EX

int const i=10, j=20;
int topass[i][j];

fuction(what goes here?)//I want to pass 'topass' and in the fuction i want to 
                        //be able to access any 'i' and and 'j', so in the 
                        //fuction would like to be able to say....change
                        // topass[3][2], or topass[1][10]

thanks
Answer  
Subject: Re: C question/passing multi-arrays
Answered By: majortom-ga on 15 Feb 2004 07:08 PST
Rated:5 out of 5 stars
 
There are two answers to your question, depending on whether you are
using the gcc compiler, or insisting on ANSI standard C that is
portable to all compilers. Since the code you have presented will not
compile in ANSI standard C, I will present the gcc answer first, as
you probably would not have written the code the way you did in your
question if your compiler was rejecting it.

In recent versions of the GNU gcc compiler, what you want to do is not
too difficult. All you have to do is define your function so that the
number of rows and columns in the array are passed as separate
parameters before the array itself is passed. (This is necessary
because two-dimensional arrays are not really high-level objects in C;
gcc has extensions to C that make it possible to work with them more
conveniently, but at the root of things, a two-dimensional C array is
really just a pointer to the first element. So passing the number of
rows and columns is necessary to help the gcc C extensions to do their
work and make the array act a bit like a two-dimensional array in a
high-level language.)

See the following code, which has been tested:

void myfunction(int rows, int cols, int topass[rows][cols]);

int main(int argc, char *argv[])
{
        int i = 10;
        int j = 20;
        int topass[i][j];
        myfunction(i, j, topass);
}

void myfunction(int rows, int cols, int topass[rows][cols])
{
  topass[0][0] = 1;
}

For more information about gcc and its extensions to the C language, see:

gcc C extensions
http://gcc.gnu.org/onlinedocs/gcc-2.95.3/gcc_4.html#SEC75

Now, the above works great with gcc, and gcc may be all you ever use.
But just to be sure you understand that what you are doing is not ANSI
standard portable C, the second half of my answer focuses on how to do
this correctly without the special extensions to C included only in
gcc:

* * *

First of all, the const keyword in ANSI C does not provide a way to declare
arrays of variable size; however, the code you have written will compile
successfully under gcc 3.1.1 and perhaps other compilers that are somewhat
relaxed about these things. In strict ANSI C you would need to write:

int topass[10][20];

Or use macros to make it a little more elegant:

#define ROWS 10
#define COLUMNS 20
int topass[ROWS][COLUMNS];

Or, if the number of rows and columns is not known at compile time,
allocate the array on the stack:

int *topass = alloca(10 * 20 * sizeof(int));

Now, as to the subject of passing the array to a function, C does not really 
have a high-level array type; the size of each dimension of the array is
unknown at runtime. This hurts the most when the array has more than one
dimension, like this one does. The "array" you have declared is actually just 
a pointer to the first element in the array. If you must have the ability 
to pass a variety of two-dimensional arrays of different dimensions to the
same function, then you will need to explicitly pass the dimensions of
the array to the function, which will need to calculate the right
offset in the array every time an element in the array is wanted:

myfunction(topass, i, j);

The function must be written like so:

void myfunction(int *topass, int i, int j)
{
  topass[i * row + col] = value you want to assign at this row and col;
}

A little confusing? You can make this a bit simpler with a macro:

#define ROWCOL(array, row, col) (array)[(row) * i + (col)]
void myfunction(int *topass, int i, int j)
{
  ROWCOL(topass, row, col) = whatever you want to assign;
}

Thanks for the opportunity to answer this question.

Request for Answer Clarification by jimmyjrosu-ga on 15 Feb 2004 07:41 PST
**Great answer by the way, was just hoping you could clarify one thing
(the answer worked, but my mind is still confused)--When accessing
like this "topass[i * row + col]"  I understand the 'i' is the first
bracket (topass[i][j]), but why is that needed.

Clarification of Answer by majortom-ga on 15 Feb 2004 12:46 PST
If you are using gcc exclusively, you don't have to use the
"topass[i * row + col]" method. You can use the method in
the first part of my answer instead.

If you are following strict ANSI C, though, then you can't
write this:

/* WRONG in ANSI C, but gcc allows it */
void myfunction(int rows, int cols, int topass[rows][cols])

The language simply does not allow it. You are only allowed to do this:

/* Allowed in ANSI C */
void myfunction(int topass[10][20])

But that would be an array of a fixed number of rows and columns, and
you specified that the array might have any size. Since ANSI C has no
provision
for passing a simple two-dimensional array of integers to a function,
you must pass a pointer to the first integer and calculate the offset
each time you want to access one. For convenience, passing the name of
the array implicitly passes a poitner to the first integer in it.

Alternatively, you could create your array differently in the first place:

int data[10 * 20];
int *dataPointers[10];
int i;
for (i = 0; (i < 10); i++) {
  dataPointers[i] = data + i * 20;
}
myfunction(rows, cols, dataPointers);

You could then write myfunction as:

void myfunction(int rows, int cols, int **dataPointers)

And you would then be allowed to refer to
dataPointers[row][col] in a more natural fashion -- but
the price is that you must set up an array of pointers
to each row of data, as shown above, and pass that to 
myfunction. It is usually just as easy to follow my
original ANSI C suggestion of calculating the offset each time.
And of course if you stick to gcc you can follow my first
set of recommendations, which make all of this convenient,
and forget about the tough parts entirely.
jimmyjrosu-ga rated this answer:5 out of 5 stars and gave an additional tip of: $1.00
Great answer, THANKS!!

Comments  
There are no comments at this time.

Important Disclaimer: Answers and comments provided on Google Answers are general information, and are not intended to substitute for informed professional medical, psychiatric, psychological, tax, legal, investment, accounting, or other professional advice. Google does not endorse, and expressly disclaims liability for any product, manufacturer, distributor, service or service provider mentioned or any opinion expressed in answers or comments. Please read carefully the Google Answers Terms of Service.

If you feel that you have found inappropriate content, please let us know by emailing us at answers-support@google.com with the question ID listed above. Thank you.
Search Google Answers for
Google Answers  


Google Home - Answers FAQ - Terms of Service - Privacy Policy