By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
426,083 Members | 2,237 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 426,083 IT Pros & Developers. It's quick & easy.

Reinitializing static array???

P: n/a
Assume I have a static array of structures the elements of which
could be any conceivable mixture of C types, pointers, arrays.
And this array is uninitialized at program startup.

If later in the program I wish to return this array to its
startup state, can this be accomplished by writing binary
zeroes to the entire memory block with memset(). E.g.,

static struct mystruct_st {
int x1;
int *x2;
double x3[10];
- - -
} myarray[20];

/* Do things with myarray */
- - -
/* Restore initial myarray */
memset(my, 0, sizeof(myarray));

(where "- - -" indicates other valid code)

Or do the initial values of the elements depend on the
version or implementation of C?

Thanks for your help.

Regards,
Charles Sullivan



Nov 15 '05 #1
Share this Question
Share on Google+
15 Replies


P: n/a
Charles Sullivan <cw******@triad.rr.com> wrote:
static struct mystruct_st {
int x1;
int *x2;
double x3[10];
- - -
} myarray[20]; /* Do things with myarray */
- - -
/* Restore initial myarray */
memset(my, 0, sizeof(myarray)); Or do the initial values of the elements depend on the
version or implementation of C?


Yes. Specifically, all-bits-zero is not guaranteed to be a valid
value for an int *; the value of NULL is implementation dependent,
which is presumably what you want x2 initialized to.

--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
Nov 15 '05 #2

P: n/a
Charles Sullivan wrote:
Assume I have a static array of structures the elements of which
could be any conceivable mixture of C types, pointers, arrays.
And this array is uninitialized at program startup.

If later in the program I wish to return this array to its
startup state, can this be accomplished by writing binary
zeroes to the entire memory block with memset().
<snip>
No, you can't, at least not portably. In particular, the all-zeroes
bitpattern is not guaranteed to initialize floating-point variables to
0.0, it is not guaranteed to be a null pointer value (or even a valid
pointer value), etc.

It is always better to explicitly initialize variables yourself, even
static ones. If you turn that into a function, you can reinitialize the
array by calling it.
Or do the initial values of the elements depend on the
version or implementation of C?

No. The initial values are all guaranteed defaults: 0 for ints, 0.0 for
doubles, null pointers for pointers, etc. The problem is, you don't know
exactly what bits are used for initialization, so memset() won't cut it.

S.
Nov 15 '05 #3

P: n/a


Charles Sullivan wrote On 10/03/05 13:16,:
Assume I have a static array of structures the elements of which
could be any conceivable mixture of C types, pointers, arrays.
And this array is uninitialized at program startup.

If later in the program I wish to return this array to its
startup state, can this be accomplished by writing binary
zeroes to the entire memory block with memset(). E.g.,

static struct mystruct_st {
int x1;
int *x2;
double x3[10];
- - -
} myarray[20];

/* Do things with myarray */
- - -
/* Restore initial myarray */
memset(my, 0, sizeof(myarray));

(where "- - -" indicates other valid code)

Or do the initial values of the elements depend on the
version or implementation of C?


A static variable is never "uninitialized" in C. It
may lack an explicit initializer, or it may have an
initializer that omits some of its constituent elements,
but if so all those "uninitialized" chunks are initialized
to zeroes of appropriate types. That is, each `int' is
initialized to `0', each `unsigned int' to `0u', each
`float' to `0.0f', each pointer to `(WhateverType*)0',
and so on.

But there's a catch: C does not specify very much about
how values are represented. For the various integer types
C promises that filling an appropriately-sized (and -aligned)
region of memory with all-bits-zero produces a zero value.
However, no such guarantee is made for `float', `double',
`long double', or pointer types. It is at least possible
that all-bits-zero is not a valid representation of `0.0f',
`0.0', or `0.0L', and may not be a valid null pointer. On
many machines it happens that these things are in fact
represented as all-bits-zero -- it's so convenient -- but
the language doesn't require it, and there are (or have been)
machines that use(d) other representations.

So: Your memset will certainly work if all the things
being zapped are integers, and will probably (but not
certainly) work if there are non-integer elements involved.
If you decide to use memset() you're running a small risk;
if you'd prefer to avoid the risk, try something like:

