注:本课程参考文献《C安全编码标准》
欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~
一.引言
灵活数组成员指的是一种特别的数组,它存在于包含多个具名成员的结构体中,并且其最后一个成员被定义为未指定大小的数组类型。这意味着,在该结构体定义中,数组的具体大小并未被明确设定。这种设计允许结构体具有“可变大小”,在实际应用中非常普遍,且被多种编译器所兼容。因此,为了实现灵活数组成员的声明,人们采用了多样化的语法形式。为了确保与C语言的实现相兼容,应当遵循C语言标准所认可的有效语法。
灵活数组定义如下:
- 作为特例,具有不止一个命名成员的结构中,最后一个成员可以具有不完整的数组类型;这被称作灵活数组成员。在大部分情况下,灵活数组成员被忽略。特别是,除了后续的填充字节较多之外,结构的大小和灵活数组成员被忽略的时候一样。但是,如果.(或者->)运算符的左操作数是指向具有灵活数组成员的结构的指针,右操作数是该成员,则该成员的表现就像被替换为不会使结构大于被访问对象的最长数组(具有相同元素类型);数组偏移仍然保持灵活数组成员的偏移,即使这会与替代数组的不同。如果该数组没有元素,它的表现就像拥有一个元素,但是如果试图访问该元素或者生成一个指向它的指针,则产生未定义行为。*
注意:具有灵活数组成员的结构可以用于生成具有已定义行为的代码,但是有如下限制。
1.不完整数组类型必须是结构中的最后一个元素。
2.不可以有包含灵活数组成员的结构数组。
3.包含灵活数组成员的结构不能作为另一个结构的成员,除非作为结构的最后一个元素。
4.除了灵活数组成员之外,结构必须包含至少一个命名成员。
二.不安全代码
在C语言标准中引入灵活数组成员之前,使用最后成员为单元素数组的结构来实现类似的功能。下面的不相容代码示例中,struct flexArrayStruct就是这样声明的。
在这个不安全代码示例试图以一个单元素数组作为最后的成员,分配类似灵活数组的成员。当结构实例化时,为malloc()计算的大小经过修改,要考虑动态数组的实际大小。
#include <stdlib.h>
struct flexArrayStruct {
int num;
int data[1];
};
void func(size_t array_size){
/* Space is allocated for the struct */
struct flexArrayStruct *structP = (struct flexArrayStruct *)malloc(sizeof(struct flexArrayStruct)+sizeof(int)*(array_size -1 ));
if(structP==NULL){
/* Handle malloc failure */
}
structP->num=array_size;
/*
* Access data[] as if it had been allocated
* as data[array_size].
*/
for (size_t i=0;i<array_size;++i){
structP->data[i]=1;
}
}
在此案例中,访问data数组第一个元素之外的任何元素都会发生未定义行为。因此编译器可能产生在访问data的第二个元素时不能返回预期值的代码。
三.解决方案
使用灵活数组实现动态尺寸结构:
#include <stdlib.h>
struct flexArrayStruct {
int num;
int data[];
};
void func(size_t array_size){
/* Space is allocated for the struct */
struct flexArrayStruct *structP = (struct flexArrayStruct *)malloc(sizeof(struct flexArrayStruct)+sizeof(int)*(array_size ));
if(structP==NULL){
/* Handle malloc failure */
}
structP->num=array_size;
/*
* Access data[] as if it had been allocated
* as data[array_size].
*/
for (size_t i=0;i<array_size;++i){
structP->data[i]=1;
}
}
四.练习与答案
不安全代码
#include <stdlib.h>
#include <stdio.h>
struct flexArrayStruct {
int num;
int data[1];
};
void func(size_t array_size) {
struct flexArrayStruct *structP = (struct flexArrayStruct *)malloc(sizeof(struct flexArrayStruct) + sizeof(int) * (array_size - 1));
if (structP == NULL) {
fprintf(stderr, "Malloc failed\n");
return;
}
structP->num = array_size;
for (size_t i = 0; i < array_size; ++i) {
structP->data[i] = i + 1;
}
for (size_t i = 0; i < array_size; ++i) {
printf("data[%zu] = %d\n", i, structP->data[i]);
}
free(structP);
}
int main() {
func(5);
return 0;
}
编译这段代码可能不会报错,但在运行时访问
data
数组的第二个及之后的元素时,可能会产生不可预期的结果,甚至导致程序崩溃。
答案
#include <stdlib.h>
#include <stdio.h>
struct flexArrayStruct {
int num;
int data[];
};
void func(size_t array_size) {
struct flexArrayStruct *structP = (struct flexArrayStruct *)malloc(sizeof(struct flexArrayStruct) + sizeof(int) * array_size);
if (structP == NULL) {
fprintf(stderr, "Malloc failed\n");
return;
}
structP->num = array_size;
for (size_t i = 0; i < array_size; ++i) {
structP->data[i] = i + 1;
}
for (size_t i = 0; i < array_size; ++i) {
printf("data[%zu] = %d\n", i, structP->data[i]);
}
free(structP);
}
int main() {
func(5);
return 0;
}
非常感谢您花时间阅读我的博客,希望这些分享能为您带来启发和帮助。期待您的反馈与交流,让我们共同成长,再次感谢!
👇热门内容👇
python使用案例与应用_安城安的博客-CSDN博客
软硬件教学_安城安的博客-CSDN博客
Orbslam3&Vinsfusion_安城安的博客-CSDN博客
网络安全_安城安的博客-CSDN博客
教程_安城安的博客-CSDN博客
python办公自动化_安城安的博客-CSDN博客
👇个人网站👇
安城安的云世界
版权归原作者 安小呆 所有, 如有侵权,请联系我们删除。