[comp.lang.c] prototyping

davis@pacific.mps.ohio-state.edu ("John E. Davis") (11/27/90)

Hi,

   Sorry about this, I am sure many are sick of these type of questions.

   I have a function that takes a 2-d array of unknown dimension and does
   things with it.  How do I declare and call it?

   I tried this:

   double trace(double **matrix, int dim)
   {
      int i;
      double t;

      t = 0.0;
      i = 0;
      while(i++ < dim) t = t + matrix[i][i];
      return t;
   }
        

   int main()
   {
     double m[10][10],t;
     .
     .
     t = trace(m,10);
     .
     .
   }


This dumps core because of segmentation fault.  However, if I prototype trace
as:

    double trace(double matrix[10][10],int n)

then the program is fine. However, it looses its generality. What is wrong
with the first prototype? 

I am sure I am doing something wrong and there is a big lesson in store for
me.


         
--
John

  bitnet: davis@ohstpy
internet: davis@pacific.mps.ohio-state.edu

gordon@osiris.cso.uiuc.edu (John Gordon) (11/27/90)

	Given that you are passing an n-dimensional array to a function, you
*MUST* explicitly provide at least n-1 of the dimensions in the argument
declaration.

	For example:

		if my_array is a 4-dimensional array, you *must* explicitly
provide at least 3 of the dimensions when you pass my_array to a function.

	main()
	{
	  int my_array[6][5][4][3];
	  .
	  .
	  .
	}


	function_one(int array[6][5][4][])
	{
	  .
	  .
	  .
	}

	Note: There is a rule that governs which dimension may be left out; I
think it is one of the end ones, but I am not sure which one.



---
John Gordon
Internet: gordon@osiris.cso.uiuc.edu        #include <disclaimer.h>
          gordon@cerl.cecer.army.mil       #include <clever_saying.h>

hp@vmars.tuwien.ac.at (Peter Holzer) (11/27/90)

gordon@osiris.cso.uiuc.edu (John Gordon) writes:


>	Given that you are passing an n-dimensional array to a function, you
>*MUST* explicitly provide at least n-1 of the dimensions in the argument
>declaration.

>	For example:

>		if my_array is a 4-dimensional array, you *must* explicitly
>provide at least 3 of the dimensions when you pass my_array to a function.

>	main()
>	{
>	  int my_array[6][5][4][3];
>	  .
>	  .
>	  .
>	}


>	function_one(int array[6][5][4][])
>	{
>	  .
>	  .
>	  .
>	}

>	Note: There is a rule that governs which dimension may be left out; I
>think it is one of the end ones, but I am not sure which one.

You may leave out the first dimension.
my_array is an array of six elements of type int [5][4][3], and
is treated in expressions like a pointer to an int [5][4][3]. 
Thus function_one wants a pointer to int [5][4][3]. Thus it
should be declared as function_one (int (* array)[5][4][3]).
The form function_one(int array [][5][4][3]) is equivalent, but
it looks as if array were an array, which it is not, so I
recommend the first form.

To answer the original posters question: The best method
(compromise between speed/portability/readability) is to set up
an array of pointers (to pointers ...) to items. You can then
create arrays of arbitrary shape and size at runtime. E.g.

#define N 20
#define M 30

main ()
{
	int	** p;
	int	i;

	if ((p = malloc (N * sizeof (* p))) == NULL) error ();
	for (i = 0; i < N; i ++) {
		if ((p[i] = malloc (M * sizeof (** p))) == NULL) error ();
	}
	function_one (p);
}

function_one (int ** array)
{
	for (i = 0; i < N; i ++){
		for (j = 0; j < M; j ++) {
			/* do something with */ array [i][j];
		}
	}
}

Isn't that in the FAQ list?????

It should be there, because it is asked very often.
--
|    _  | Peter J. Holzer                       | Think of it   |
| |_|_) | Technical University Vienna           | as evolution  |
| | |   | Dept. for Real-Time Systems           | in action!    |
| __/   | hp@vmars.tuwien.ac.at                 |     Tony Rand |

henry@zoo.toronto.edu (Henry Spencer) (11/28/90)

In article <DAVIS.90Nov26144044@pacific.mps.ohio-state.edu> davis@pacific.mps.ohio-state.edu  (John E. Davis) writes:
>   I have a function that takes a 2-d array of unknown dimension and does
>   things with it.  How do I declare and call it?

You can't do this in C.  Period.  Indexing into the array requires knowing
the size of the rows in the array.  C insists on knowing this at compile time,
so the second dimension must be declared as a specific number.  The only way
out of this is to pass a pointer to the array as if it were one-dimensional,
and do the indexing arithmetic yourself.

>   I tried this:
>   double trace(double **matrix, int dim)

