Velocity Reviews > variable length array

# variable length array

Jean-Claude Arbaut
Guest
Posts: n/a

 06-03-2009
Hi,

I can use:

double get(int n, int p, double t[n][p], int i, int j) {
return t[i][j];
}

and in another function
double (*u)[];
t = (double (*)[])calloc(n*p, sizeof(double));
a=get(n,p,u,i,j);

Now, how would I declare u for 3 dimensions or more ?

Barry Schwarz
Guest
Posts: n/a

 06-03-2009
On Wed, 03 Jun 2009 02:16:55 +0200, Jean-Claude Arbaut
<(E-Mail Removed)> wrote:

>Hi,
>
>I can use:
>
>double get(int n, int p, double t[n][p], int i, int j) {
> return t[i][j];
>}
>
>and in another function
>double (*u)[];

I believe this would need to be
double (*u)[p];
as in examples 3 and 4 in 6.7.5.2(9)-(10)

>t = (double (*)[])calloc(n*p, sizeof(double));

Surely you meant u here, not t. The cast is unnecessary. Furthermore,
all bits zero need not be the representation of 0.0. A frequently
recommended construct is
t = calloc(n, sizeof *t);
or the malloc "almost equivalent"
t malloc (n * sizeof *t);

>a=get(n,p,u,i,j);
>
>Now, how would I declare u for 3 dimensions or more ?

When declaring arrays in functions and pointers to arrays, only the
high-order dimension can be unspecified/omitted.

If t3 is going to be defined in the function as
double t3[x][y][z]
then u3 will need to be defined as
double (*u3)[y][z];

--
Remove del for email

Jean-Claude Arbaut
Guest
Posts: n/a

 06-03-2009
Barry Schwarz wrote:

> On Wed, 03 Jun 2009 02:16:55 +0200, Jean-Claude Arbaut
> <(E-Mail Removed)> wrote:
>
>> Hi,
>>
>> I can use:
>>
>> double get(int n, int p, double t[n][p], int i, int j) {
>> return t[i][j];
>> }
>>
>> and in another function
>> double (*u)[];

>
> I believe this would need to be
> double (*u)[p];
> as in examples 3 and 4 in 6.7.5.2(9)-(10)

There is one in n1256.pdf, p41
And I'm not a C standard expert, but I tought
it's legal to have one incomplete dimension.

gcc -Wall -std=c99 -pedantic doesn't bark at me.
I know that doesn't prove much, but that's strange.

>> t = (double (*)[])calloc(n*p, sizeof(double));

>
> Surely you meant u here, not t.

yes

> The cast is unnecessary.

Someone just told me that on fr.clc Actually it's
a bad habit I got from using a bad compiler that gave
a warning for uncasted (mc)alloc. I can't remember
which compiler it was.

> Furthermore,
> all bits zero need not be the representation of 0.0. A frequently
> recommended construct is
> t = calloc(n, sizeof *t);
> or the malloc "almost equivalent"
> t malloc (n * sizeof *t);

Does it guarantee that memory is zeroed ?

>> a=get(n,p,u,i,j);
>>
>> Now, how would I declare u for 3 dimensions or more ?

>
> When declaring arrays in functions and pointers to arrays, only the
> high-order dimension can be unspecified/omitted.

Same remark as above.

> If t3 is going to be defined in the function as
> double t3[x][y][z]
> then u3 will need to be defined as
> double (*u3)[y][z];

Is there really no way to allocate it ?
I mean, it's possible with a warning to do

double *p = malloc(100*sizeof(double));
a = get(10,10,p,0,0);

But what should I do to declare it correctly ?

Keith Thompson
Guest
Posts: n/a

 06-03-2009
Jean-Claude Arbaut <(E-Mail Removed)> writes:
> Barry Schwarz wrote:
>> On Wed, 03 Jun 2009 02:16:55 +0200, Jean-Claude Arbaut
>> <(E-Mail Removed)> wrote:

[...]
>>> t = (double (*)[])calloc(n*p, sizeof(double));

>>
>> Surely you meant u here, not t.

>
> yes
>
>> The cast is unnecessary.

