You are not logged in.

#1 2006-09-14 02:56:52

tardo
Member
Registered: 2006-07-15
Posts: 526

passing 3d arrays to functions in C

So.. I have a certain char array[8][3][30], declared as ***array, and allocated as the program progresses. I'd like to pass that to an external function, but GCC pukes out warnings that the type case isn't right, and anytime I access it in the function, it segfaults (basically, it doesn't pass properly).

my function prototype:

int parse_table(char ***table);

and code to pass it:

parse_table(table);

anyone knowledgable on this?

Offline

#2 2006-09-14 04:16:59

paranoos
Member
From: thornhill.on.ca
Registered: 2004-07-22
Posts: 442

Re: passing 3d arrays to functions in C

man, i haven't touched C in a long time... but what if you changed it to

int parse_table(char *table[8][3])

or

int parse_table(char table[8][3][])

that's what i remember doing back in the day.

Offline

#3 2006-09-14 04:50:39

palandir
Member
Registered: 2006-05-14
Posts: 73

Re: passing 3d arrays to functions in C

It's ugly to do this, you should pack the array into a struct and pass that to the function. Then you won't have to worry about it. wink

However, if you want to pass it directly:

int parse_table(char table[][dim2][dim3], int dim1) {

Offline

#4 2006-09-14 15:32:05

phrakture
Arch Overlord
From: behind you
Registered: 2003-10-29
Posts: 7,879
Website

Re: passing 3d arrays to functions in C

first off: if you are ever ever ever ever ever passing an array as a pointer to a function you __MUST__ pass the length.  There is no way to get array length from a pointer.  If you don't do this, you risk buffer overflows, among other things (random segfaults).

secondly, I would just use a single array in this case... some_array[i*j*k] ~= some_array[i][j][k]

Offline

#5 2006-09-14 22:17:28

tardo
Member
Registered: 2006-07-15
Posts: 526

Re: passing 3d arrays to functions in C

unfortunately, a single array just makes simple code more complicated... I can't pass the size, because the size changes everytime I run the program with a different input file.

I've temporarily solved it by making it a global variable. I like the idea of a struct, I'll definitely try that one out.

Offline

#6 2006-09-14 22:24:33

phrakture
Arch Overlord
From: behind you
Registered: 2003-10-29
Posts: 7,879
Website

Re: passing 3d arrays to functions in C

tardo wrote:

unfortunately, a single array just makes simple code more complicated... I can't pass the size, because the size changes everytime I run the program with a different input file.

I don't think you understand... you MUST pass the size... there is no "arraylen()" function like strlen().  sizeof() doesn't work either, as that is compile-time.

Offline

#7 2006-09-14 22:36:39

nogoma
Member
From: Cranston, RI
Registered: 2006-03-01
Posts: 217

Re: passing 3d arrays to functions in C

phrakture wrote:

I don't think you understand... you MUST pass the size... there is no "arraylen()" function like strlen().  sizeof() doesn't work either, as that is compile-time.

Definitely... you *must* know the size somewhere, as you have to use it when malloc'ing if it isn't known at compile time...


-nogoma
---
Code Happy, Code Ruby!
http://www.last.fm/user/nogoma/

Offline

#8 2006-09-14 23:41:06

tardo
Member
Registered: 2006-07-15
Posts: 526

Re: passing 3d arrays to functions in C

Let me try and summarize what I'm writing... perhaps I might get an idea or something...

main()
{
  char ***table;
  parse_table(table);

  use_table(table);
}

parse_table(char ***table)
{
  // read one value from file
  // determine other two values from file input
  // allocate memory depending on values (varies with file input)
}

use_table(char ***table)
{
  // programming homework (probably a tree)
}

something like that... not the best code I've ever written, but I'm certainly open to ideas.

Offline

#9 2006-09-15 00:00:17

Cerebral
Forum Fellow
From: Waterloo, ON, CA
Registered: 2005-04-08
Posts: 3,108
Website

Re: passing 3d arrays to functions in C

What phrak and the others are saying is that somewhere you've gotta let the rest of your program know the size of your array. 

Using your example, it might look like this:

main()
{
  char ***table;
  int i, j, k;
  table = parse_table(i, j, k);

  use_table(table, i, j, k);
}

char *** parse_table(int &i, int &j, int &k) // using a C++ism here with ref variables
{
  i = read_from_file();
  j = read_from_file();
  k = read_from_file();

  char *** table = new char[i][j][k];

  // read in table values
 
  return table;
}

void use_table(char ***table, int i, int j, int k)
{
  // programming homework (probably a tree)
}

Notice how the dimensions are passed around?  This is necessary to use the array correctly.

Offline

#10 2006-09-15 01:16:31

tardo
Member
Registered: 2006-07-15
Posts: 526

Re: passing 3d arrays to functions in C

char *** table = new char[i][j][k];

Is this valid in C? or is this shorthand...

either way, I see what you're trying to say. Thanks for the help.

Offline

#11 2006-09-15 02:25:31

nogoma
Member
From: Cranston, RI
Registered: 2006-03-01
Posts: 217

Re: passing 3d arrays to functions in C

tardo wrote:
char *** table = new char[i][j][k];

Is this valid in C? or is this shorthand...

either way, I see what you're trying to say. Thanks for the help.

The C++ FAQ Lite is a good reference for a lot of these "gotchas" of C++ coding, and that particular tip deals with this question (as does the immediately following one...). It is also a good illustration of why people are saying avoid working with these sort of pointer constructs, if possible! Also, not to be a nitpicker, but if we're talking about "new", we're talking about C++, not C wink


-nogoma
---
Code Happy, Code Ruby!
http://www.last.fm/user/nogoma/

Offline

#12 2006-09-15 02:28:49

tardo
Member
Registered: 2006-07-15
Posts: 526

Re: passing 3d arrays to functions in C

thanks. I can't program in C++, just C =]

Offline

#13 2006-09-15 02:40:03

nogoma
Member
From: Cranston, RI
Registered: 2006-03-01
Posts: 217

Re: passing 3d arrays to functions in C

tardo wrote:

thanks. I can't program in C++, just C =]

Zoop! Sorry, I saw the "new" in somebody else's post, and got all carried away with C++. Anyway, you'll need to do a series of mallocs; in this case, the C FAQ is your friend wink. *ahem*, from looking at your earlier post, the meat of your homework assignment here is the "use_table" function, so I hope I'm not "giving away" anything you should be figuring out on your own...

edit: You will also note in reading that link that the functions using such multidim arrays have the array dimensions passed along!


-nogoma
---
Code Happy, Code Ruby!
http://www.last.fm/user/nogoma/

Offline

#14 2006-09-15 03:12:13

nogoma
Member
From: Cranston, RI
Registered: 2006-03-01
Posts: 217

Re: passing 3d arrays to functions in C

tardo wrote:
main()
{
  char ***table;
  parse_table(table);

  use_table(table);
}

parse_table(char ***table)
{
  // read one value from file
  // determine other two values from file input
  // allocate memory depending on values (varies with file input)
}

use_table(char ***table)
{
  // programming homework (probably a tree)
}

AHEM, so, I actually bothered to read this properly this time roll. If this is actually how you have your code structured, this is definitely a problem. Think about this: "table" is of type "char ***", correct? parse_table takes a type "char ***"... you have pass-by-value semantics here. So, essentially, parse_table will receive a COPY of an unitialized memory location. You will then set this local copy to the return of malloc (e.g. something lik table = malloc(/*stuff*/)). However, this is not affecting the table seen in main()! Essentially, you should have something like:

int main() {
char ***table = parse_table();
/* rest of main */
}

char *** parse_table() {
/* Stuff that mallocs into local_table pointer */
return local_table;
}

Where, you malloc the stuff in parse_table, and return that pointer. Alternatively (and painfully), you could do something weird like:

int main() {
char ***table;
parse_table(&table);
/* rest of main */
}

void parse_table(char ****table) { /* Note: four "asterisks", not three! */
/* malloc evilness in here, with something like (*table) = malloc(/* stuff */) */
}

(Don't do this, it's ugly and unnecessary)

Just to be completely pendantic, check it this sample code I whipped up:

#include <stdlib>                                                                                                                                                                
#include <stdio>                                                                                                                                                                 
                                                                                                                                                                                    
void evil_and_wrong(char *f) {                                                                                                                                                     
  printf("Memory location we'd allocate to (evil_and_wrong): %un", &f);                                                                                                           
  f = (char*)malloc(5*sizeof(char)); 
  f[0]='p';                                                                                                                                              
}                                                                                                                                                                                  
                                                                                                                                                                                   
void my_alloc_f(char **f) {                                                                                                                                                        
  printf("Memory location we'd allocate to (my_alloc_f): %un", f);                                                                                                                
   (*f) = (char*)malloc(5*sizeof(char));                                                                                                                                            
   (*f)[0]='p';                                                                                                                                                                     
 }                                                                                                                                                                                  
                                                                                                                                                                                    
 char * nicer_my_alloc_f() {                                                                                                                                                        
   char *local_f = (char*) malloc(5*sizeof(char));                                                                                                                                  
  local_f[0]='p';                                                                                                                                                                  
  return local_f;                                                                                                                                                                  
}                                                                                                                                                                                  
                                                                                                                                                                                   
int main() {                                                                                                                                                                       
  char *f;                                                                                                                                                                         
  printf("ACTUAL Memory location: %un", &f);                                                                                                                                      
  evil_and_wrong(f);                                
  // We won't try anything with "f" here, since it'll segault...                                                                                                                               
  my_alloc_f(&f);                                                                                                                                                                  
  printf("Should see: %un", 'p');                                                                                                                                                 
  printf("See: %un", f[0]);                                                                                                                                                       
  free(f);                                                                                                                                                                         
  f = nicer_my_alloc_f();                                                                                                                                                          
  printf("See: %un", f[0]);                                                                                                                                                       
  free(f);                                                                                                                                                                         
  return 0;                                                                                                                                                                        
}                   

Look at the outputted memory locations, and think about the fact you're trying to store the address of the allocated memory...


-nogoma
---
Code Happy, Code Ruby!
http://www.last.fm/user/nogoma/

Offline

#15 2006-09-15 03:17:23

Cerebral
Forum Fellow
From: Waterloo, ON, CA
Registered: 2005-04-08
Posts: 3,108
Website

Re: passing 3d arrays to functions in C

tardo wrote:
char *** table = new char[i][j][k];

Is this valid in C? or is this shorthand...

Er, yeah, apologies for that - like with the reference params, that's a bit of C++ that crept in.

You'd need something like

int n;
char *** table = (char ***) malloc( i * sizeof( char ** ) );
for (n = 0; n<i; n++)
{
    table[n] = (char **) malloc ( j * sizeof ( char * ) );
    // another nested for loop to allocate third dimension here
}

which is what that C Faq was talking about, looks like.

In the end, it might be easier to use Phrak's suggestion of a single-dimensional array of size i*j*k - it's a small bit of math to figure out which index [i][j][k] maps to, but it's totally doable, and might simplify things.

Offline

Board footer

Powered by FluxBB