void clear_structs(struct mystruct_st *p, size_t n) {
const struct mystruct_st empty = { 0 };
while (n-- > 0)
*p++ = empty;
}

--
Er*********@sun.com

Nov 15 '05 #4

P: n/a

Many thanks Eric, Skarmander, and Christopher for clarifying my
thinking on this issue. Your responses and advice are much
appreciated.

Regards,
Charles Sullivan

Nov 15 '05 #5

P: n/a
Christopher Benson-Manica wrote:

Charles Sullivan <cw******@triad.rr.com> wrote:
static struct mystruct_st {
int x1;
int *x2;
double x3[10];
- - -
} myarray[20];

/* Do things with myarray */
- - -
/* Restore initial myarray */
memset(my, 0, sizeof(myarray));

Or do the initial values of the elements depend on the
version or implementation of C?


Yes. Specifically, all-bits-zero is not guaranteed to be a valid
value for an int *; the value of NULL is implementation dependent,
which is presumably what you want x2 initialized to.


But, given the definition of myarray[], doesn't the standard guarantee
that the memory will be initialized as all-bits-zero at program startup?
(Or does it guarantee that pointers will be NULL and floats/doubles will
be 0.0?)

While all-bits-zero may not be NULL or a valid double, won't the memset()
call set myarray[] back to what it was when the program started?

The following shows all "00"s on my system, but (un?)fortunately, my
system has both NULL and 0.0 represented as all-bits-zero.

==========
#include <stdio.h>

static struct
{
int i;
char *pt;
double d;
}
foo[5];

int main()
{
unsigned char *pt;
int i;

printf("sizeof = %ld\n",(long)sizeof(foo));

for ( i=0, pt=(unsigned char *)foo ; i < sizeof(foo) ; i++, pt++ )
{
if ( (i%16) == 0 )
printf("\n%03x: ",i);
if ( (i%8) == 0 )
printf(" ");
printf(" %02x",*pt);
}
printf("\n");
}
==========

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:Th*************@gmail.com>
Nov 15 '05 #6

P: n/a
Kenneth Brody wrote:
Christopher Benson-Manica wrote:
Charles Sullivan <cw******@triad.rr.com> wrote:

static struct mystruct_st {
int x1;
int *x2;
double x3[10];
- - -
} myarray[20];
/* Do things with myarray */
- - -
/* Restore initial myarray */
memset(my, 0, sizeof(myarray));

Or do the initial values of the elements depend on the
version or implementation of C?


Yes. Specifically, all-bits-zero is not guaranteed to be a valid
value for an int *; the value of NULL is implementation dependent,
which is presumably what you want x2 initialized to.

But, given the definition of myarray[], doesn't the standard guarantee
that the memory will be initialized as all-bits-zero at program startup?

No.
(Or does it guarantee that pointers will be NULL and floats/doubles will
be 0.0?)
Yes.
While all-bits-zero may not be NULL or a valid double, won't the memset()
call set myarray[] back to what it was when the program started?
No.
The following shows all "00"s on my system, but (un?)fortunately, my
system has both NULL and 0.0 represented as all-bits-zero.

Yes. :-)

S.
Nov 15 '05 #7

P: n/a
Skarmander wrote:

Kenneth Brody wrote:

[...]
Yes. Specifically, all-bits-zero is not guaranteed to be a valid
value for an int *; the value of NULL is implementation dependent,
which is presumably what you want x2 initialized to.

But, given the definition of myarray[], doesn't the standard guarantee
that the memory will be initialized as all-bits-zero at program startup?

No.
(Or does it guarantee that pointers will be NULL and floats/doubles will
be 0.0?)

Yes.


Well, that's what happens when I've apparently only worked on NULL and
0.0 are all-bits-zero platforms. The "uninitialized" global variables
are placed in a .bss (or equivalent) segment, which get initialized to
all bits zero.

Okay... Is it possible that a platform have more than one representation
of 0.0? For example, "static double d = 0.0;" could result in all-bits-
zero, but "d1 = 1.0; d2 = 1.0 ; d3 = d1-d2;" could result in some other
representation.
While all-bits-zero may not be NULL or a valid double, won't the memset()
call set myarray[] back to what it was when the program started?