>
> Someone just told me that on fr.clc Actually it's
> a bad habit I got from using a bad compiler that gave
> a warning for uncasted (mc)alloc. I can't remember
> which compiler it was.

Could it have been a C++ compiler?

>> Furthermore,
>> all bits zero need not be the representation of 0.0. A frequently
>> recommended construct is
>> t = calloc(n, sizeof *t);
>> or the malloc "almost equivalent"
>> t malloc (n * sizeof *t);

>
> Does it guarantee that memory is zeroed ?

No, malloc doesn't initialize the allocated space, whereas calloc sets
it to all-bits-zero. But setting it to all-bits-zero doesn't
guarantee that all elements will be set to 0.0, since there's no
guarantee that all-bits-zero is a representation of all-bits-zero.

You can probably get away with it on most (maybe all?) existing
systems, but it's not portable. For guaranteed portability, you need
to set the elements to 0.0 using a loop -- and if you're going to do
that anyway you might as well just use malloc rather than calloc.
And, depending on what you're doing with the data, you might not need
to set *all* the elements to 0.0.

[...]

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Flash Gordon
Guest
Posts: n/a

 06-03-2009
Keith Thompson wrote:
> Jean-Claude Arbaut <(E-Mail Removed)> writes:
>> Barry Schwarz wrote:
>>> On Wed, 03 Jun 2009 02:16:55 +0200, Jean-Claude Arbaut
>>> <(E-Mail Removed)> wrote:

> [...]
>>>> t = (double (*)[])calloc(n*p, sizeof(double));
>>> Surely you meant u here, not t.

>> yes
>>
>>> The cast is unnecessary.

>> Someone just told me that on fr.clc Actually it's
>> a bad habit I got from using a bad compiler that gave
>> a warning for uncasted (mc)alloc. I can't remember
>> which compiler it was.

>
> Could it have been a C++ compiler?
>
>>> Furthermore,
>>> all bits zero need not be the representation of 0.0. A frequently
>>> recommended construct is
>>> t = calloc(n, sizeof *t);
>>> or the malloc "almost equivalent"
>>> t malloc (n * sizeof *t);

>> Does it guarantee that memory is zeroed ?

>
> No, malloc doesn't initialize the allocated space, whereas calloc sets
> it to all-bits-zero. But setting it to all-bits-zero doesn't
> guarantee that all elements will be set to 0.0, since there's no
> guarantee that all-bits-zero is a representation of all-bits-zero.

I know you meant "since there's no guarantee that all-bits-zero
represents a floating point 0.0 (or a null pointer)".

> You can probably get away with it on most (maybe all?) existing
> systems, but it's not portable. For guaranteed portability, you need
> to set the elements to 0.0 using a loop -- and if you're going to do
> that anyway you might as well just use malloc rather than calloc.
> And, depending on what you're doing with the data, you might not need
> to set *all* the elements to 0.0.

If the OP does choose to use calloc, make sure the non-portable
assumption is documented just in case someone ports the SW later to an
unusual system where it is a problem.
--
Flash Gordon

luserXtrog
Guest
Posts: n/a

 06-03-2009
On Jun 3, 1:03*pm, Flash Gordon <(E-Mail Removed)> wrote:
> Keith Thompson wrote:
> > Jean-Claude Arbaut <(E-Mail Removed)> writes:
> >> Barry Schwarz wrote:
> >>> On Wed, 03 Jun 2009 02:16:55 +0200, Jean-Claude Arbaut
> >>> <(E-Mail Removed)> wrote:

> > [...]
> >>>> t = (double (*)[])calloc(n*p, sizeof(double));
> >>> Surely you meant u here, not t.
> >> yes

>
> >>> The cast is unnecessary.
> >> Someone just told me that on fr.clc Actually it's
> >> a bad habit I got from using a bad compiler that gave
> >> a warning for uncasted (mc)alloc. I can't remember
> >> which compiler it was.

>
> > Could it have been a C++ compiler?

