Reinitializing static array???

Discussion in 'C Programming' started by Charles Sullivan, Oct 3, 2005.

  1. 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
    Charles Sullivan, Oct 3, 2005
    #1
    1. Advertising

  2. Charles Sullivan <> 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.
    Christopher Benson-Manica, Oct 3, 2005
    #2
    1. Advertising

  3. Charles Sullivan

    Skarmander Guest

    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.
    Skarmander, Oct 3, 2005
    #3
  4. Charles Sullivan

    Eric Sosman Guest

    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;
    }

    --
    Eric Sosman, Oct 3, 2005
    #4
  5. Re: Reinitializing static array??? - Thanks!!!

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

    Regards,
    Charles Sullivan
    Charles Sullivan, Oct 3, 2005
    #5
  6. Christopher Benson-Manica wrote:
    >
    > Charles Sullivan <> 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:>
    Kenneth Brody, Oct 3, 2005
    #6
  7. Charles Sullivan

    Skarmander Guest

    Kenneth Brody wrote:
    > Christopher Benson-Manica wrote:
    >
    >>Charles Sullivan <> 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.
    Skarmander, Oct 3, 2005
    #7
  8. 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:>
    Kenneth Brody, Oct 4, 2005
    #8
  9. Kenneth Brody <> 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) <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.
    Keith Thompson, Oct 4, 2005
    #9
  10. Charles Sullivan

    Flash Gordon Guest

    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.
    Flash Gordon, Oct 4, 2005
    #10
  11. Flash Gordon <> 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) <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.
    Keith Thompson, Oct 4, 2005
    #11
  12. 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
    those who know me have no need of my name, Oct 17, 2005
    #12
  13. Charles Sullivan

    Guest

    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


    > }
    >
    > --
    >
    , Oct 20, 2005
    #13
  14. In article <>, "" <> 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

    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
    Michael Wojcik, Oct 20, 2005
    #14
  15. Charles Sullivan

    Guest

    Michael Wojcik wrote:
    > In article <>, "" <> 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
    >
    > 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
    , Oct 20, 2005
    #15
  16. In article <>, "" <> writes:
    > Michael Wojcik wrote:
    > > In article <>, "" <> 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

    Push up the bottom with your finger, it will puffy and makes stand up.
    -- instructions for "swan" from an origami kit
    Michael Wojcik, Oct 21, 2005
    #16
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Natan

    Static vs. non-static connection

    Natan, May 24, 2004, in forum: ASP .Net
    Replies:
    8
    Views:
    7,304
    Sami Vaaraniemi
    May 26, 2004
  2. Peter B. Steiger

    Can a static array contain a dynamic array of pointers?

    Peter B. Steiger, Apr 19, 2004, in forum: C Programming
    Replies:
    8
    Views:
    2,080
    Dave Thompson
    Apr 26, 2004
  3. Replies:
    2
    Views:
    1,538
    Jack Klein
    Jul 14, 2005
  4. Replies:
    23
    Views:
    837
    Chris Thomasson
    Aug 29, 2007
  5. JCD

    reinitializing an applet

    JCD, Aug 3, 2008, in forum: Java
    Replies:
    20
    Views:
    711
    Joshua Cranmer
    Aug 5, 2008
Loading...

Share This Page