No.


Given the "yes" to my parenthetical question above, the answer to this
one is obviously "no".
The following shows all "00"s on my system, but (un?)fortunately, my
system has both NULL and 0.0 represented as all-bits-zero.

Yes. :-)


:-)

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:Th*************@gmail.com>
Nov 15 '05 #8

P: n/a
Kenneth Brody <ke******@spamcop.net> writes:
[...]
Well, that's what happens when I've apparently only worked on NULL and
0.0 are all-bits-zero platforms. The "uninitialized" global variables
are placed in a .bss (or equivalent) segment, which get initialized to
all bits zero.

Okay... Is it possible that a platform have more than one representation
of 0.0? For example, "static double d = 0.0;" could result in all-bits-
zero, but "d1 = 1.0; d2 = 1.0 ; d3 = d1-d2;" could result in some other
representation.


Theoretically, yes. It's common for a floating-point format to have
distinct representations for +0.0 and -0.0; whether 1.0-1.0, or any
other operation, might yield -0.0 is a question I won't try to answer.

[...]

One good way to get a "zero" value for a structure type is:

struct my_struct {
... member declarations ...
};
struct my_struct my_struct_zero = { 0 };

All members of my_struct_zero will be properly initialized to zero
values (0, '\0', 0.0, NULL), *not* necessarily to all-bits-zero. You
can then do:

struct my_struct obj = { 0 };
... play with obj ...
... Now we need to reset it to its initial value ...
obj = my_struct_zero;

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #9

P: n/a
Keith Thompson wrote:

<snip>
One good way to get a "zero" value for a structure type is:

struct my_struct {
... member declarations ...
};
struct my_struct my_struct_zero = { 0 };
I would suggest using
const struct my_struct_zero = { 0 };
So the compiler complains about any attempt to modify it otherwise
things very puzzling to another programmer could happen.
All members of my_struct_zero will be properly initialized to zero
values (0, '\0', 0.0, NULL), *not* necessarily to all-bits-zero. You
can then do:

struct my_struct obj = { 0 };
... play with obj ...
... Now we need to reset it to its initial value ...
obj = my_struct_zero;

--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
Nov 15 '05 #10

P: n/a
Flash Gordon <sp**@flash-gordon.me.uk> writes:
Keith Thompson wrote:
One good way to get a "zero" value for a structure type is:
struct my_struct {
... member declarations ...
};
struct my_struct my_struct_zero = { 0 };


I would suggest using
const struct my_struct_zero = { 0 };
So the compiler complains about any attempt to modify it otherwise
things very puzzling to another programmer could happen.


Yes, thanks for the improvement.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #11

P: n/a
in comp.lang.c i read:
Assume I have a static array
[...] uninitialized at program startup.
which is to say implicitly initialized, every member of every element to
the type's zero value, whether that means all bits zero or something else.
If later in the program I wish to return this array to its
startup state, can this be accomplished by writing binary
zeroes to the entire memory block with memset(). E.g.,


not portably.

use a second static object, and memcpy if it's an array. if the array is
large a single element and a loop.

--
a signature
Nov 15 '05 #12

P: n/a

Eric Sosman wrote:
Charles Sullivan wrote On 10/03/05 13:16,:
Assume I have a static array of structures the elements of which
could be any conceivable mixture of C types, pointers, arrays.
And this array is uninitialized at program startup.

If later in the program I wish to return this array to its
startup state, can this be accomplished by writing binary
zeroes to the entire memory block with memset(). E.g.,

static struct mystruct_st {
int x1;
int *x2;
double x3[10];
- - -
} myarray[20];

/* Do things with myarray */
- - -
/* Restore initial myarray */
memset(my, 0, sizeof(myarray));

(where "- - -" indicates other valid code)

