简体   繁体   中英

Difference between char * and char (*)[25]

#include<stdio.h>

int main()
{
    char str[25] = "Hello World";
    printf("%s\n", &str+2);
    printf("%p\n",&str);
    printf("%p\n",&str+2);
    return 0;
}

The program above flashes an error for line 6 saying:

warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[25]’ [-Wformat=]

I wonder what's the difference between these two. And the output always shows two addresses having a difference of 32 bytes. I was expecting an output with a difference of 2 as I'm trying to print the address of str and address of str +2. Can you explain?

The difference for this two cases is quite simple. Assume that we have an array of 25 characters: char arr[25]; . By convention expression arr evaluated to a pointer to first array element, ie arr is the same as &arr[0] . Note, that here unary operator & is applied to lvalue arr[0] which has type of char . And as result & gives an expression with type char * (ie pointer to char )

When we say &arr - the lvalue is arr , that is char [25] (ie array of 25 characters). And as result the whole expression has type char (*)[25] (ie pointer to array of 25 characters). So, we've got expression with completely another type, that is not compatible with char * .

Few notes about indexing. Difference between &arr + 2 and &arr is 50 bytes (0x32 in hexadecimal), because sizeof(arr) == 25 .

char * is a pointer to char while char (*)[25] is a pointer to an array of 25 char 's so these types are different and the compiler rightfully issues a warning.

Moreover, since &str is the address of the str array and is of type char (*)[25] , the value of &str+2 will be equal to:

&str + 2*sizeof(char (*)[25]) = &str + 2*25 = &str + 50 = &str + 0x32

Since a pointer is incremented according to the type it points to.

EDIT: after OP added a new line 6.

This is the correct syntax to print a string and pointer values. In all cases there was a & where it should not be, because a reference to the array identifier decays it to a pointer.

#include <stdio.h>

int main()
{
    char str[25] = "Hello World";
    printf("%s\n", str+2);
    printf("%p\n", (void*)str);
    printf("%p\n", (void*)(str+2));
    return 0;
}

Program output:

llo World
0018FF20
0018FF22

EDIT 2: This shows the effect of passing the pointer of the array. The compiler thinks you are addressing the third element of an array of strings each size 25. I have contrived to show how this undefined behaviour actually manifested.

#include <stdio.h>

int main()
{
    char str[25] = "Hello World";
    char abc[] = "abcdefghijklmnopqrstuvwxyz";
    printf("%s\n", &str+2);
    return 0;
}

Program output:

wxyz

After a little research I came up with this explanation. &str+2 is treated as a pointer to an array. char (*)[25] says that it's a pointer to a character array of size 25. To find the explain to why the output shows 32 byte difference I ran the program again and notices the output was displayed in hex ie

0x7ffd865b2710
0x7ffd865b2742

When converted to base 10, it becomes a difference of 50 bytes which is a pointer to the array that lies at second place to the current array(remember &str+2). TO make it more clear here's a little memory diagram.

&str   -----> current array ie str. array is 25 bytes long.
&str+1 -----> array lies after 1 position to current array. This address is 25 bytes away from &str.
&str+2-----> array lies after 2 position to current array. This address is 50 bytes away from &str.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM