Arrays and pointers

S

Sheldon

Hi,

Can someone please explain how one can pass a 2D array to a function
but only using a single pointer?
This example surely does this and it is confusing the heck out me:

int nc_put_vars_float (int ncid, int varid, const size_t start[],
const size_t count[], const ptrdiff_t stride[],
const float *fp);

#include <netcdf.h>
...
#define NDIM 2 /* rank of netCDF variable */
int ncid; /* netCDF ID */
int status; /* error status */
int rhid; /* variable ID */
static size_t start[NDIM] /* netCDF variable start point: */
= {0, 0}; /* first element */
static size_t count[NDIM] /* size of internal array: entire
*/
= {2, 3}; /* (subsampled) netCDF variable */
static ptrdiff_t stride[NDIM] /* variable subsampling intervals:
*/
= {2, 2}; /* access every other netCDF
element */
float rh[2][3]; /* note subsampled sizes for */
/* netCDF variable dimensions */
...
status = nc_open("foo.nc", NC_WRITE, &ncid);
if (status != NC_NOERR) handle_error(status);
...
status = nc_inq_varid(ncid, "rh", &rhid);
if (status != NC_NOERR) handle_error(status);
...
status = nc_put_vars_float(ncid, rhid, start, count, stride, rh);
if (status != NC_NOERR) handle_error(status);

Complete example:
http://www.unidata.ucar.edu/softwar..._005f-type.html#nc_005fput_005fvars_005f-type

I want to use the nc_put_vars_float function but my arrays are within
a structure and when I call the function giving it ptr->array where
array is a 2D array, I get an error of incompatible pointer type.

Can someone please explain what's going on and how I can modify my
struct array so that this function accepts it?

Sincerely,
Marston
 
B

Ben Bacarisse

Sheldon said:
Can someone please explain how one can pass a 2D array to a function
but only using a single pointer?
This example surely does this and it is confusing the heck out me:

int nc_put_vars_float (int ncid, int varid, const size_t start[],
const size_t count[], const ptrdiff_t stride[],
const float *fp);

#include <netcdf.h>
...
#define NDIM 2 /* rank of netCDF variable */
int ncid; /* netCDF ID */
int status; /* error status */
int rhid; /* variable ID */
static size_t start[NDIM] /* netCDF variable start point: */
= {0, 0}; /* first element */
static size_t count[NDIM] /* size of internal array: entire
*/
= {2, 3}; /* (subsampled) netCDF variable */
static ptrdiff_t stride[NDIM] /* variable subsampling intervals:
*/
= {2, 2}; /* access every other netCDF
element */
float rh[2][3]; /* note subsampled sizes for */
/* netCDF variable dimensions */
...
status = nc_open("foo.nc", NC_WRITE, &ncid);
if (status != NC_NOERR) handle_error(status);
...
status = nc_inq_varid(ncid, "rh", &rhid);
if (status != NC_NOERR) handle_error(status);
...
status = nc_put_vars_float(ncid, rhid, start, count, stride, rh);

This example is wrong, but on most systems you'll get away with it.
You can get rid of the compile-time error simply by passing &rh[0][0]
rather than rh -- you get a compatible pointer that way.
if (status != NC_NOERR) handle_error(status);

Complete example:
http://www.unidata.ucar.edu/softwar..._005f-type.html#nc_005fput_005fvars_005f-type

I want to use the nc_put_vars_float function but my arrays are within
a structure and when I call the function giving it ptr->array where
array is a 2D array, I get an error of incompatible pointer type.

rh gets converted to a pointer to the first element of the array rh.
This is *not* a float. 2D arrays, in C, are arrays of arrays so the
first elements is an array of floats. A pointer to the array has the
rather odd type of float (*)[3]. Passing a pointer to the first float
(&rh[0][0]) gives you a pointer of the correct type[1] but the legality of
accessing the whole array from this pointer is... questionable. You
have no choice here -- this is the interface decided on by the library
authors so you should assume that you can safely ignore those
technicalities.

In you case, of course, you pass &ptr->array[0][0] but exactly the
same arguments apply.
Can someone please explain what's going on and how I can modify my
struct array so that this function accepts it?

No need. The function is designed to handle multidimensional arrays
provided you

[1] You can also pass (void *)rh, or rh[0], or... there are numerous
ways to get a pointer that the compiler won't complain about.
 
M

Marston

