Home > Back-end >  Question about char * [length] assignment
Question about char * [length] assignment

Time:11-30

How does this code work?

#include <stdio.h>
#include <string.h>

int main()
{
#define NAME_LEN 10

        char name[NAME_LEN 1];                          // line 8
        strcpy(name,"Hi");                              // line 9
        char (* name_ptr)[NAME_LEN  1] = & name;        // line 10

        printf("%s=%s\n%s=%s\n",                        // line 12
                "name",name,                            // line 13
                "name_ptr",name_ptr                     // line 14
        );
}

Everything is routine until line 10. To me, Line 10 mixes together declaring a char * and char [length], so I would expect to have an array of 10 char * (clearly, the compiler disagrees, because this works). When I compile this with -Wall, I get the following:

$ cc -g -Wall a.C
a.C: In function ‘int main()’:
a.C:16:2: warning: format ‘%s’ expects argument of type ‘char*’, but argument 5 has type ‘char (*)[11]’ [-Wformat=]
  );

What am I missing?

CodePudding user response:

char (* name_ptr)[NAME_LEN  1]

name_ptr is a pointer to char array of NAME_LEN 1 elements. So the type of this pointer is not the same as char * even if they reference the same object.

The easiest to spot and understand difference is the pointer arithmetic.

Example:

int main()
{
#define NAME_LEN 10

    char name[NAME_LEN 1];                          // line 8
    strcpy(name,"Hi");                              // line 9
    char (* name_ptr)[NAME_LEN  1] = & name;        // line 10

    printf("name = %p (name   1) = %p, difference in chars = %td\n", 
            (void *)name, (void *)(name   1), (char *)(name   1) - (char *)name);                        // line 12
    printf("name_ptr = %p (name_ptr   1) = %p, difference in chars = %td\n", 
            (void *)name_ptr, (void *)(name_ptr   1), (char *)(name_ptr   1) - (char *)name_ptr);                        // line 12
}

And the result:

name = 0x7fff645264b5 (name   1) = 0x7fff645264b6, difference in chars = 1
name_ptr = 0x7fff645264b5 (name_ptr   1) = 0x7fff645264c0, difference in chars = 11

As you see the pointer to array adds the whole size of the array to the initial address.

So if you want to use this pointer in the printf you need to dereference it:

        printf("name_ptr = %s\n",name_ptr[0]);                  
        printf("name_ptr = %s\n",*name_ptr);                  

CodePudding user response:

In c, the type of a pointer doesn't really change what it points to.

As mentioned by 0___________, the only difference between the char* (pointer to chars) expected by printf's %s flag and the char (*)[11] (pointer to 11-long char arrays) is the pointer arithmetic.

Now what you do in line 10 is make your char (*)[11] point to a place in memory where there happens to be a ['h', 'i', '\0']. Then in your printf call, you tell it to read a string from that location. And there is indeed a string there, null terminated and everything.

So it complains to you about the pointer type but it still does what it's told because it has all it needs at the place the pointer points to.

  • Related