[comp.sys.mac.programmer] Think C: Initialization puzzle??

billf@hpcvlx.cv.hp.com (Bill F. Faus) (03/23/90)

Question:

    Can someone help me understand why this initialization is legal:

        char     a[] = "hunky dory";
        char *   p = a;

        char     b = 'x';
        char *   q = &b;  

   And this isn't:

       char *    q = "wishy washy";
       char *    p = q;

   This question has come up as I want to initalize 120K of string
   data and use the STRS option of Think C so I don't have to worry
   about data segments.  As in:

       char *    bit_map_A  = "\012\013\014....";
       char *    bit_map_B  = "\230\231\232....";
                 .........
       char *    bit_map_ZZ = "\001\002\003....";


   If instead I had used char arrays instead of char pointers:
 
       char *    bit_map_A[] = "\012\013\014...."; 

   Then I could subsequently intialize an array of bitmaps like:

       char *    bit_map_ptr[] = {bit_map_A, bit_map_B, ...., bit_map_ZZ};

   The 'bind' I get in is that arrays intialized with string literals 
   get allocated in the main data segment, so I run out of room but
   I CAN use the nifty feature of referring to the array name in
   subsequent initialization statments. Whereas pointers initialized to 
   string literals get allocated to the automatic STRS data segments
   but I CANNOT refer to the pointer names in subsequent initialization
   statements.

---------------
billf@cv.hp.com

wilson@ernie.Berkeley.EDU (James E. Wilson) (03/26/90)

In article <101780005@hpcvlx.cv.hp.com> billf@hpcvlx.cv.hp.com (Bill F. Faus) writes:
>    Can someone help me understand why this initialization is legal:
>        char     a[] = "hunky dory";
>        char *   p = a;
>
>        char     b = 'x';
>        char *   q = &b;  
>
>   And this isn't:
>       char *    q = "wishy washy";
>       char *    p = q;

Although pointers and arrays are generally equivalent, there are some
very important differences between them.

In short, when specifying an initial value for a global or static variable,
the value must be a constant known at compile time.  This is true for 'a'
which is an array and for '&b' which is the address of a variable, but is
not true for 'q' which is a pointer.  A longer explanation follows.

First of all, since 'a' is declared as an array, space is allocated for its
contents.  However, no space is allocated for 'a' itself.  The value of
'a' is the address where the array contents are stored, and this value
is a compile-time constant.

If you think of 'a' as a constant, then this explains why arrays behave as
they do.  For example, "a = q;" is illegal because you can't modify the
value of constants.  "char *p = a;" is legal because 'a' is a constant
known at compile time.

Also, this explains why "p = &a;" makes no sense.  You can not take
the address of an array 'a', because it is a constant, and hence does not have
an address.  You should think of "p = &a;" as equivalent to "p = &1000;" which
also make no sense.  What happens when you write this depends on what compiler
you are using.  Some compilers treat this the same as "p = a"; some
compilers say "Warning: ampersand before array ignored" and treat it
the same as "p = a"; and finally, some compilers consider this an error
and will refuse to compile it.  It is best to write "p = a" assuming that
that is what you meant.  If you really wanted a doubly indirect pointer
to the array, then declare a variable to hold the address of the array,
and then take the address of the new variable.

Secondly, "char *q = &b;" is legal because 'b' is a variable (of type char),
and its address is a constant known at compile time.

Thirdly, "char *p = q;" is not legal because 'q' is a char pointer, and
the value of 'q' is NOT a constant.

>   This question has come up as I want to initalize 120K of string
>   data and use the STRS option of Think C so I don't have to worry
>   about data segments.  As in:
>       char *    bit_map_A  = "\012\013\014....";
>                 .........
>       char *    bit_map_ZZ = "\001\002\003....";
>
>   If instead I had used char arrays instead of char pointers:
>       char *    bit_map_A[] = "\012\013\014...."; 
>   Then I could subsequently intialize an array of bitmaps like:
>       char *    bit_map_ptr[] = {bit_map_A, bit_map_B, ...., bit_map_ZZ};

"char * bit_map_A[] = "\012..." will give a type mismatch error, I assume
you mean "char bit_map_A[] = "\012..."

The easiest solution would be to define an array of "char **", and put the
addresses of your strings in it, i.e.
	char *bit_map_A = "\012..."
	...
	char *bit_map_ZZ = "\001..."
and then
	char **bit_map_ptr[] = {&bit_map_A, &bit_map_B, ..., &bit_map_ZZ};

Alternatively, you can write a small program which will read in the
string values (from a ascii file with scanf() or from a binary data file
with fgets()) and then write them into appropriately sized resources,
and then save the resources into a file.  Then to use them, for example,
	char **bit_map_A;
	bit_map_A = GetResource(...);
and then bit_map_A[0] is a string.  This works best with simple data
structures, though.  Creating an array of string pointers is tricky.
It is much easier to create an array of fixed sized strings as a resource.

Jim Wilson			wilson@ernie.Berkeley.EDU
"...black men in Harlem (a part of New York City) were less likely to reach the
age of 65 than men in Bangladesh (one of the worlds poorest nations)..."
  -- New England Journal of Medicine, January 1990