结构体0长度数组的作用
2011-06-09 17:11
330 查看
在标准 C 和 C++ 中,不允许用 0 长度数组,但在 GNU C 中,却可以定义 0 长度数组。比如:
引用
struct
line
{
int
length
;
char
contents
[
0
];
}
0
长度数组不占有空间,从打印 sizeof (struct line) 可以看到这个结构体的长度为 4,这 4 字节空间属于整型量 length
。那么结构体里最后的 0 长度字符数组 contents[0] 用来做什么呢?答案是,它可以用来指向一段由你自己分配的 buffer
空间。如:
引用
int
this_length
=
60
;
struct
line
*
thisline
=
(struct
line
*
)malloc
(sizeof
(struct
line
) +
this_length
);
thisline->length = this_length;
这样,就开辟了 64 字节空间。前面 4 个字节为 this_length 用,后面 60 个字节被 contents 数组用。经过空间分配后,就相当于把结构体定义为:
引用
struct
line
{
int
length
;
char
contents
[
60
];
}
顺便看一下这个空间的分布,做如下打印:
引用
printf
("thisline 指向的地址为 %p
/n
"
,
thisline
);
printf
("thisline指向的第一个元素值为:%d
/n
"
,
thisline
->
length
);
printf
("该元素的地址为%p
/n
"
,
&
thisline
->
length
);
printf
("%p
/n
"
,
&
thisline
->
contents
);
printf
("%p
/n
"
,
&
thisline
->
contents
[
0
]);
printf
("%p
/n
"
,
&
thisline
->
contents
[
1
]);
输出为:
引用
thisline 指向的地址为 0x8780008
thisline指向的第一个元素值为:60
该元素的地址为0x8780008
0x878000c
0x878000c
0x878000d
从输出可以看到,thisline-contents 只是一个“不占有空间“(其特性由编译器决定)的常量指针。在这里,它表示接着整型值后的起始地址。
现在,我们可以使用这个数组了,比如给这个数组的前几个元素赋下值:
引用
char
c
=
'x'
;
int
i
;
thisline
->
contents
[
0
]
=
c
;
c
=
'y'
;
thisline
->
contents
[
1
]
=
c
;
c
=
'z'
;
thisline
->
contents
[
2
]
=
c
;
for
(i
=
0
; i
<
3
; i
++
)
printf
("%c
/n
"
,
thisline
->
contents
[
i
]);
还有一个问题需要探讨。既然用了 malloc() 函数,那么在最后就会使用 free() 函数来释放掉所申请的内存空间。那么,在这里,是不是只是用 free(thisline) 就能达到目的了呢?下面做一个实验:
首先在程序中,将分配缓冲区的首地址备份起来:
引用
struct
line
*
thisline_bak
=
thisline
;
现在做如下释放然后看一下空间中首元素(length)的值:
引用
free(thisline);
printf
("%d
/n
"
,
thisline_bak
->
length
);
一般在打印里可以看到 length 的输出值为 0 ,这也说明,首个元素的内存空间确实被释放了。在这里,严格的说,这个指针已经不能再这么用,因为它指向了一个被释放的内存空间。
但是,如果我们再次运行
引用
for
(i
=
0
; i
<
3
; i
++
)
printf
("%c
/n
"
,
thisline
->
contents
[
i
]);
这
个打印,发现仍然能够正常的打印出值来,从而说明了,后面申请的数组缓冲区还没释放。原因是,由于分配的空间返回的指针被强制转换为 struct
line 类型,且所得到的空间并不是平缓的(包含的不是同一种元素类型的空间)。在这里的空间组成是,一个整型值 +
后面一大块字符型缓冲区。所以,在释放时,free() 函数认为 *thisline 只是一个指向 4
字节整型值的空间。因而,我们要完全释放整个申请的空间,还需要:
引用
free (thisline->contents);
此后,如果再次打印之前那 3 个赋值的元素时,会发现段错误,或者是类似下面的错误:
引用
*** glibc detected *** ./array4: free(): invalid pointer: 0x09e4300c ***
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6(+0x6b591)[0x5b8591]
/lib/tls/i686/cmov/libc.so.6(+0x6cde8)[0x5b9de8]
/lib/tls/i686/cmov/libc.so.6(cfree+0x6d)[0x5bcecd]
./array4[0x80485ad]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0x563bd6]
./array4[0x80483c1]
======= Memory map: ========
... ...
所以,在不用这段空间时,可如下释放:
引用
free (thisline->contents); /*先释放掉后面的数组buffer*/
free(thisline); /*再释放掉 4 字节整型空间*/
引用
struct
line
{
int
length
;
char
contents
[
0
];
}
0
长度数组不占有空间,从打印 sizeof (struct line) 可以看到这个结构体的长度为 4,这 4 字节空间属于整型量 length
。那么结构体里最后的 0 长度字符数组 contents[0] 用来做什么呢?答案是,它可以用来指向一段由你自己分配的 buffer
空间。如:
引用
int
this_length
=
60
;
struct
line
*
thisline
=
(struct
line
*
)malloc
(sizeof
(struct
line
) +
this_length
);
thisline->length = this_length;
这样,就开辟了 64 字节空间。前面 4 个字节为 this_length 用,后面 60 个字节被 contents 数组用。经过空间分配后,就相当于把结构体定义为:
引用
struct
line
{
int
length
;
char
contents
[
60
];
}
顺便看一下这个空间的分布,做如下打印:
引用
printf
("thisline 指向的地址为 %p
/n
"
,
thisline
);
printf
("thisline指向的第一个元素值为:%d
/n
"
,
thisline
->
length
);
printf
("该元素的地址为%p
/n
"
,
&
thisline
->
length
);
printf
("%p
/n
"
,
&
thisline
->
contents
);
printf
("%p
/n
"
,
&
thisline
->
contents
[
0
]);
printf
("%p
/n
"
,
&
thisline
->
contents
[
1
]);
输出为:
引用
thisline 指向的地址为 0x8780008
thisline指向的第一个元素值为:60
该元素的地址为0x8780008
0x878000c
0x878000c
0x878000d
从输出可以看到,thisline-contents 只是一个“不占有空间“(其特性由编译器决定)的常量指针。在这里,它表示接着整型值后的起始地址。
现在,我们可以使用这个数组了,比如给这个数组的前几个元素赋下值:
引用
char
c
=
'x'
;
int
i
;
thisline
->
contents
[
0
]
=
c
;
c
=
'y'
;
thisline
->
contents
[
1
]
=
c
;
c
=
'z'
;
thisline
->
contents
[
2
]
=
c
;
for
(i
=
0
; i
<
3
; i
++
)
printf
("%c
/n
"
,
thisline
->
contents
[
i
]);
还有一个问题需要探讨。既然用了 malloc() 函数,那么在最后就会使用 free() 函数来释放掉所申请的内存空间。那么,在这里,是不是只是用 free(thisline) 就能达到目的了呢?下面做一个实验:
首先在程序中,将分配缓冲区的首地址备份起来:
引用
struct
line
*
thisline_bak
=
thisline
;
现在做如下释放然后看一下空间中首元素(length)的值:
引用
free(thisline);
printf
("%d
/n
"
,
thisline_bak
->
length
);
一般在打印里可以看到 length 的输出值为 0 ,这也说明,首个元素的内存空间确实被释放了。在这里,严格的说,这个指针已经不能再这么用,因为它指向了一个被释放的内存空间。
但是,如果我们再次运行
引用
for
(i
=
0
; i
<
3
; i
++
)
printf
("%c
/n
"
,
thisline
->
contents
[
i
]);
这
个打印,发现仍然能够正常的打印出值来,从而说明了,后面申请的数组缓冲区还没释放。原因是,由于分配的空间返回的指针被强制转换为 struct
line 类型,且所得到的空间并不是平缓的(包含的不是同一种元素类型的空间)。在这里的空间组成是,一个整型值 +
后面一大块字符型缓冲区。所以,在释放时,free() 函数认为 *thisline 只是一个指向 4
字节整型值的空间。因而,我们要完全释放整个申请的空间,还需要:
引用
free (thisline->contents);
此后,如果再次打印之前那 3 个赋值的元素时,会发现段错误,或者是类似下面的错误:
引用
*** glibc detected *** ./array4: free(): invalid pointer: 0x09e4300c ***
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6(+0x6b591)[0x5b8591]
/lib/tls/i686/cmov/libc.so.6(+0x6cde8)[0x5b9de8]
/lib/tls/i686/cmov/libc.so.6(cfree+0x6d)[0x5bcecd]
./array4[0x80485ad]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0x563bd6]
./array4[0x80483c1]
======= Memory map: ========
... ...
所以,在不用这段空间时,可如下释放:
引用
free (thisline->contents); /*先释放掉后面的数组buffer*/
free(thisline); /*再释放掉 4 字节整型空间*/
相关文章推荐
- 结构体最后的长度为0或1数组的作用(转载)
- 结构体最后的长度为0或1数组的作用
- 结构体最后的长度为0或1数组的作用--零长数组
- 结构体零长度数组的作用
- 结构体零长度数组的作用
- 结构体最后的长度为0或1数组的作用(转载)
- 结构体0长度数组的作用
- 结构体最后的长度为0或1数组的作用(转载)
- 结构体最后的长度为0或者1的数组
- PHP SPL标准库之数据结构固定长度数组(SplFixedArray)
- 结构体最后的长度为0或1数组的作用
- 建立一个学生结构数组来记录学生信息(学号ID,姓名和C语言成绩),要求动态建立一个结构数组,数组长度从键盘输入,自行给数组元素赋值并打印学生信息,最后不要忘记释放内存。 结构st
- 结构体最后的长度为0或1数组的作用
- 使用数组实现固定长度的队列结构
- 结构体最后的长度为0或1数组的作用(转载)
- 结构体成员最后一个定义0长度数组
- 定长度结构体数组、不定长度结构体指针初始化
- 在C#中如何定义一个变长的结构数组?如果定义好了,如何获得当前数组的长度?
- 定长度结构体数组、不定长度结构体指针初始化
- MySQL创建表结构里面的那个长度对于整型的作用