6.1 结构的基本知识

struct声明定义了一种数据类型

// 结构声明,point为标记
struct point {
    int x;
    int y;
    point (int x, int y) {
        x = x;
        y = y;
    }
}; 

// 变量声明
struct point pt;
struct point {int x; int y} pt;
struct {int x; int y} pt; // 不可复用

// 初始化
struct point maxpt = {320, 200};
struct point maxpt = point(320, 200);

struct point maxpt;
maxpt.x = 320;
maxpt.y = 200;

// 操作
// 作为一个整体复制和赋值,通过&运算符取地址,访问其成员
struct point *pp;
pp->x;
pp->y;
(*pp).x;
(*pp).y;
//运算符.和->都是从左至右结合的

6.2 结构与函数

结构的复制和赋值包括向函数传递参数以及从函数返回值。

6.3 结构数组

// 声明
struct key {
    char *word;
    int count;
} keytab[NKEYS];

struct key {
    char *word;
    int count;
}
strcut key keytab[NKEYS];

// 声明 + 初始化
struct key {
    char *word;
    int count;
} keytab[] = {
    {"auto", 0},
    {"break", 0},
    {"case", 0},
    {...},
};

struct key {
    char *word;
    int count;
} keytab[] = { // 如果初值是简单变量或字符串,并且其中的任何值都不为空,则内层的花括号可以省略
    "auto", 0,
    "break", 0,
    "case", 0,
    ...
};

sizeof一个编译时(compile-time)一元运算符,用来计算任一对象的长度(无符号整型size_t,在中定义

sizeof 对象 sizeof (类型名)

条件编译语句#if不能用sizeof:预处理器不对类型名进行分析,预处理器不计算#define语句中的表达式,#define可以

结构的长度不一定等于各成员长度的和,因为不同的对象有不同的对齐要求,struct {char c; int i;};可能需要8个字节的存储空间,而不是5个字节。

6.4 指向结构的指针

当函数的返回值类型比较复杂时,如

struct key binsearch(char word, struct key *tab, int n)

可以写成如下格式

struct key binsearch(char word, struct key *tab, int n)

6.5 自引用结构

struct tnode {
    char *word;
    int count;
    struct tnode *left;
    struct tnode *right;
}

struct t {
    ...
    struct s *p;
}
struct s {
    ...
    struct s *q;
}

6.6 表查找

install(s,t)将名字s和替换文本记录到某个表中 lookup(s)在表中查找s,找到返回指向该处的指针,没找到,返回NULL

哈希查找方法

/* hash */
unsigned hash(char *s)
{
    unsigned hashval;

    for (hashval=0; *s!='\0'; s++)
        hashval = *s + 31 * hashval;
    return hashval % HASHSIZE;
}

6.7 类型定义(typedef)

用来建立新的数据类型名,新定义的类型名一般首字母大写。

typedef int length;

typedef struct tnode *Treeptr;

typedef struct tnode {
    char *word;
    int count;
    Treeptr left;
    Treeptr right;
} Treenode;

typedef int (*PFI)(char *, char *); // 一个指向函数的指针,有两个char*类型的参数,返回值类型为int。
PFI strcmp, numcmp;

typedef类似于#define,typedef由编译器解释的,文本替换功能要超过预处理器的能力。

好处:

  1. 程序参数化,提高可移植性
  2. 更好的说明性

6.8 联合

联合的目的:一个变量可以合法地保存多种数据类型中任何一种类型的对象

表达式中读取的类型必须是最近一次存入和类型。程序员负责跟踪当前保存在联合中的类型。如果保存的类型与读取的类型不一致,其结果取决于具体的实现。

double bit2double(unsigned word0, unsigned word1)
{
    union {
        double d;
        unsigned u[2];
    } temp;
    temp.u[0] = word0;
    temp.u[1] = word1;
    return temp.d;
}

初始化

只能用第一个成员类型的值进行初始化。

6.9 位字段

设置

flags |= EXTERNAL | STATIC;

检测

if ((flags & EXTERNAL) == 0)

替代以上情况

struct {
    unsigned int is_keyword : 1;
    unsigned int is_extern : 1;
    unsigned int is_static : 1;
} flags;