Sheldon said:
Can someone please explain how one can pass a 2D array to a function
but only using a single pointer?
This example surely does this and it is confusing the heck out me:
int nc_put_vars_float (int ncid, int varid, const size_t start[],
const size_t count[], const ptrdiff_t stride[],
                                   const float *fp);
#include <netcdf.h>
        ...
     #define NDIM 2                /* rank of netCDF variable */
     int ncid;                     /* netCDF ID */
     int status;                   /* error status */
     int rhid;                     /* variable ID */
     static size_t start[NDIM]     /* netCDF variable start point: */
                      = {0, 0};    /* first element */
     static size_t count[NDIM]     /* size of internal array: entire
*/
                        = {2, 3};  /* (subsampled) netCDF variable */
     static ptrdiff_t stride[NDIM] /* variable subsampling intervals:
*/
                      = {2, 2};    /* access every other netCDF
element */
     float rh[2][3];               /* note subsampled sizes for */
                                   /* netCDF variable dimensions */
        ...
     status = nc_open("foo.nc", NC_WRITE, &ncid);
     if (status != NC_NOERR) handle_error(status);
        ...
     status = nc_inq_varid(ncid, "rh", &rhid);
     if (status != NC_NOERR) handle_error(status);
        ...
     status = nc_put_vars_float(ncid, rhid, start, count, stride, rh);

This example is wrong, but on most systems you'll get away with it.
You can get rid of the compile-time error simply by passing &rh[0][0]
rather than rh -- you get a compatible pointer that way.
     if (status != NC_NOERR) handle_error(status);
I want to use the nc_put_vars_float function but my arrays are within
a structure and when I call the function giving it ptr->array where
array is a 2D array, I get an error of incompatible pointer type.

rh gets converted to a pointer to the first element of the array rh.
This is *not* a float.  2D arrays, in C, are arrays of arrays so the
first elements is an array of floats.  A pointer to the array has the
rather odd type of float (*)[3].  Passing a pointer to the first float
(&rh[0][0]) gives you a pointer of the correct type[1] but the legality of
accessing the whole array from this pointer is... questionable.  You
have no choice here -- this is the interface decided on by the library
authors so you should assume that you can safely ignore those
technicalities.

In you case, of course, you pass &ptr->array[0][0] but exactly the
same arguments apply.
Can someone please explain what's going on and how I can modify my
struct array so that this function accepts it?

No need.  The function is designed to handle multidimensional arrays
provided you

[1] You can also pass (void *)rh, or rh[0], or... there are numerous
ways to get a pointer that the compiler won't complain about.

Hi,

Thank you for your help. The first method didn't work &array[0][0] but
(void *)array did.
Why is this? Can you explain of point me to the document?

/Marston
 
B

Ben Bacarisse

Marston said:
Thank you for your help. The first method didn't work &array[0][0] but
(void *)array did.
Why is this? Can you explain of point me to the document?

No, there is too much missing. I have no idea what "does not work"
means and I have no idea what your code is. I would want to know why
the two methods are behaving differently, but without the code
everything would be a wild guess.
 
B

Barry Schwarz

snip
int nc_put_vars_float (int ncid, int varid, const size_t start[],
const size_t count[], const ptrdiff_t stride[],
                                   const float *fp);
snip
     float rh[2][3];               /* note subsampled sizes for */
snip
snip

Thank you for your help. The first method didn't work &array[0][0] but

There is no 2D object in your code called array. I assume you meant
rh. You need to show us the actual code and explain what "didn't
work" means, preferably by quoting the entire diagnostic from the
compiler.
(void *)array did.
Why is this? Can you explain of point me to the document?

Pointers to void are compatible with (there is an implicit conversion
between them and) every other type of pointer.

When rh is used as the argument to a function, it is an expression of
type array. As explained in 6.3.2.1-3, this expression is converted
to the address of the first element of the array with type pointer to
element type. In other words, rh is equivalent to &rh[0]. Since
rh[0] is an array of three float, the expression has type pointer to
array of three float, expressed as float(*)[3]. You then cast this
expression to type void*. The prototype for nc_put_vars_float says
that this argument must have type float*. Since void* is compatible
with float*, the compiler silently converts (generates the code to
convert) the void* to a float*. Since rh, rh[0], and rh[0][0] all
share the exact same address, nc_put_vars_float is perfectly happy to
process the data starting at that address.

As Ben pointed out, while this works on almost all system, it is of
questionable legality as far as the standard is concerned. But that
is a different issue you can find in the archives.
 
K

Keith Thompson

