C++结构体中变长数组的使用问题分解刨析

目录
  • 1. 问题来源
  • 2. 问题复现
    • 2.1 初始程序
    • 2.2 独立变长数组复现
    • 2.3 变长数组置前复现
    • 2.4 缓冲区溢出复现
  • 3. 结构体变长数组使用要点

1. 问题来源

今天在结构体里面使用变长数组来封装消息体,运行程序时弹出如下错误:

*** stack smashing detected ***: <unknown> terminated
Aborted (core dumped)

问题已经解决,由于源程序不方便截取,现在通过一个实例来复现问题。

2. 问题复现

2.1 初始程序

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
    int a;
    char body[];
} msg_t;
int main(void)
{
    msg_t msg;
    char *pdu = "abcdefg";
    strcpy(msg.body,pdu);
    printf("msg body:%s\n",msg.body);
    return 0;
}

上述程序编译是没有问题的,但如果带变长数组的结构体换两种写法,会复现两种错误。

2.2 独立变长数组复现

typedef struct {
    char body[];
} msg_t;

结构体中只有变长数组body[],无其他成员。编译错误如下:

test.c:7:10: error: flexible array member in a struct with no named members
     char body[];

这种情况在实际中并不会出现,如果只有一个成员,就没必要多一层结构体。

2.3 变长数组置前复现

typedef struct {
	char body[];
	int a;
} msg_t;

变长数组body[]不为结构最后一个成员。编译错误如下:

test.c:7:10: error: flexible array member not at end of struct
     char body[];

这种情况就是按照C99标准变长数组必须是结构体的最后一个成员。

2.4 缓冲区溢出复现

运行编译出的可执行程序,打印错误如下:

msg body:abcdefg
*** stack smashing detected ***: <unknown> terminated
Aborted (core dumped)

这里是因为没有为变长数组body分配内存,检测到了缓冲区溢出,通过如下表达式分配内存:

msg_t *msg= (msg_t*)malloc(sizeof(msg_t)+16*sizeof(char));

这样就为结构体指针msg分配了一块内存空间,程序变为:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
    int a;
    char body[];
} msg_t;
int main(void)
{
    msg_t *msg = (msg_t*)malloc(sizeof(msg_t)+16*sizeof(char));
    char *pdu = "abcdefg";
    strcpy(msg->body,pdu);
    printf("msg body:%s\n",msg->body);
    free(msg);
    return 0;
}

编译成功,运行结果正常:

msg body:abcdefg

3. 结构体变长数组使用要点

  • 结构体中不能只有变长数组一个成员,同时变长数组必须为结构体最后一个成员。
  • 变长数组不占用结构体的存储空间,长度为0,数组名只是一个占位符。sizeof()计算结构体大小时,变长数组在其中长度为0。
  • 使用变长数组结构体时,用malloc()分配内存空间。使用完毕用free()可以直接释放整个结构体的空间。

