The short answer is, "it does not".
More precisely, "char **var" declares "var" as a variable of *type*
"pointer to pointer to char". Whether "var" actually points to
anything at all (much less "anything useful") is up to you, the
programmer.
And I realize that with var[], var is actually a memory address (or at
least as it is represented by C, IIRC (an internal copy which is a fixed
pointer)) pointing (permanently) to the first element of an array.
This is also wrong, or at least, not quite right.
There are some "gotchas" with array declarations that do not occur
with pointers, so we have to start adding more context. If we write,
for instance:
int arr1[8] = { 1, 2, 3, 0 };
outside of a function, or inside a block, we have both declared
and defined "arr1" as a variable of type "array 8 of int" (to use
the "cdecl" program's syntax). Because we initialized the array,
we can omit the size, and have the compiler figure it out:
int arr2[] = { 1, 2, 3, 0 };
but now we get an "array 4 of int", because we only used four
initializers.
On the other hand, we have a peculiar feature of the C language in
which function parameters that *look like* arrays are actually
declared as pointers. If we write:
void somefunc(char s[]) {
/* code */
}
the compiler is obligated to pretend that we actually wrote:
void somefunc(char *s) {
/* code */
}
That is, the local-variable "s" within the function somefunc() has
type "pointer to char", rather than "array MISSING_SIZE of char".
The reason for this peculiar feature has to do with what I call
"The Rule" about arrays and pointers in C, combined with the fact
that C passes arguments by value. For (much) more about The Rule,
see <
http://web.torek.net/torek/c/pa.html>.
Except for some new features in C99 intended for optimization,
there is never any reason you *have* to use the array notation to
declare formal parameter names in function definitions, and I
encourage programmers to use the pointer notation, so that the
declaration is not misleading: since "s" inside somefunc() has type
"char *", we should all declare it as "char *" in the first place.
Ever since the C89 standard came out, something peculiar happens
if we write:
int arr3[];
outside a function. This is a "tentative definition" of the
array "arr3", and if we reach the end of a translation unit (roughly,
"C source file") without coming across any more details for arr3[],
it acts as if we had written:
int arr3[1] = { 0 };
On the other hand, though, if we try to use empty square brackets
*inside* a function (not as a parameter but inside the {}s):
void wrong(void) {
int arr4[]; /* ERROR */
/* more stuff */
}
we have done something wrong. Empty square brackets are not allowed
here.
Finally, C99 has something called a "flexible array member" of
structures, which we can ignore for now, but does give you one more
place where you can write empty square brackets and have it mean
something special.
All of these are just things you have to memorize -- quirks about
C that "are just the way they are": not for any particular reason
other than that Dennis Ritchie and/or the C standards folks said
so. They all make it a little more tricky to talk about arrays in
C.
And I realize that *var[] is an array of pointers where each
pointer can point to the beginning of a string (or whatever).
If it is indeed an array at all -- for instance, if we write:
char *arr5[100];
either outside or inside a function (not as a parameter to a
function), then arr5 has type "array 100 of pointer to char", and
each of those 100 "pointer to char"s can point to the first of a
sequence of "char"s making up a C string.
Again, "it does not"...
In the declaration 'char var[];' var, when used by itself is just a
pointer to the first element ...
I think it is better to say that it *becomes* a pointer to the
first element of the array.
This is The Rule about arrays and pointers in C:
In a value context, an object of type "array N of T" becomes
a value of type "pointer to T", pointing to the first element
of that array, i.e., the one with subscript zero.
The compiler has to *produce* this pointer, often using a single
machine instruction. The array itself is a C object -- something
occupying memory, and (we can hope) holding some useful values --
but the pointer the C compiler comes up with is a mere "value"
(an "rvalue", in typical computer-science lingo).
The Rule is yet another arbitrary rule, something else you have to
memorize about C. It is *so* important, and used so often, though,
that it is not "just" another rule, it is *The* Rule: The Rule
about arrays and pointers in C. Memorize it, work with it, until
it seems natural, and then all this pointer stuff in C will start
to make sense.
Note that The Rule applies only to *objects* in *value contexts*.
You have to be able to distinguish between objects and values, and
spot the contexts, but this is pretty easy if you have done any C
programming, or even much programming in other languages. If you
have statements like:
a = 17;
b = a + 25;
you know that "a" gets set to 17, and "b" gets set to 42. But how
is it that we *set* "a" on the first line, then *get* its value to
add 25 to it on the second line? The answer is "object" vs "value"
contexts. The "a =" part means "set a" -- set the object. The
"17" part just means "the value 17". The "b =" part means we will
set "b" (the object), and the "a + 25" part means we will fetch
the value in "a" and add 25.
Most of these contexts are obvious -- the left side of an "="
operator is an "object context", and the right side is a "value
context". C has a lot of operators, though, and there are two
important ones that have "object context": the unary-& operator,
which takes the address of an object, and the sizeof operator,
which produces the size (in "C bytes") of an object.
Most of the other operators have value context, and if you name an
object, such as an ordinary variable, you get the object's value.
For ordinary "int"s and "double"s and such, the value of the object
is whatever value you last stored in the variable. For arrays,
the value is that produced by The Rule.
You can either use this value right away -- printing it out, or
applying some operator to it, for instance -- or you can store it
in an object. Consider what happens if we choose to store the
value the compiler produces when we apply The Rule to "arr5".
Remember that "arr5" has type "array 100 of pointer to char":
char *arr5[100];
and that The Rule says:
In a value context,
(yep, got one of those)
an object of type "array N
(check -- that is what we have; N here is 100)
of T"
(and T is "pointer to char")
becomes a value of type "pointer to T",
(pointer to pointer to char)
pointing to the first element of the array, i.e., the one
with subscript zero.
So if we want to store this value in an object, we need one of
type "pointer to pointer to char", or "char **":
char **holder;
holder = arr5;
(Note that the array's size -- the constant named N, 100 in this
case -- gets throw away. We are allowed to ignore it when working
with The Rule. It is a darn good idea to save it away somewhere
else, though, because if the array has 100 elements, we had better
not write over arr5[231], which does not exist. The Rule tosses
the constant, so in practical code, *we* have to save it -- the
language threw it away, but it really does matter. For now, we
will ignore it, and perhaps cross fingers, toes, and/or eyes and
hope we do not use an out-of-bounds array subscript later. Or
maybe we will occasionally check, remembering the size is 100.)
Now "holder" stores the value produced by The Rule: a value of
type "pointer to pointer to char", pointing to the first element
of arr5 -- &arr5[0], in other words.
This is where things get interesting. Suppose we now want to use
the value with the subscript operators, or with ordinary pointer
arithmetic. It may be time to remember that subscripts are in fact
defined in terms of pointer arithmetic, and the unary "*"
pointer-following operator:
a
"means":
*((a) + (i))
where the addition uses pointer arithmetic. We fetch the values
of the two operands -- the array "a" and the index "i" -- and add
them, then we use pointer-follower-"*" to find the object in that
slot in the array.
But wait! I just said "we use the value of the array"! There it
goes again: The Rule tells us how to find the "value" of an array
object in a value context. If "a" is an array, The Rule says that
we find its value by dropping the constant N, and then taking the
address of its first element.
This is exactly what we did when we stuck the "value" of arr5 into
the variable named "holder"! If "holder" holds the value that
gets produced by The Rule, what difference is there between:
arr5 /* i.e., *((arr5) + (i)) */
and:
holder /* i.e., *((holder) + (i)) */
? The answer is: there is no significant difference at all --
"arr5" has The Rule applied, producing a value, but "holder" is
used in a value context, pulling the *same* value out of it. The
only real difference is in the machine instruction(s) used to create
the value the first time (by applying The Rule), or to pull the
value out of the "holder" variable.
Of course, if we use *different* operators, we can get different
results. In particular, the sizeof operator has "object context"
instead of "value context":
size1 = sizeof arr5;
size2 = sizeof holder;
will set size1 to some fairly large number (like 200, 400, or 800)
and size2 to some small number (like 2, 4, or 8) on today's machines;
so "arr5" and "holder" really are very different. Their *values*
are the same, though, due to The Rule, and to us setting "holder"
to the value The Rule creates for "arr5".
In short: arrays are not pointers; but, due to The Rule, the "value"
of an array *is* a pointer, so a pointer is "just as good" as the
actual array, if you only want the value. (But the pointer *MUST*
be set to the right value first! Arrays are collections of lots
of objects -- N of them, where N is the size in the array definition
-- while a pointer is just *one* object. To use it like an array,
you have to point it at enough memory to hold all N objects.)
[skipping a bunch of stuff]
any string that's in quotes in a C program gets stored in a read-only
part of your program when it's running ...
Well, maybe: it *may* be read-only, and as a programmer, you are
expected not to write on it. If you *do* write on it, the language
makes no promises; things can go very wrong. So you should treat
it as if it is read-only, even if it happens not to be.
Also, this is not true for "any" string, just "most" of them (as
you noted later, in something I snipped later).
so the line:
char *str = "Confused";
gets coppied inot the read-only memory as soon as your program sees it,
then assigns that address to str, which is why you can't change strings
like that.
More precisely, string literals -- those things inside double quotes
-- are a shorthand for creating anonymous arrays of "char". These
arrays may be stored in read-only areas (and high-quality C compilers
should strive to make sure they are). There is an exception for
string literals used to initialize arrays of "char"s, so that:
char buf[] = "hello";
is not required to create one of those anonymous arrays (you have
a perfectly good, non-anonymous, array named "buf"; why bother with
two copies of the character sequence 'h' 'e' 'l' 'l' 'o' '\0'?).
But other cases do create the anonymous arrays.
Logically speaking, these anonymous arrays *should* have type
"const char [N]":
const char __internal_string_00000[9] =
{ 'C', 'o', 'n', 'f', 'u', 's', 'e', 'd', '\0' };
because they are supposed to be read-only; but for historical
compatibility with C from the 1970s and 1980s, the "const" is
left off of the type. The string literal "Confused" thus has
type "array 9 of char" -- 9 because there are nine bytes inside
it, counting the terminating '\0' -- instead of "array 9 of
const char".
Since this is an array, it -- like all arrays -- is once again
subject to The Rule. You can write:
str = "Confused"; /* just like: str = __internal_string_00000; */
to make str point to the uppercase 'C' -- the first element
of the array.
Every string literal (except those that initialize arrays of char)
generates, inside the compiler, another one of these
"__internal_string_01234[]" style arrays, and every one of these
arrays is another candidate for The Rule. (Identical string literals
may or may not reuse an already-internally-generated array -- this
part is up to the compiler. Note also that "Hel-LO, World", and
"O, World" could actually share a single array, if the compiler is
sufficiently clever/sneaky, because they both *end* with the same
sequence.)
when you call printf() with that str pointer as one of the
args, it simply goes to that location in read-only memory and reads it.
Indeed, every time you pass a string literal to printf() for the
format argument:
printf("str is `%s'\n", str);
you create another one of these anonymous arrays and apply The
Rule. (See how often The Rule gets used? Almost every printf()
in every C program has at least one occurrence.)
Note that the anonymous array *is* still an array, not a pointer;
if you apply one of the "object context" operators to it, it stays
an array. In particular, if you apply the sizeof operator, you
should get the size of the array, *not* the size of a pointer:
int sz = sizeof "the anonymous array for this string literal";
*must* set sz to 44 (if I counted right) -- 43 characters plus the
terminating '\0'. Likewise, we can even do weird things like:
char (*p1)[44] = &"the anonymous array for this string literal";
The "&" operator produces the address of the anonymous array,
just as if we had written out a named array:
char some_name[44] = "...";
char (*p2)[44] = &some_name;
except that the entire array to which "p1" points is read-only,
despite not being const-qualified. (We could const-qualify the
some_name array and p2, and even const-qualify p1 except for
some brokenness in C's type system. This brokenness is what you
get when a committee designs the thing.
)
(Some C compilers have gotten string literals wrong, historically,
producing pointers instead of arrays. There are only two ways to
tell in legitimate C code, using sizeof and unary "&". That is,
only the tricks shown here with "sz" and "p1" will expose the
difference, because The Rule is so darn ubiquitous.)