关于 char * [length] 赋值的问题
Question about char * [length] assignment
此代码如何工作?
#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
);
}
第 10 行之前一切都是例行公事。对我来说,第 10 行混合在一起声明 char *
和 char [length]
,所以我希望有一个 10 char *
的数组(显然,编译器不同意,因为这有效)。当我用 -Wall
编译它时,我得到以下信息:
$ 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=]
);
我错过了什么?
char (* name_ptr)[NAME_LEN +1]
name_ptr
是指向包含 NAME_LEN +1
个元素的 char
数组的指针。所以 this 指针的类型与 char *
不同,即使它们引用相同的对象。
最容易发现和理解的区别是指针运算。
示例:
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
}
结果:
name = 0x7fff645264b5 (name + 1) = 0x7fff645264b6, difference in chars = 1
name_ptr = 0x7fff645264b5 (name_ptr + 1) = 0x7fff645264c0, difference in chars = 11
如您所见,指向数组的指针将数组的整个大小添加到初始地址。
所以如果你想在 printf
中使用这个指针,你需要取消引用它:
printf("name_ptr = %s\n",name_ptr[0]);
printf("name_ptr = %s\n",*name_ptr);
在 c 中,指针的类型并没有真正改变它指向的内容。
如 0___________ 所述,printf
的 %s
标志预期的 char*
(指向字符的指针)与 [=13= 之间的唯一区别](指向11长字符数组的指针)是指针算法。
现在你在第 10 行所做的是让你的 char (*)[11]
指向内存中恰好有 ['h', 'i', '[=15=]']
的位置。然后在您的 printf 调用中,您告诉它从该位置读取一个字符串。那里确实有一个字符串,以 null 结尾等等。
所以它向你抱怨指针类型,但它仍然按照它所说的去做,因为它在指针指向的地方有它需要的一切。
此代码如何工作?
#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
);
}
第 10 行之前一切都是例行公事。对我来说,第 10 行混合在一起声明 char *
和 char [length]
,所以我希望有一个 10 char *
的数组(显然,编译器不同意,因为这有效)。当我用 -Wall
编译它时,我得到以下信息:
$ 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=]
);
我错过了什么?
char (* name_ptr)[NAME_LEN +1]
name_ptr
是指向包含 NAME_LEN +1
个元素的 char
数组的指针。所以 this 指针的类型与 char *
不同,即使它们引用相同的对象。
最容易发现和理解的区别是指针运算。
示例:
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
}
结果:
name = 0x7fff645264b5 (name + 1) = 0x7fff645264b6, difference in chars = 1
name_ptr = 0x7fff645264b5 (name_ptr + 1) = 0x7fff645264c0, difference in chars = 11
如您所见,指向数组的指针将数组的整个大小添加到初始地址。
所以如果你想在 printf
中使用这个指针,你需要取消引用它:
printf("name_ptr = %s\n",name_ptr[0]);
printf("name_ptr = %s\n",*name_ptr);
在 c 中,指针的类型并没有真正改变它指向的内容。
如 0___________ 所述,printf
的 %s
标志预期的 char*
(指向字符的指针)与 [=13= 之间的唯一区别](指向11长字符数组的指针)是指针算法。
现在你在第 10 行所做的是让你的 char (*)[11]
指向内存中恰好有 ['h', 'i', '[=15=]']
的位置。然后在您的 printf 调用中,您告诉它从该位置读取一个字符串。那里确实有一个字符串,以 null 结尾等等。
所以它向你抱怨指针类型,但它仍然按照它所说的去做,因为它在指针指向的地方有它需要的一切。