>
> >>> Furthermore,
> >>> all bits zero need not be the representation of 0.0. *A frequently
> >>> recommended construct is
> >>> * *t = calloc(n, sizeof *t);
> >>> or the malloc "almost equivalent"
> >>> * *t *malloc (n * sizeof *t);
> >> Does it guarantee that memory is zeroed ?

>
> > No, malloc doesn't initialize the allocated space, whereas calloc sets
> > it to all-bits-zero. *But setting it to all-bits-zero doesn't
> > guarantee that all elements will be set to 0.0, since there's no
> > guarantee that all-bits-zero is a representation of all-bits-zero.

>
> I know you meant "since there's no guarantee that all-bits-zero
> represents a floating point 0.0 (or a null pointer)".
>
> > You can probably get away with it on most (maybe all?) existing
> > systems, but it's not portable. *For guaranteed portability, you need
> > to set the elements to 0.0 using a loop -- and if you're going to do
> > that anyway you might as well just use malloc rather than calloc.
> > And, depending on what you're doing with the data, you might not need
> > to set *all* the elements to 0.0.

>
> If the OP does choose to use calloc, make sure the non-portable
> assumption is documented just in case someone ports the SW later to an
> unusual system where it is a problem.

Sounds like a good spot for an assertion;

assert(u[0][0]==0.0);

--
lxt

James Kuyper
Guest
Posts: n/a

 06-03-2009
luserXtrog wrote:
> On Jun 3, 1:03 pm, Flash Gordon <(E-Mail Removed)> wrote:
>> Keith Thompson wrote:

....
>>> it to all-bits-zero. But setting it to all-bits-zero doesn't
>>> guarantee that all elements will be set to 0.0, since there's no
>>> guarantee that all-bits-zero is a representation of all-bits-zero.

>> I know you meant "since there's no guarantee that all-bits-zero
>> represents a floating point 0.0 (or a null pointer)".

....
> Sounds like a good spot for an assertion;
>
> assert(u[0][0]==0.0);

Perhaps - but keep in mind that if all-bits-zero is a trap
representation for 'double', the left operand of the comparison
expression has undefined behavior, which means (among other less
annoying possibilities), that your assert might fail to trigger. That
pretty much eliminates it's usefulness.

For similar purposes I've used a memcmp() between a zero-initialized
object and an object of the same size memset() to all-bits-0. That
completely avoids the undefined behavior mentioned above. Unfortunately,
it doesn't cover the possibility that all-bits-zero represents a value
equivalent to a zero-initialized variable, but with a different
representation. I was willing to live with that possibility; it would
only have made my program slightly inefficient - it wouldn't have broken it.

Barry Schwarz
Guest
Posts: n/a

 06-04-2009
On Wed, 03 Jun 2009 10:36:43 +0200, Jean-Claude Arbaut
<(E-Mail Removed)> wrote:

>Barry Schwarz wrote:
>
>> On Wed, 03 Jun 2009 02:16:55 +0200, Jean-Claude Arbaut
>> <(E-Mail Removed)> wrote:
>>
>>> Hi,
>>>
>>> I can use:
>>>
>>> double get(int n, int p, double t[n][p], int i, int j) {
>>> return t[i][j];
>>> }
>>>
>>> and in another function
>>> double (*u)[];

>>
>> I believe this would need to be
>> double (*u)[p];
>> as in examples 3 and 4 in 6.7.5.2(9)-(10)

>
>There is one in n1256.pdf, p41
>And I'm not a C standard expert, but I tought
>it's legal to have one incomplete dimension.

The example on page 41 shows a pair of declarations, each of which is
partially incomplete. But as set, none of the incomplete parts remain
incomplete.

>
>gcc -Wall -std=c99 -pedantic doesn't bark at me.
>I know that doesn't prove much, but that's strange.
>
>
>
>>> t = (double (*)[])calloc(n*p, sizeof(double));

>>
>> Surely you meant u here, not t.

>
>yes
>
>> The cast is unnecessary.

>
>Someone just told me that on fr.clc Actually it's
>a bad habit I got from using a bad compiler that gave
>a warning for uncasted (mc)alloc. I can't remember
>which compiler it was.
>
>> Furthermore,
>> all bits zero need not be the representation of 0.0. A frequently
>> recommended construct is
>> t = calloc(n, sizeof *t);
>> or the malloc "almost equivalent"
>> t malloc (n * sizeof *t);

