0长度的数组在ISO C和C++的规格说明书中是不允许的,但是GCC的C99支持的这种用法。
GCC对0长度数组的文档参考:“Arrays of Length Zero”
如下代码片段,哪个更简洁更灵活,看一眼就知道了:
#include <stdlib.h> #include <string.h> typedef struct tagArray { int length; char contents[]; //这个成员必须是结构体的最后一个成员。 }ARRAY_S; typedef struct tagPointer { int length; char *contents; }POINTER_S; int main() { int array_length = 10; ARRAY_S *pArray = (ARRAY_S*)malloc (sizeof(ARRAY_S) + array_length); POINTER_S *pPointer = NULL; if (NULL == pArray) { return 0; } pArray->length = array_length; memset(pArray->contents, ‘a‘, array_length); free(pArray); pPointer = (POINTER_S*)malloc(sizeof(POINTER_S)); if(pPointer == NULL) { return 0; } memset(pPointer, 0, sizeof(POINTER_S)); pPointer->length = array_length; pPointer->contents = (char*)malloc(array_length); if (pPointer->contents == NULL) { free(pPointer); return 0; } memset(pPointer->contents, ‘a‘, array_length); free(pPointer->contents); free(pPointer); return 0; }
第一种结构体的定义:想给一个结构体内的数据分配一个连续的内存,有两个好处: (1)方便内存释放。 如果我们的代码提供给别人使用,你在里面做了二次内存分配,并把整个结构体返回给用户。 用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。 所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。 (2)有利于访问速度。 连续的内存有益于提高访问速度,也有益于减少内存碎片。 第二种结构体的使用:需要分配两次内存以及释放两次内存,在检查申请内存成功与否的代码量上看也明显没有第一种更简洁。
看看内存是怎么个连续的,用gdb的x命令来查看:(ARRAY_S中的那个char contents[]不占用结构体的内存,
所以ARRAY_S就只有一个int成员,4个字节,而我们还要为contents[]分配10个字节长度,所以,一共是14个字节):
1 (gdb) p pArray 2 $1 = (ARRAY_S *) 0x804b008 3 (gdb) p *pArray 4 $2 = {length = 10, contents = 0x804b00c "aaaaaaaaaa"} 5 (gdb) p pArray ->contents 6 $3 = 0x804b00c "aaaaaaaaaa" 7 (gdb) x/14b pArray 8 0x804b008: 10 0 0 0 97 97 97 97 9 0x804b010: 97 97 97 97 97 97 从上面的内存布局我们可以看到,前4个字节是 int length,后10个字节就是char contents[]。 如果用指针的话,会变成这个样子: 10 (gdb) p pPointer 11 $4 = (POINTER_S *) 0x804b020 12 (gdb) p *pPointer 13 $5 = {length = 10, contents = 0x804b030 "aaaaaaaaaa"} 14 (gdb) p pPointer ->contents 15 $6 = 0x804b030 "aaaaaaaaaa" 16 (gdb) x/16b pPointer 17 0x804b020: 10 0 0 0 48 -80 4 8 18 0x804b028: 0 0 0 0 17 0 0 0 19 (gdb) x/10b pPointer ->contents 20 0x804b030: 97 97 97 97 97 97 97 97 21 0x804b038: 97 97 22 (gdb) x/16x pPointer 23 0x804b020: 0x0a 0x00 0x00 0x00 0x30 0xb0 0x04 0x08 24 0x804b028: 0x00 0x00 0x00 0x00 0x11 0x00 0x00 0x00
第17行前四个字节是 int length,后四个字节是contents的地址。
第23行以16进制显示,地址是: 0x30 0xb0 0x04 0x08, 即:0x0804b030。
第20行和第21行是char* contents指向的内容。
因此,可以看出其中的差别:数组的原地就是内容,而指针的那里保存的是内容的地址。
时间: 2024-10-23 08:29:05