Or do the initial values of the elements depend on the
version or implementation of C?
A static variable is never "uninitialized" in C. It
may lack an explicit initializer, or it may have an
initializer that omits some of its constituent elements,
but if so all those "uninitialized" chunks are initialized
to zeroes of appropriate types. That is, each `int' is
initialized to `0', each `unsigned int' to `0u', each
`float' to `0.0f', each pointer to `(WhateverType*)0',
and so on.

But there's a catch: C does not specify very much about
how values are represented. For the various integer types
C promises that filling an appropriately-sized (and -aligned)
region of memory with all-bits-zero produces a zero value.
However, no such guarantee is made for `float', `double',
`long double', or pointer types. It is at least possible
that all-bits-zero is not a valid representation of `0.0f',
`0.0', or `0.0L', and may not be a valid null pointer. On
many machines it happens that these things are in fact
represented as all-bits-zero -- it's so convenient -- but
the language doesn't require it, and there are (or have been)
machines that use(d) other representations.

So: Your memset will certainly work if all the things
being zapped are integers, and will probably (but not
certainly) work if there are non-integer elements involved.
If you decide to use memset() you're running a small risk;
if you'd prefer to avoid the risk, try something like:

void clear_structs(struct mystruct_st *p, size_t n) {
const struct mystruct_st empty = { 0 };
while (n-- > 0)
*p++ = empty;


why not the much simpler
*p = empty;

And there is no need for the argument 'n'

Am I missing something? BTW {0} syntax in the init may not
work in the first member in mystruct_st itself is a struct.
It may need {{0}} or even {{{0}}} (If that struct also had a struct
as first member)

Karhik

}

--
Er*********@sun.com


Nov 15 '05 #13

P: n/a

In article <11**********************@o13g2000cwo.googlegroups .com>, "ka*****@gmail.com" <ka*****@gmail.com> writes:

BTW {0} syntax in the init may not
work in the first member in mystruct_st itself is a struct.
It may need {{0}} or even {{{0}}} (If that struct also had a struct
as first member)


No, it need not. {0} is always a valid initializer for an object
of any complete type, or an array of unknown size. (Obviously it's
not valid for objects of incomplete type, namely incomplete structs
and unions and variable-length arrays.)

For scalar objects, {0} follows from ISO 9899-1999 6.7.8 #11. For
aggregate and union objects, {0} follows from the same section, #13,
#16, #17, and #19-#22. See also (non-normative) footnote 127.

Chapter and verse if you believe otherwise, please.

--
Michael Wojcik mi************@microfocus.com

The lark is exclusively a Soviet bird. The lark does not like the
other countries, and lets its harmonious song be heard only over the
fields made fertile by the collective labor of the citizens of the
happy land of the Soviets. -- D. Bleiman
Nov 15 '05 #14

P: n/a
Michael Wojcik wrote:
In article <11**********************@o13g2000cwo.googlegroups .com>, "ka*****@gmail.com" <ka*****@gmail.com> writes:

BTW {0} syntax in the init may not
work in the first member in mystruct_st itself is a struct.
It may need {{0}} or even {{{0}}} (If that struct also had a struct
as first member)
No, it need not. {0} is always a valid initializer for an object
of any complete type, or an array of unknown size. (Obviously it's
not valid for objects of incomplete type, namely incomplete structs
and unions and variable-length arrays.)

For scalar objects, {0} follows from ISO 9899-1999 6.7.8 #11. For
aggregate and union objects, {0} follows from the same section, #13,
#16, #17, and #19-#22. See also (non-normative) footnote 127.

Chapter and verse if you believe otherwise, please.


You could be right since I have only seen the behavior of gcc
in such a case. As you say, probably it is very valid C. I double
checked, it is just that gcc is emitting different warnings. It does
produce correct runtime behavior though.

$>cat struct_init.c
#include <stdio.h>
#include <stdlib.h>
typedef struct foo_phy_st_ {
int age;
int ht;
int wt;
} foo_phy_st;

typedef struct foo_edu_st_ {
int years;
} foo_edu_st;
typedef struct foo_person_st_ {
foo_phy_st phy;
foo_edu_st edu;
} foo_person_st;


int main (void)
{
#ifdef MULTI_BRACES
foo_person_st a = {{0}};
#else
foo_person_st a = {0};
#endif
printf("%d %d\n", a.phy.age, a.edu.years);
return 0;
}

