Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which one is the correct address of this char array in C?

#include<stdio.h>
int main()
{
  char *str1 = "computer";

  printf ("%p\n", (void *)   str1);   // i
  printf ("%p\n", (void *)  &str1);   // ii
  printf ("%d\n",           *str1);   // iii
  printf ("%p\n", (void *)  *&str1);  // iv
  printf ("%p\n", (void *)  &*str1);  // v

  return 0;
}

I know that & is the 'address of' operator and * is the 'value at address' operator. According to me,

i. This is the address of the char array since the name of the array represents the address of the first element.

ii. I do not understand this as address of an address seems confusing.

iii. This should represent the value at address (that is computer) but the format specifier is %p and a random number gets printed in the output.

iv. This should mean value at address of address. This is again confusing.

I'm getting random values in the output. I understand that some of these could be because of undefined behavior. But if someone could clarify the meaning of these, I will be very grateful.

I also want to say that

printf ("%p\n",  **str1);
printf ("%p\n",  &&str1);

give compilation failed errors.

like image 916
aste123 Avatar asked Sep 15 '25 18:09

aste123


1 Answers

The only array in the sample code is the one produced by the string literal:

"computer"

In most contexts,1 a string literal in C directs the compiler to produce (or act as if it had produced) an array somewhere in memory, with the contents of that array filled with the characters making up the string literal. You are not allowed to write on the array elements—as if the array had type const char [N] for the appropriate integer constant N—but the array itself actually has type char [N]. (The array may be, and on most modern compilers is-if-possible, placed in physically-read-only storage such as ROM or text space, although many compilers have directives that can affect this. As others noted the rules are a bit different for C++. The integer constant N is determined by the number of characters in the string literal, with a terminating '\0' char added.)

In general, given a variable v of type "array N of T" (for some type T), you simply write &v to get its address. This is a value of type "pointer to array N of T". This works for string literals as well:2

char (*p_a)[6] = &"hello";

Here p_a is a pointer to the array. The difference between this and:

char *p_c = "world";

is that p_c is a pointer to a single char rather than a pointer to the (entire) array. Hence p_c[1] is the second char in that array, the 'o'. But p_a[1] would be the entire 6-char-long array that follows the first array "hello", if there were such an array (there is not one, and hence attempting to access p_a[1] produces undefined behavior).

Literally speaking, then, the answer to the question as asked is "none of them". None of these expressions point to the entire array all at once!

Since we know that "computer" consists of 9 chars—the eight visible chars and the one terminating '\0'—we can take the value stored in str1, which is a pointer to the first of those 9 chars, and convert it (via casts and/or assignments) into the correct type, char (*)[9], in order to get "the address of the (entire) array":

char (*answer_1)[9] = (void *)str1;

or:

((char (*)[9]) str1); /* answer2: produce the value, then ignore it */

for instance.

The thing about pointers and arrays in C, though, is that a pointer to the first element of an array is, for all practical purposes, "just as good" as a pointer to the entire array. Hence just plain str1, which is a pointer to the first element of the 9-char-long array, is "just as good" as a pointer to the entire 9-char-long array.

This all sounds bizarre to people new to C. Ages ago, I made up a graphic that displays the key difference; it can be found here. The essence of the difference is the "size of the circle" rather than the "address value" itself.

Item number 2 (or I should say "ii") in your list, &str1, uses the fact that you have an actual object, str1, of type "pointer to char". The address-of operator & gets you a pointer to that object: a value of type "pointer to (pointer to char)", or char **. The value itself can be thought of as an arrow pointing to the variable str1, while the value stored in str1 itself can be thought of as an arrow pointing to the c in "computer".


1The main exception here is when the string literal is used as an initializer. For instance:

char ch_array[9] = "computer";

exactly fills the 9-char-long array ch_array, without necessarily creating a second array anywhere. In these cases you can control the actual const-ness of the resulting array; ch_array is not const and is something you can write to, so you can change the letters in this array, making it read "catputer", for instance, if you wish.

The C standards also allow you to make the array one element "too short", i.e., to fail to hold the terminating '\0'. In this case the terminator is simply not stored anywhere. There is no standard way to do this without creating such an object, although there was a proposal, which went nowhere, to use a final \z escape inside a string literal to get the same result.

Note that string concatenation:

char *x = "com" "put" "er";

does not insert the terminating '\0' between parts: the terminator is added after concatenation. And, since writing on the anonymous array generated here produces undefined behavior, a compiler can (and good ones do) share string literals as well, possibly with "tail sharing",3 so that:

char *s1 = "hello world", *s2 = "world";

might generate only one array, holding the "hello world" string, and make s2 point to the w within that string.

2Back in the 1980s, a lot of compilers got this wrong. To be fair, there was no standard for C at the time: the original ANSI C standard came out in December of 1989, so it was not until 1990 that there were any official rules one could apply to compiler-writers.

3"Tail sharing" is not a term of art, just a phrase I've made up here to attempt to describe the process.

like image 98
torek Avatar answered Sep 18 '25 10:09

torek