Barry Schwarz said:
Pointers to void are compatible with (there is an implicit conversion
between them and) every other type of pointer.
[...]

Quibble: the standard defines the concept of compatible types, and
that's not it.

Another quibble: The conversion between void* and other pointer types
doesn't apply to pointer-to-function types.
 
M

Marston

snip
int nc_put_vars_float (int ncid, int varid, const size_t start[],
const size_t count[], const ptrdiff_t stride[],
                                   const float *fp);
snip
     float rh[2][3];               /* note subsampled sizes for */
snip
     status = nc_put_vars_float(ncid, rhid, start, count, stride, rh);
snip

Thank you for your help. The first method didn't work &array[0][0] but

There is no 2D object in your code called array.  I assume you meant
rh.  You need to show us the actual code and explain what "didn't
work" means, preferably by quoting the entire diagnostic from the
compiler.
(void *)array did.
Why is this? Can you explain of point me to the document?

Pointers to void are compatible with (there is an implicit conversion
between them and) every other type of pointer.  

When rh is used as the argument to a function, it is an expression of
type array.  As explained in 6.3.2.1-3, this expression is converted
to the address of the first element of the array with type pointer to
element type.  In other words, rh is equivalent to &rh[0].  Since
rh[0] is an array of three float, the expression has type pointer to
array of three float, expressed as float(*)[3].  You then cast this
expression to type void*.  The prototype for nc_put_vars_float says
that this argument must have type float*.  Since void* is compatible
with float*, the compiler silently converts (generates the code to
convert) the void* to a float*.  Since rh, rh[0], and rh[0][0] all
share the exact same address, nc_put_vars_float is perfectly happy to
process the data starting at that address.

As Ben pointed out, while this works on almost all system, it is of
questionable legality as far as the standard is concerned.  But that
is a different issue you can find in the archives.

Thanks for clearing this up for me.
As long as the data is processed as a 2D array I'm happy.

/M
 
B

Barry Schwarz

snip
Thanks for clearing this up for me.
As long as the data is processed as a 2D array I'm happy.

Sheldon, it would be nice if you stuck to one name.

You have set your sights too low. Why are you passing a 2D array to a
function expecting a 1D array?

You never told us why the simpler and safer &rh[0][0] did not work.
Ben's advice appeared sound and if it isn't many of us would like to
know why.
 
B

Ben Bacarisse

Barry Schwarz said:
snip


Sheldon, it would be nice if you stuck to one name.

You have set your sights too low. Why are you passing a 2D array to a
function expecting a 1D array?

That is a simple one to answer: because the library he is using does
it that way. There is no good solution to this problem in C (as far
as I know) so this is simply the best of a bad job. Well, maybe not
the *best* in that I'd be inclined to make the data pointer a void *,
even though the function knows the type it expects. Passing &array to
a void * parameter does, by some people's reading of the standard,
allow access to all of the array unlike passing array or array[0].
You never told us why the simpler and safer &rh[0][0] did not work.

Yes, this bothers me since it suggests there is really another problem
here.
 
C

chunpulee

array2d[x][y]

void fun(char *array2d, int x, int y)
{
int i, j;
char *node;

for (i = 0; i < x, ++i) {
for (j = 0; j < y; ++j) {
node = array2d + i*y + j;
... ...
}
}
}
 
B

Barry Schwarz

Barry Schwarz said:
snip


Sheldon, it would be nice if you stuck to one name.

You have set your sights too low. Why are you passing a 2D array to a
function expecting a 1D array?

That is a simple one to answer: because the library he is using does
it that way. There is no good solution to this problem in C (as far
as I know) so this is simply the best of a bad job. Well, maybe not
the *best* in that I'd be inclined to make the data pointer a void *,
even though the function knows the type it expects. Passing &array to
a void * parameter does, by some people's reading of the standard,
allow access to all of the array unlike passing array or array[0].

I understand the library expects a 1D array. I don't know why he is
using a 2D array when a 1D would work just as well.
You never told us why the simpler and safer &rh[0][0] did not work.

Yes, this bothers me since it suggests there is really another problem
here.
 
B

Ben Bacarisse

I understand the library expects a 1D array. I don't know why he is
using a 2D array when a 1D would work just as well.

Ah, I see what you mean.

Presumably his data is 2D and it makes sense to keep it like that
until the library has to be used. Of course if it is not 2D data or
it could be managed adequately in a 1D array, you have a point. Maybe
we will get to find out...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top