Sigh.  Please see any good C textbook for the differences between pointers
and arrays.  This is wrong no matter what shape your array has.
-- 
"I'm not sure it's possible            | Henry Spencer at U of Toronto Zoology
to explain how X works."               |  henry@zoo.toronto.edu   utzoo!henry

browns@iccgcc.decnet.ab.com (Stan Brown) (11/28/90)

In article <DAVIS.90Nov26144044@pacific.mps.ohio-state.edu>, 
davis@pacific.mps.ohio-state.edu ("John E. Davis") writes:

>    I have a function that takes a 2-d array of unknown dimension and does
>    things with it.  How do I declare and call it?
> 
The function was defined thusly:
> 
>    double trace(double **matrix, int dim)
>    {
	/* stuff deleted */
>    }

So you have a function that expects a pointer to a pointer to double.
Because of the PARTIAL equivalence of arrays and pointers in the
specific context of function definitions, you could also say that the
function expects an array of pointers to double.  Note that neither of
these is the same as an array of double--not a one-dimensional or a
two-dimensional array of double.

The function was called thusly:
> 
>    int main()
>    {
>      double m[10][10],t;
>      .
>      .
>      t = trace(m,10);
>      .
>      .
>    }
> 
> This dumps core because of segmentation fault.

m is a 2-D array of double.  This is not compatible with the definition
of the function above.

BTW, which compiler are you using?  It should have rejected the function
call if the prototype was in scope.  Catching stuff like this before it
core dumps is the reason we have prototypes.

The cure? Depends on what you're trying to accomplish.

With these hints, you might try reading the Frequently Asked Questions
again.  Pointers and arrays are not the same thing.  There are certain
cases where a first-level pointer and the name of a 1-D array are
treated as the same thing, but I can't think of any way that a
second-level pointer and a 2-D array could conform.

Please do not attribute these remarks to any other person or company.
                                   email: browns@iccgcc.decnet.ab.com
Stan Brown, Oak Road Systems, Cleveland, Ohio, USA    +1 216 371 0043

browns@iccgcc.decnet.ab.com (Stan Brown) (11/28/90)

X-NEWS: iccgcc comp.lang.c: 5098
Path: iccgcc!browns
From: browns@iccgcc.decnet.ab.com (Stan Brown)
Newsgroups: comp.lang.c
Subject: Re: prototyping (oh no! not again??)
Message-ID: <2149.275250b3@iccgcc.decnet.ab.com>
Date: 27 Nov 90 11:40:35 EST
References: <DAVIS.90Nov26144044@pacific.mps.ohio-state.edu>
Distribution: comp
Lines: 48

In article <DAVIS.90Nov26144044@pacific.mps.ohio-state.edu>, 
davis@pacific.mps.ohio-state.edu ("John E. Davis") writes:

>    I have a function that takes a 2-d array of unknown dimension and does
>    things with it.  How do I declare and call it?
> 
The function was defined thusly:
> 
>    double trace(double **matrix, int dim)
>    {
	/* stuff deleted */
>    }

So you have a function that expects a pointer to a pointer to double.
Because of the PARTIAL equivalence of arrays and pointers in the
specific context of function definitions, you could also say that the
function expects an array of pointers to double.  Note that neither of
these is the same as an array of double--not a one-dimensional or a
two-dimensional array of double.

The function was called thusly:
> 
>    int main()
>    {
>      double m[10][10],t;
>      .
>      .
>      t = trace(m,10);
>      .
>      .
>    }
> 
> This dumps core because of segmentation fault.

m is a 2-D array of double.  This is not compatible with the definition
of the function above.

BTW, which compiler are you using?  It should have rejected the function
call if the prototype was in scope.  Catching stuff like this before it
core dumps is the reason we have prototypes.

The cure? Depends on what you're trying to accomplish.

With these hints, you might try reading the Frequently Asked Questions
again.  Pointers and arrays are not the same thing.  There are certain
cases where a first-level pointer and the name of a 1-D array are
treated as the same thing, but I can't think of any way that a
second-level pointer and a 2-D array could conform.

Please do not attribute these remarks to any other person or company.
                                   email: browns@iccgcc.decnet.ab.com
Stan Brown, Oak Road Systems, Cleveland, Ohio, USA    +1 216 371 0043

hagins@dg-rtp.dg.com (Jody Hagins) (11/28/90)

