Home > Back-end >  I made array of pointer. What is difference between names and names[0]?
I made array of pointer. What is difference between names and names[0]?

Time:09-21

https://i.stack.imgur.com/7Fgkp.jpg output)this the link for image of output

my code ---->

#include <stdio.h>
 
const int MAX = 5;
 
int main () {

   char *names[] = {
      "Zara Ali",
      "Hina Ali",
      "Nuha Ali",
      "Sara Ali",
      "Zara Ali"
   };
   
   int i = 0;

   for ( i = 0; i < MAX; i  ) {
      printf("Value of *names[%d] = %c char\n", i, *names[i] );
   }
  
   for ( i = 0; i < MAX; i  ) {
      printf("Value of *(names %d) = %d\n", i, *(names i) );
   }
   for ( i = 0; i < MAX; i  ) {
      printf("Value of names[%d] = %d\n", i, names[i] );
   }
   for ( i = 0; i < MAX; i  ) {
      printf("Value of *(names %d) = %s\n", i, *(names i) );
   }
   for ( i = 0; i < MAX; i  ) {
      printf("Value of names[%d] = %s\n", i, names[i] );
   }
   
 
   
   printf("Value of names = %d\n",names );
   printf("Value of names 1 = %d\n",names 1 );
   return 0;
}

when value of names and names[0] is not same. where can i learn this topic properly. the problem is "i don't know that .. which variable is storing which adress or value".

CodePudding user response:

First of all, the following line is wrong:

printf("Value of names = %d\n",names );

Using the %d format specifier is not the correct way to print a pointer. Although it may work on most 32-bit platforms (on which pointers normally have a size of 4), it will most certainly not work properly on 64-bit platforms (on which pointers normally have a size of 8).

The correct way to print a pointer is using the %p format specifier and by casting the pointer to void*:

printf( "Value of names = %p\n", (void*)names );

On most platforms, the cast to void* is not necessary, so you can probably safely omit it (even if ISO C formally requires the cast).

As already pointed out in the comments section, writing names[i] is, by definition, equivalent to writing *(names i).

The reason why the difference between names and names 1 is 8 is because in both expressions, the array names decays to a pointer to its first element, i.e. to &names[0]. Incrementing a pointer by 1 does not increase the address by 1, but rather makes it point to the next element. Since each element of the array names is a pointer and seems to have a size of 8 on your platform (you seem to be on a 64-bit platform with 64-bit pointers), the address is incremented by 8 when you increment the pointer by 1.

In your picture, you seem to also be asking why the difference between *(names 0) and *(names 1) is 9. The expression *(names 0) is equivalent to names[0], which is a pointer to the string literal "Zara Ali". The expression *(names 1) is equivalent to names[1], which is a pointer to the string literal "Hina Ali". So both of these expressions represent addresses of string literals, i.e. addresses of where the compiler is storing a certain string literal. Where compilers store string literals is up to the compiler to decide and compilers may behave differently. However, in this case, it seems that the compiler decided to store both string literals next to each other in memory. The string literal "Zara Ali" has a length of 9 (including the null terminating character), so that explains why the difference in the addresses is 9.

CodePudding user response:

Pictures will help:

      char *                char
 –––                  ––– 
|   | names[0] ––––> |'Z'| names[0][0]
 –––                  ––– 
|   | names[1] ––    |'a'| names[0][1]
 –––             |    ––– 
 ...             |    ...
                 |    ––– 
                 |   |'i'| names[0][7]
                 |    ––– 
                 |   | 0 | names[0][8]
                 |    ––– 
                 |
                 |    ––– 
                  -> |'H'| names[1][0]
                      ––– 
                     |'i'| names[1][1]
                      ––– 
                      ...
                      ––– 
                     |'i'| names[1][7]
                      ––– 
                     | 0 | names[1][8]
                      ——— 

Each string literal ("Zara Ali", "Hina Ali", etc.) is stored as a zero-terminated array of char somewhere in memory (string literals are stored in such a way that they are available over the lifetime of the program).

Each names[i] stores the address of the first character of each string literal.

The expression names has type "pointer to pointer to char" (char **)1 and evaluates to the address of the first element of the names array - it’s equivalent to writing &names[0]. The expression names[0] evaluates to the address of the first character in the "Zara Ali" string literal - it’s the same as writing &names[0][0].

Use the %p conversion specifier to print pointer values instead of %d - %d expects its corresponding argument to have type int, and pointers are not integers:

printf( "Value of names[%d] = %p\n", i, (void *) names[i] );

printf( "Value of names = %p\n", (void *) names );
printf( "Value of names 1 = %p\n", (void *) (names   1) );

This is pretty much the only time you need to explicitly cast a pointer to void * in C.


  1. Unless it is the operand of the sizeof or unary & operators, or unless it is a string literal used to initialize an array of character type in a declaration, an expression of type "N-element array of T" will be converted, or "decay”, to an expression of type "pointer to T" and the value of the expression will be the address of the first element of the array.

    The variable names is declared as an array of pointer to char (char *[]). However, when names appears in an expression and it is not the operand of sizeof or unary &, it is converted to type "pointer to pointer to char (char **).

    This is why names is an array of char * - each of the string literals is itself an array expression ("9-element array of char"), but in this context "decays" to type char *.
  • Related