C char数组作为指针

gra*_*hel 5 c arrays pointers

我想明白:

  • 为什么会发生这种情况,有时char[1]在C中使用char*(为什么这样做?)和
  • 内部如何工作(发生了什么)

提供以下示例程序:

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

struct test_struct {
    char *a;
    char b[1];
} __attribute__((packed)); ;

int main() {

    char *testp;
    struct test_struct test_s;

    testp = NULL;
    memset(&test_s, 0, sizeof(struct test_struct));

    printf("sizeof(test_struct) is: %lx\n", sizeof(struct test_struct));

    printf("testp at: %p\n", &testp);
    printf("testp is: %p\n", testp);

    printf("test_s.a at: %p\n", &test_s.a);
    printf("test_s.a is: %p\n", test_s.a);

    printf("test_s.b at: %p\n", &test_s.b);
    printf("test_s.b is: %p\n", test_s.b);

    printf("sizeof(test_s.b): %lx \n", sizeof(test_s.b));

    printf("real sizeof(test_s.b): %lx \n", ((void *)(&test_s.b) - (void *)(&test_s.a)) );

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我得到以下输出(OS X,64位):

sizeof(test_struct) is: 9
testp at: 0x7fff62211a98
testp is: 0x0
test_s.a at: 0x7fff62211a88
test_s.a is: 0x0
test_s.b at: 0x7fff62211a90
test_s.b is: 0x7fff62211a90
sizeof(test_s.b): 1 
real sizeof(test_s.b): 8 
Run Code Online (Sandbox Code Playgroud)

查看内存地址,可以看到即使结构大9字节,也分配了16个字节,这似乎是由char b[1].但是我不确定是否由于优化/内存对齐原因分配了那些额外的字节,或者这是否与C对char数组的内部处理有关.

一个现实世界的例子可以在<fts.h>:

`man 3 fts`将结构成员`fts_name`显示为:

            char *fts_name;                 /* file name */
Run Code Online (Sandbox Code Playgroud)

而/usr/include/fts.h将成员定义为:

            char fts_name[1];               /* file name */
Run Code Online (Sandbox Code Playgroud)

最后,fts_name可以真正用作指向C字符串的指针.例如,使用printf("%s", ent->fts_name)作品打印到stdout .

因此,如果a char[1]实际上是一个大字节,则它不能用作我的64位机器上的内存指针.另一方面,将其视为完全char *无效也不起作用,如test_s.b is上面的输出所示,它应该显示一个NULL指针然后......

Jak*_*ski 2

这是描述该技巧的答案char[1]malloc()基本上,这个想法是在结构体时分配更多内存,以便已经为字符串提供了一些存储空间,而无需额外分配。有时您甚至可以看到char something[0]用于相同目的,这更不直观。

另一方面,将其视为完整的 char * 也不起作用,正如上面输出的 test_s.b 所示,它应该显示一个 NULL 指针...

如果某物是一个数组,则它的名称和&name仅给出指向 C 中数组开头的指针。无论它是结构中的成员还是独立变量,这都有效。

printf("real sizeof(test_s.b): %lx \n", ((void *)(&test_s.b) - (void *)(&test_s.a)) );
Run Code Online (Sandbox Code Playgroud)

这一行给出了为 分配的空间大小a,而不是b在此结构中。在后面放一些东西b并用它来减去。使用该packed属性(这意味着您不允许编译器弄乱对齐等),您应该得到 1。

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

struct test_struct {
    char *a;
    char b[1];
    char c;
} __attribute__((packed));

int main() {
  struct test_struct s;
  printf("%lx\n", ((void*)&s.c) - ((void*)&s.b));
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我明白了1