In article <1990Nov27.001813.9244@ux1.cso.uiuc.edu>,
gordon@osiris.cso.uiuc.edu (John Gordon) writes:
|> 
|> 	Given that you are passing an n-dimensional array to a function,
you
|> *MUST* explicitly provide at least n-1 of the dimensions in the
argument
|> declaration.
|> 
|> 	For example:
|> 
|> 		if my_array is a 4-dimensional array, you *must* explicitly
|> provide at least 3 of the dimensions when you pass my_array to a
function.
|> 
|> 	main()
|> 	{
|> 	  int my_array[6][5][4][3];
|> 	  .
|> 	  .
|> 	  .
|> 	}
|> 
|> 
|> 	function_one(int array[6][5][4][])
|> 	{
|> 	  .
|> 	  .
|> 	  .
|> 	}
|> 
|> 	Note: There is a rule that governs which dimension may be left out;
I
|> think it is one of the end ones, but I am not sure which one.
|> 
|> 


Why can you not do the following?

	function_one(int *array)
	{
	  .
	  .
	  .
	}

You do not need to declare the size of the array (or number of
indecies)
and you can still access the individual elements of the array.


|> 
|> ---
|> John Gordon
|> Internet: gordon@osiris.cso.uiuc.edu        #include <disclaimer.h>
|>           gordon@cerl.cecer.army.mil       #include
<clever_saying.h>
|> 



Jody Hagins
hagins@gamecock.rtp.dg.com

