龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > C/C++开发 >

C语言柔性数组实例详解

时间:2014-09-11 11:20来源:网络整理 作者:网络 点击:
分享到:
这篇文章主要介绍了C语言柔性数组,通过实例分析了不完整类型、结构体及柔性数组等概念,需要的朋友可以参考下

本文实例分析了C语言柔性数组的概念及用法,对于进一步学习C程序设计有一定的借鉴价值。分享给大家供大家参考。具体如下:

一般来说,结构中最后一个元素允许是未知大小的数组,这个数组就是柔性数组。结构中的柔性数组前面必须至少一个其他成员,柔性数组成员允许结构中包含一个大小可变的数组,sizeof返回的这种结构大小不包括柔性数组的内存。包含柔数组成员的结构用malloc函数进行内存的动态分配,且分配的内存应该大于结构的大小以适应柔性数组的预期大小。柔性数组到底如何使用?

不完整类型

C和C++对于不完整类型的定义是一样的,不完整类型是这样一种类型,它缺乏足够的信息例如长度去描述一个完整的对象。

不完整类型举例:
前向声明就是一种常用的不完整类型

struct test; //test 只给出了声明,没有给出定义

不完整数据类型必须通过某种方式补充完整,才能使它们进行实例化。否则只能用于定义指针或引用,因为此时实例化的是指针或引用本身,不是base和test对象

一个未知长度的数组也属于不完整类型:

extern int a[];

extern 关键字不能去掉,因为数组的长度未知,不能作为定义出现。不完整类型的数组需要补充完整才能使用。不完整类型的数组可以通过几种方式补充完整,大括号形式的初始化就是其中的一种方式:

int a[] = { 10,20 };

结构体

首先,我们需要知道——所谓变量,其实是内存地址的一个抽像名字罢了。在静态编译的程序中,所有的变量名都会在编译时被转成内存地址。机器是不知道我们取的名字的,只知道地址。

所以有了——栈内存区,堆内存区,静态内存区,常量内存区,我们代码中的所有变量都会被编译器预先放到这些内存区中。

有了上面这个基础,我们来看一下结构体中的成员的地址是什么?我们先简单化一下代码:

struct test{
  int i;
  char *p;
};

上面代码中,test结构中i和p指针,在C的编译器中保存的是相对地址——也就是说,他们的地址是相对于struct test的实例的。如果我们有这样的代码:

struct test t;

下面做个实验:

#include<stdio.h>
struct test{
  int i;
  char *p;
};
int main(void)
{
  struct test t;
  printf("%p\n", &t);
  printf("%p\n", &(t.i));
  printf("%p\n", &(t.p));
  return 0;
}

运行结果:

我们可以看到,t.i的地址和t的地址是一样的,t.p的址址相对于t的地址多了个8。说白了,t.i 其实就是(&t + 0×0), t.p 的其实就是 (&t + 0×8)。0×0和0×8这个偏移地址就是成员i和p在编译时就被编译器给hard code了的地址。于是,你就知道,不管结构体的实例是什么——访问其成员其实就是加成员的偏移量。

下面再来做个实验:

#include<stdio.h>
struct test{
  int i;
  short c;
  char *p;
};
int main(void)
{
  struct test *pt=NULL;
  printf("%p\n", &(pt->i));
  printf("%p\n", &(pt->c));
  printf("%p\n", &(pt->p));
  return 0;
}

运行结果:

注意:上面的pt->p的偏移之所以是0×8而不是0×6,是因为内存对齐了(我在64位系统上)。关于内存对齐,具体可以参看本站C语言内存对齐实例详解一文。

柔性数组

柔性数组成员(flexible array member)也叫伸缩性数组成员,这种代码结构产生于对动态结构体的需求。在日常的编程中,有时候需要在结构体中存放一个长度动态的字符串,一般的做法,是在结构体中定义一个指针成员,这个指针成员指向该字符串所在的动态内存空间,例如:

struct s_test
{
  int a;
  double b;
  char* p;
};

p指向字符串,这种方法造成字符串与结构体是分离的,不利于操作。把字符串和结构体连在一起的话,效果会更好,可以修改如下:

char a[] = "Hello world";
struct s_test *ptest = (struct s_test*)malloc(sizeof(s_test)+streln(a)+1);
strcpy(ptest+1,a);
精彩图集

赞助商链接