$> gcc -Wall -W -ansi -pedantic struct_init.c
struct_init.c: In function `main':
struct_init.c:25: warning: missing braces around initializer
struct_init.c:25: warning: (near initialization for `a.phy')
struct_init.c:25: warning: missing initializer
struct_init.c:25: warning: (near initialization for `a.phy.ht')
struct_init.c:25: warning: missing initializer
struct_init.c:25: warning: (near initialization for `a.edu')
$> gcc -Wall -W -ansi -pedantic -DMULTI_BRACES struct_init.c
struct_init.c: In function `main':
struct_init.c:23: warning: missing initializer
struct_init.c:23: warning: (near initialization for `a.phy.ht')
struct_init.c:23: warning: missing initializer
struct_init.c:23: warning: (near initialization for `a.edu')
$> gcc -ansi -pedantic struct_init.c
struct_init.c: In function `main':
struct_init.c:25: warning: missing braces around initializer
struct_init.c:25: warning: (near initialization for `a.phy')
struct_init.c:25: warning: missing initializer
struct_init.c:25: warning: (near initialization for `a.phy.ht')
struct_init.c:25: warning: missing initializer
struct_init.c:25: warning: (near initialization for `a.edu')
$> gcc struct_init.c
struct_init.c: In function `main':
struct_init.c:25: warning: missing braces around initializer
struct_init.c:25: warning: (near initialization for `a.phy')
struct_init.c:25: warning: missing initializer
struct_init.c:25: warning: (near initialization for `a.phy.ht')
struct_init.c:25: warning: missing initializer
struct_init.c:25: warning: (near initialization for `a.edu')

$> gcc -Wall -W -ansi -std=c99 -pedantic struct_init.c
struct_init.c: In function `main':
struct_init.c:25: warning: missing braces around initializer
struct_init.c:25: warning: (near initialization for `a.phy')
struct_init.c:25: warning: missing initializer
struct_init.c:25: warning: (near initialization for `a.phy.ht')
struct_init.c:25: warning: missing initializer
struct_init.c:25: warning: (near initialization for `a.edu')

$> gcc --version
gcc (GCC) 3.3.3 (Yellow Dog Linux 3.3.3-16.ydl.8)
Copyright (C) 2003 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is
NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.

Karthik
--
Michael Wojcik mi************@microfocus.com

The lark is exclusively a Soviet bird. The lark does not like the
other countries, and lets its harmonious song be heard only over the
fields made fertile by the collective labor of the citizens of the
happy land of the Soviets. -- D. Bleiman


Nov 15 '05 #15

P: n/a

In article <11*********************@g43g2000cwa.googlegroups. com>, "ka*****@gmail.com" <ka*****@gmail.com> writes:
Michael Wojcik wrote:
In article <11**********************@o13g2000cwo.googlegroups .com>, "ka*****@gmail.com" <ka*****@gmail.com> writes:

BTW {0} syntax in the init may not
work in the first member in mystruct_st itself is a struct.
It may need {{0}} or even {{{0}}} (If that struct also had a struct
as first member)


No, it need not. {0} is always a valid initializer for an object
of any complete type, or an array of unknown size.


You could be right since I have only seen the behavior of gcc
in such a case. As you say, probably it is very valid C. I double
checked, it is just that gcc is emitting different warnings.


The behavior of an implementation - even the behavior of *all*
implementations - does not define the language; the standard does.
Obviously, if commonly-used implementations deviate from the standard
in some way (which is not the case with gcc here; I'm just hypothe-
sizing), it may be practical to write for them rather than for the
language as it's actually defined. However, it's usually unwise to
make claims here that are backed up only by experimenting with a
single implementation. If you wish to do so anyway, I recommend
qualifying them ("With gcc, ...").

Of course an implementation can emit whatever diagnostics it likes,
even if it's complaining about a perfectly valid and useful
construct.

[OT] Splint also complains about {0} as an initializer in some
cases, such as when initializing an array of struct. Very annoying;
it's on my list of misfeatures to fix. (I am, on the whole, not
very fond of Splint, but it's one of the better choices among the
free tools. I may yet seek budget for switching my group to a
commercial tool for C static defect analysis, though.)

--
Michael Wojcik mi************@microfocus.com

Push up the bottom with your finger, it will puffy and makes stand up.
-- instructions for "swan" from an origami kit
Nov 15 '05 #16

This discussion thread is closed

Replies have been disabled for this discussion.