darcy@druid.uucp (D'Arcy J.M. Cain) (11/28/90)

In <DAVIS.90Nov26144044@pacific.mps.ohio-state.edu> John E. Davis writes:
>   double trace(double **matrix, int dim)
>   {
>      int i;
>      double t;
>
>      t = 0.0;
>      i = 0;
>      while(i++ < dim) t = t + matrix[i][i];

My first reaction was that you wind up accessing matrix[10][10] so you are
accessing an area outside of the array.  you should use:
    for (i = 0; i < dim; i++) ...
but that doesn't explain why it works when you use:
>    double trace(double matrix[10][10],int n)
unless that changes the program just enough that the area following
the array is now part of your data space.  If so that is just bad news
somewhere else anyway.  Try using the for construct.

-- 
D'Arcy J.M. Cain (darcy@druid)     |
D'Arcy Cain Consulting             |   I support gun control.
West Hill, Ontario, Canada         |   Let's start with the government!
+ 416 281 6094                     |

epames@eos.ericsson.se (Michael Salmon) (11/28/90)

In article <DAVIS.90Nov26144044@pacific.mps.ohio-state.edu> John E. Davis writes:
>   double trace(double **matrix, int dim)
                        ^^ this is pointer to pointer to double
>   {
>      int i;
>      double t;
>
>      t = 0.0;
>      i = 0;
>      while(i++ < dim) t = t + matrix[i][i];
                                ^^ this is *(*(matrix + i) + i)
>      return t;
>   }
I don't think your compiler should have allowed this as you were
passing a pointer to a double not a pointer to a pointer to a double.
What has happened is that the double at matrix[0][i] is treated as a
pointer and dereferenced with an offset of i, not surprisingly you
got an error.

Michael Salmon
L.M.Ericsson
Stockholm

davis@pacific.mps.ohio-state.edu ("John E. Davis") (11/29/90)

In article <1990Nov28.010539.22412@druid.uucp> darcy@druid.uucp (D'Arcy J.M. Cain) writes:
   In <DAVIS.90Nov26144044@pacific.mps.ohio-state.edu> John E. Davis writes:
   >   double trace(double **matrix, int dim)
   >   {
   >      int i;
   >      double t;
   >
   >      t = 0.0;
   >      i = 0;
   >      while(i++ < dim) t = t + matrix[i][i];

   My first reaction was that you wind up accessing matrix[10][10] so you are
   accessing an area outside of the array.  you should use:
       for (i = 0; i < dim; i++) ...
   but that doesn't explain why it works when you use:
   >    double trace(double matrix[10][10],int n)
   unless that changes the program just enough that the area following
   the array is now part of your data space.  If so that is just bad news
   somewhere else anyway.  Try using the for construct.


This is not the function that I really had in mind.  I 'invented' this one as
I was composing the article as a quick example the make my point.  I guess I
should write:   
               i = 0; while(i < dim) t = t + matrix[i][i++];

I noticed this after I posted it.



By the way,  I have been following the C vs Fortran thread.  It seems that not
enough computer science types understand the needs of a scientist.  For
example, it is not at all uncommon to have *big* multidimensional arrays, eg.,
arrays with 5 or more subscripts. As somone pointed out, we do not randomly
access  the elements.  Most of the time only one subscript is varying so the
advantages of pointers to pointers to pointers to ... to double is unclear.
Also, what C lacks is something as the fortran ** operator. Why can't this be
implemented as a binary operator say as x^y.  As far as I understand it, the
** operator is smart enough to to convert f(x) ** 2  to (y = f(x), y*y) or
something like this; however I am not sure what the pow function does. Does it
do: pow(x,2) = exp(2*log(x)) or some faster equivilent? Perhaps someone can
fill me in.

--
John

  bitnet: davis@ohstpy
internet: davis@pacific.mps.ohio-state.edu

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (11/29/90)

In article <DAVIS.90Nov28140038@pacific.mps.ohio-state.edu>, davis@pacific.mps.ohio-state.edu ("John E. Davis") writes:
> Also, what C lacks is something as the fortran ** operator. Why can't this be
> implemented as a binary operator say as x^y.

For the same reason that SIN isn't a unary operator in Fortran, even
though mathematicians use "sin x" in preference to "sin(x)".  Let's
face it, Fortran hasn't a MOD operator!  (All together now, let's flame
Fortran for not having something as basic as "%".)  The answer is:
either you go the APL route of making _everything_ an operator, or you
draw a line somewhere and say "this has the syntax of an operator, that
has the syntax of a function call".  That choice has *NO* consequences
for how the implementation works.  In this particular case, "^" already
*is* an operator in C, meaning bit-wise exclusive or.

> I am not sure what the pow function does.
Why not check a manual and find out before complaining that C hasn't got 
an equivalent of **?  In ANSI C, if you have done
	#include <math.h>
there is no significant non-syntactic difference between pow() and
<REAL or DOUBLE> ** <INTEGER or REAL or DOUBLE>.
An ANSI C compiler is fully entitled to compile
	x = pow(y, 2);		/* I _did_ say ANSI!  Pre-ANSI needs 2.0 */
as 	x = y*y;

Is this in the FAQ?

-- 
I am not now and never have been a member of Mensa.		-- Ariadne.

epames@eos.ericsson.se (Michael Salmon) (11/29/90)

In article <DAVIS.90Nov26144044@pacific.mps.ohio-state.edu> John E. Davis writes:

>   I have a function that takes a 2-d array of unknown dimension and does
>   things with it.  How do I declare and call it?
>
You could try this approach, I haven't tried it but I'm pretty sure
that it will work. I have used 4x4 because I hate typing but the idea
is of course extensible both in the size and number of dimensions.

    double	actual[4][4];
    double	*matrix[4] = {
	actual[0],
	actual[1],
	actual[2],
	actual[3]
    }

Your call to trace will now be correct and you should be able to
access matrix[i][j] as you are used to. The major disadvantage as
far as I can see is that matrix must be external or static to allow
initialization or you will have to initialize it manually. Hope
that this is some help.

Michael Salmon
L.M.Ericsson
Stockholm

brianh@hpcvia.CV.HP.COM (brian_helterline) (11/30/90)

davis@pacific.mps.ohio-state.edu ("John E. Davis") writes:
:In article <1990Nov28.010539.22412@druid.uucp> darcy@druid.uucp (D'Arcy J.M. Cain) writes:
:   In <DAVIS.90Nov26144044@pacific.mps.ohio-state.edu> John E. Davis writes:
:   >   double trace(double **matrix, int dim)
:   >   {
:   >      int i;
:   >      double t;
:   >
:   >      t = 0.0;
:   >      i = 0;
:   >      while(i++ < dim) t = t + matrix[i][i];

:   My first reaction was that you wind up accessing matrix[10][10] so you are
:   accessing an area outside of the array.  you should use:
:       for (i = 0; i < dim; i++) ...
:   but that doesn't explain why it works when you use:
:   >    double trace(double matrix[10][10],int n)
:   unless that changes the program just enough that the area following
:   the array is now part of your data space.  If so that is just bad news
:   somewhere else anyway.  Try using the for construct.


:This is not the function that I really had in mind.  I 'invented' this one as
:I was composing the article as a quick example the make my point.  I guess I
:should write:   
:               i = 0; while(i < dim) t = t + matrix[i][i++];
						     ^^^^^^^
	Wrong again!  There is no guarantee that this will evaluate to
	what you want.  If i=5, you could end up with matrix[6][5].
	Using a variable more than once in an expression with a post-
	increment is *undefined behavior*.

	What do you have against a for(i=0; i<dim; ++i ) loop?

	
:I noticed this after I posted it.

[rest deleted]

karl@ima.isc.com (Karl Heuer) (12/01/90)

In article <4402@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes:
>Why not check a manual and find out before complaining that C hasn't got
>an equivalent of **?  In ANSI C, if you have done
>	#include <math.h>
>there is no significant non-syntactic difference between pow() and
><REAL or DOUBLE> ** <INTEGER or REAL or DOUBLE>.

But there *is* a significant difference between pow() and Fortran's
<INTEGER> ** <INTEGER>.  (Namely, the latter gets the right answer.)
Therefore, I have to agree with John that C hasn't got an equivalent of **.

(One can, of course, argue that it's not a serious flaw since the missing
functionality can be easily provided by the user if not by the vendor.)

Karl W. Z. Heuer (karl@ima.isc.com or uunet!ima!karl), The Walking Lint