到此这篇关于C++结构体中变长数组的使用问题分解刨析的文章就介绍到这了,更多相关C++变长数组内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ 手把手教你实现可变长的数组实现

    01 实现自定义的可变长数组类型 假设我们要实现一个会自动扩展的数组,要实现什么函数呢?先从下面的main函数给出的实现,看看有什么函数是需要我们实现的. int main() { MyArray a; // 初始化的数组是空的 for(int i = 0; i < 5; ++i) a.push_back(i); // push_back是成员函数 MyArray a2,a3; a2 = a; // 重载赋值运算符函数 // 由于上一句a2 = a语句,所以a.length()实际上就是a2.l

  • 浅谈C++内存分配及变长数组的动态分配

    第一部分 C++内存分配 一.关于内存 1.内存分配方式 内存分配方式有三种: (1)从静态存储区域分配.内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在 例如全局变量,static变量. (2)在栈上创建.在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存 储单元自动被释放.栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限. (3) 从堆上分配,亦称动态内存分配.程序在运行的时候用malloc或new申请任意多少的内存,程序员

  • C++结构体中变长数组的使用问题分解刨析

    目录 1. 问题来源 2. 问题复现 2.1 初始程序 2.2 独立变长数组复现 2.3 变长数组置前复现 2.4 缓冲区溢出复现 3. 结构体变长数组使用要点 1. 问题来源 今天在结构体里面使用变长数组来封装消息体,运行程序时弹出如下错误: *** stack smashing detected ***: <unknown> terminatedAborted (core dumped) 问题已经解决,由于源程序不方便截取,现在通过一个实例来复现问题. 2. 问题复现 2.1 初始程序 #

  • 详解C语言结构体中的char数组如何赋值

    目录 前景提示 一.char数组类型的处理 1.结构体初始化 2.结构体内数据赋值(简单法) 二.char数组指针类型的处理 1.结构体初始化 2.结构体内数据赋值 3.结构体内输出数据 三.全部代码 1.char数组 2.char数组指针 总结 前景提示 定义一个结构体,结构体中有两个变量,其中一个是char类型的数组,那么,怎么向这个数组中插入数据,打印数据呢? typedef struct SequenceList { // 数组的元素 char element[20]; // 数组的长度

  • oracle中变长数组varray,嵌套表,集合使用方法

    创建变长数组类型 CREATE TYPE varray_type AS VARRAY(2) OF VARCHAR2(50); 这个变长数组最多可以容纳两个数据,数据的类型为 varchar2(50) 更改元素类型的大小或精度 可以更改变长数组类型和嵌套表类型 元素的大小. ALTER TYPE varray_type MODIFY ELEMENT TYPE varchar2(100) CASCADE; CASCADE选项吧更改传播到数据库中的以来对象.也可以用 INVALIDATE 选项使依赖对

  • C语言变长数组 struct中char data[0]的用法详解

    今天在看一段代码时出现了用结构体实现变长数组的写法,一开始因为忘记了这种技术,所以老觉得作者的源码有误,最后经过我深思之后,终于想起以前看过的用struct实现变长数组的技术.下面是我在网上找到的一篇讲解很清楚的文章. 在实际的编程中,我们经常需要使用变长数组,但是C语言并不支持变长的数组.此时,我们可以使用结构体的方法实现C语言变长数组. struct MyData { int nLen; char data[0];}; 在结构中,data是一个数组名:但该数组没有元素:该数组的真实地址紧随结

  • C语言变长数组使用详解

    看如下代码: #include<stdio.h> typedef struct { int len; int array[]; }SoftArray; int main() { int len = 10; printf("The struct's size is %d\n",sizeof(SoftArray)); return 0; } 运行结果: [root@VM-0-7-centos mydoc]# ./a.out The struct's size is 4 我们可以

  • C#使用List类实现动态变长数组的方法

    本文实例讲述了C#使用List类实现动态变长数组的方法.分享给大家供大家参考.具体如下: C#中的list可以当做数组使用,而且无需定义长度,完全是动态的 class Person { public string Name { get; set; } public string Address { get; set; } } static void Main(string[] args) { List<Person> people = new List<Person>(); peo

  • 详解C语言的结构体中成员变量偏移问题

    c语言中关于结构体的位置偏移原则简单,但经常忘记,做点笔记以是个记忆的好办法 原则有三个: a.结构体中的所有成员其首地址偏移量必须为器数据类型长度的整数被,其中第一个成员的首地址偏移量为0, 例如,若第二个成员类型为int,则其首地址偏移量必须为4的倍数,否则就要"首部填充":以此类推 b.结构体所占的总字节数即sizeof()函数返回的值必须是最大成员的长度的整数倍,否则要进行"末尾填充": c.若结构体A将结构体B作为其成员,则结构体B存储的首地址的偏移量必须

  • 详解C语言结构体中的函数指针

    结构体是由一系列具有相同类型或不同类型的数据构成的数据集合.所以,标准C中的结构体是不允许包含成员函数的,当然C++中的结构体对此进行了扩展.那么,我们在C语言的结构体中,只能通过定义函数指针的方式,用函数指针指向相应函数,以此达到调用函数的目的. 函数指针 函数类型 (*指针变量名)(形参列表):第一个括号一定不能少. "函数类型"说明函数的返回类型,由于"()"的优先级高于"*",所以指针变量名外的括号必不可少.  注意指针函数与函数指针表示

  • 深入理解结构体中占位符的用法

    复制代码 代码如下: typedef union{    struct x{    char a1 : 2;    char b1 : 3;    char c1 : 3;    }x1;    char c;}my_un;int main(){    my_un a;    a.c = 100;    printf("%d/n",a.x1.c1);    printf("%d/n",sizeof(my_un)); return 0;} 输出结果:31即第一个是3,

随机推荐