That should have been
t = malloc(n*sizeof *t)

>
>Does it guarantee that memory is zeroed ?
>
>>> a=get(n,p,u,i,j);
>>>
>>> Now, how would I declare u for 3 dimensions or more ?

>>
>> When declaring arrays in functions and pointers to arrays, only the
>> high-order dimension can be unspecified/omitted.

>
>Same remark as above.
>
>
>> If t3 is going to be defined in the function as
>> double t3[x][y][z]
>> then u3 will need to be defined as
>> double (*u3)[y][z];

>
>
>Is there really no way to allocate it ?
>I mean, it's possible with a warning to do
>
>double *p = malloc(100*sizeof(double));
>a = get(10,10,p,0,0);

This is not correct. Even if the compiler calls the diagnostic a
warning you still invoke undefined behavior. The function is
expecting a double(*)[p] and you are passing a double*. There is no
guarantee that the two pointers have the same representation or
alignment. Also there are several discussions in the archive if it is
legal to step through a 2D array as if it were a long 1D array.

>
>But what should I do to declare it correctly ?

I showed the definition of the array and the pointer above. You
assign allocated memory to the pointer with
u3 = calloc(x, sizeof *u3);
or the malloc "almost equivalent"
u3 = malloc (x * sizeof *u3);
the same as I showed for a 2D pointer.

--
Remove del for email

Scarlet Pimpernel
Guest
Posts: n/a

 06-04-2009
Keith Thompson wrote:
> Jean-Claude Arbaut <(E-Mail Removed)> writes:

>> Someone just told me that on fr.clc Actually it's
>> a bad habit I got from using a bad compiler that gave
>> a warning for uncasted (mc)alloc. I can't remember
>> which compiler it was.

>
> Could it have been a C++ compiler?

Maybe. And I guess that would mean the warning is expected

>>> Furthermore,
>>> all bits zero need not be the representation of 0.0. A frequently
>>> recommended construct is
>>> t = calloc(n, sizeof *t);
>>> or the malloc "almost equivalent"
>>> t malloc (n * sizeof *t);

>> Does it guarantee that memory is zeroed ?

>
> No, malloc doesn't initialize the allocated space, whereas calloc sets
> it to all-bits-zero. But setting it to all-bits-zero doesn't
> guarantee that all elements will be set to 0.0, since there's no
> guarantee that all-bits-zero is a representation of all-bits-zero.
>
> You can probably get away with it on most (maybe all?) existing
> systems, but it's not portable. For guaranteed portability, you need
> to set the elements to 0.0 using a loop -- and if you're going to do
> that anyway you might as well just use malloc rather than calloc.
> And, depending on what you're doing with the data, you might not need
> to set *all* the elements to 0.0.

I think I would use calloc which would be both correct and
faster on almost all machine, and document the lack of
portability.

Scarlet Pimpernel
Guest
Posts: n/a

 06-04-2009
Barry Schwarz wrote:

> I showed the definition of the array and the pointer above. You
> assign allocated memory to the pointer with
> u3 = calloc(x, sizeof *u3);
> or the malloc "almost equivalent"
> u3 = malloc (x * sizeof *u3);
> the same as I showed for a 2D pointer.
>

Ok, actually, I had in mind a declaration of multidimensional
array without dimensions, but it would probably never be
necessary, since you must know the dimensions to allocate
it.

Another possible problem, you can declare a double[p][q][r] and pass
it to a function that will use double[q][r][p]. I suppose
it's still valid C ?

And, another idea, would it be correct to use a void* like here:

double get(int n, int p, int q, double t[n][p][q],int i, int j, int k) {
return t[i][j][k];
}

double toto() {
int n,p,q;
double x;
void *a;
n = 100;
p = 200;
q = 300;
a = malloc(n*p*q*sizeof(double));
x = get(n,p,q,a,0,0,0);
return x;
}

(gcc gives no warning)