C语言深度解剖读书笔记2

struct

平时我们要求函数的参数尽量不多于四个,如果函数的参数多于四个使用起开非常容易出错(包括每个参数的意义和顺序都容易弄错),效率也会降低(与具体CPU有关)。这个时候,就可以用结构体压缩参数个数。
空结构体多大
结构体所占的内存大小是其成员内存之和,如果成员内存为0,例如:

struct student
{
}stu;

sizeof(stu)的值是多少?
在Visual C++上测试结果是1 。GCC里计算出来为0。

柔性数组

C99(C语言的官方标准第二版)中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员,但结构中的柔性数组成员前面必须至少有一一个其他成员。柔性数组成员允许结构中包含一个大小可变的数组。sizeof返回的这种结构大小不包括柔性数组的内存。包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
柔性数组的使用:

typedef struct st_type
{
    int i;
    int a[0];
}type_a;

有些编译器会报错无法编译可以改成:

typedef struct st_type
{
    int i;
    int a[];
}type_a;

这样我们就可以定义一个可变长的结构体,用sizeof(type_ a) 得到的只有4,就是sizeof(i) = sizeof(int)。0个元素的数组没有占用空间,而后我们可以进行变长操作了。通过如下表达式给结构体分配内存:

type_a *p = (type_a *)malloc(sizeof(type_a)+100*sizeof(int));

这样我们为结构体指针p分配了一块内存。用p->item[n]就能简单地访问可变长元素。但是这时候我们再用sizeof(¥p)测试结构体的大小,发现仍然为4。

在定义这个结构体的时候,模子的大小就已经确定不包含柔性数组的内存大小。柔性数组只是编外人员,不占结构体的编制,只是说在使用柔性数组时需要把它当作结构体的一个成员,仅此而已。再说得直白点,柔性数组其实与结构体没什么关系,只是“挂羊头卖狗肉”而已,算不得结构体的正式成员。

  需要说明的是:C89不支持这种东西,C99把它作为一-种特例加人了标准。但是,C99支持的而不是zeroarray,形同intitem[0],这种形式是非法的;C99支持的是incomplete type ,形同int item[],只不过有些编译器把int item[0]作为非标准扩展来支持,而且在C99发布之前已经有了这种非标准扩展了。C99发布之后,有些编泽器把两者合而为一。

  当然,上面既然用malloc函数分配了内存,肯定就需要用free函数来释放内存:
free(p);
struct与class的区别

struct的成员默认情况下的属性是public,而class成员的却是private。

union

union关键字的用法与struct的用法非常类似。
union维护足够的空间来放置多个数据成员中的“一种”,而不是为每一个数据成员配置空间。在union中所以的数据成员公用一个空间,同一时间只能储存其中一个数据成员,所以的数据成员具有相同的起始地址。例如:

union StateMachine
{
    char character;
    int number;
    char *str;
    double exp;
};

一个union只配置一个足够大的空间来容纳最大长度的数据成员,以本例而言,最大长度是double类型,所以StateMachine的空间大小就是double数据类型的大小。

大小端模式对union类型数据的影响

大端模式(Big_endian):字数据的高字节存储在低地址中,而字数据的低字节
则存放在高地址中。
小端模式(Little_endian):字数据的高字节存储在高地址中,而字数据的低字
节则存放在低地址中。
union型数据所占的空间等于其最大的成员所占的空间。对union型成员的存取都
从相对于该联合体基地址的偏移量为0处开始,也就是联合体的访问不论对哪个变量的
存取都是从union的首地址位置开始。

如何用程序确认当前系统的存储模式

写一个C函数,若处理器是大端,返回0;处理器是小端,返回1。

int checkSystem()
{
    union check
    {
        int i;
        char ch;
    }c;
    c.88i = 1;
    
    return(c.ch == 1);
}

enum

枚举类型的使用方法

enum enum_type_name
{
    ENUM_CONST_1,
    ENUM_CONST_2,
    ...
    ENUM_CONST_n,   
}enum_variable_name;
枚举与#define宏的区别

#define宏常量是在预编译阶段进行简单替换;枚举常量则是在编译的时候确实其值。
一般在调试器里,可以调试枚举常量,但是不能调试宏常量。
枚举可以一次定义大量相关的常量,而#define宏一次只能定义一个。

typedef
typedef struct student
{
    //code
}Stu_st,*Stu_pst;

struct student stu1 和 Stu_st stu1——没有区别
struct student *stu、Stu_pst 和 Stu_st *stu2——没有区别

你可能感兴趣的:(C语言)