C语言的枚举、结构、自定义数据类型、全局变量、宏

1.枚举

枚举是一种用户定义的数据类型,它用关键字enum以如下语法来表明:
    enum 枚举类型名字{名字0,……,名字n};

枚举类型的名字通常并不使用,要用的是大括号里的名字,它们是常量符号,
他们的类型是int,值则依次从0到n。如:`enum colors{red,yellow,green};`
就是指创建了三个常量,red值为0,greed值为2。

2.枚举量

  • 枚举量可以作为值
  • 枚举类型可以跟上enum作为类型,但实际以整数计算和输入输出
  • 声明枚举量的时候可以指定值:
    • enum COLOR{RED=1,YELLOW,GREEN=5};
    • red值为1,则yellow值为2,green值指定为5。

3.声明结构类型

struct date{
    int month;
    int year;
};      //这个分号最容易忘记

struct date today;  //给这个结构取个名字
today.month = 05;   //给结构中的某个变量赋值
printf("Today's month is %i.\n",today.month);
  • 和本地变量一样,在函数内部声明的结构类型只能在函数内部使用,
  • 所以通常在函数外部声明结构类型,以便可以被多个函数使用。
  • 结构的初始化:
    • struct data {int month; int day; int year};
    • struct date today = {05,27,2020};
      • 按顺序指定赋值
    • struct date thismonth = {.month=5, .year=2020};
      • 没有给day赋值,默认为0。

4.声明结构的形式

// 1.p1和2都是point,里面有x和y的值。
    struct point{
        int x;
        int y;
    };
    struct point p1,p2;

// 2.p1和p2都是一种无名结构,里面有x和y。
    struct {
        int x;
        int y;
    } p1,p2;

// 3.p1和p2都是point,里面有x和y的值。 (最常见)
    struct point{
        int x;
        int y;
    } p1,p2;

// 对于第一和第三种形式,都声明了结构point。
// 但是第二种形式没有声明结构point,只定义了两个变量。

5.结构运算

  • 要访问整个结构,直接用结构变量的名字。
  • 可以对结构做:赋值、取地址、也可以传递给函数参数。
  • 数组无法做以下这种运算,结构可以:
    • p1=(struct point){5,10}; 相当于p1.x=5; p2.y=10;
    • p1 = p2; 相当于p1.x=p2.x; p1.y=p2.y;

6.结构指针

和数组不同,结构变量的名字并不是结构变量的地址,所以必须
使用&运算符获取地址:`struct date *pDate = &today;`

7.结构作为函数参数

int numberOfDays(struct data d)

  • 整个结构可以作为参数的值传入函数;
  • 这时在函数内新建一个结构变量,并复制调用者的结构的值;
  • 也可以返回一个结构,这些与数组完全不同。

8.输入输出结构

我们将一个结构传入了函数,然后在函数中操作,但是没有返回;
传入结构和传入数组是不同的,它传入的是外面那个结构的克隆体,而不是指针。
所以我们可以创建一个临时变量,然后把这个结构返回给调用者。

9.结构指针作为参数

struct data {
    int month;
    int day;
} myday;
struct data *p = &myday;
(*p).month = 12;    //符号较多,简写为下一行
p->month = 12;      //读作arrow,p所指的month

10.结构数组

可以自定义结构的类型。
struct time testTimes[3] = {{8,27,25},{11,0,0},{5,12,34}};

11.嵌套的结构

strcut rectangle {
    struct point pt1;
    struct point pt2;
};

如果定义这样一个变量:
    struct rectangle r,*rp;
    rp = &r;
则下面这四种形式是等价的:
    r.pt1.x  (r.pt1).x   rp->pt1.x  (rp->pt1).x
    但是没有rp->pt1->x,(因为pt1不是指针)

12.自定义数据类型(typedef)

C提供typedef的功能来声明一个已有的数据类型的新名字,
比如`typedef int Length`,使得Length成为int类型的别名。
这样,Length可以代替int出现在变量定义和参数声明啦。
`Length a,b,len;`,`Length numbers[10];`。

主要用于给复杂的struct定出名字。
typedef struct{
    int day;
    int year;
} data;
最后面的data是这个结构的名字。

13.联合(union)

  • 存储
    • 所有成员共享一个空间,
    • 同一时间只有一个成员是有效的,
    • union的大小是其最大的成员
  • 初始化
    • 对第一个成员做初始化

14.全局变量

  • 与任何函数都无关,可以在任何函数内部使用。
  • printf("in fun %s name=%d\n",__func__,gWord);
    这个字符串__func__表示当前函数的名字,即main。
  • 没有初始化会得到0值,指针会得到NULL值。
  • 只能用编译时已知的值来初始化全局变量。
  • 它们的初始化发生在main函数之前。
  • 如果函数内部存在和全局变量同名的变量,全局变量会被隐藏。

15.静态本地变量

  • 在本地变量定义时加上static修饰符即可。
  • 当函数离开时,静态本地变量会继续存在并保持其值。
  • 其初始化只会在第一次进入这个函数时做,以后会保持上次离开时的值。
  • 静态本地变量实际上是特殊的全局变量,(它们位于同样的内存区域)。
    • 具有全局的生存期,局部的作用域。

16.宏定义

  • #开头的是编译预处理指令。
  • 它们不是C语言成分,但是C语言程序离不开它们。
  • #define用来定义一个宏。

17.#define

  • #define <名字> <值>
    • 注意没有结尾的分号,因为不是C的语句。
    • 宏超过一行,最后需要加\。
  • 名字必须是一个单词,值可以是各种东西。
    • 在开始编译前,预处理会把程序中的名字换成值。
    • 完全的文本替换。
  • 使用参数:gcc --save-temps (将产生的临时文件保存下来)

18.没有值的宏

  • #define _DEBUG
    这类宏用于条件编译,后面又其他的编译预处理指令来检
    查这个宏是否已经被定义过了。

19.预定义的宏

  • __LINE__ %d 所在行数
  • __FILE__ %s 所在文件的全路径
  • __DATE__ %s 日期
  • __TIME__ %s 时间
  • __STDC__ 判断是否为标准C程序

20.带参数的宏

  • 基本原则:一切都要括号

    • 整个值要括号。
    • 参数出现的每个地方都要括号。
    • 前往不要加分号。
  • 可以带多个参数、求出较小值:

    • #define MIN(a,b) ((a)>(b) ? (b):(a))

你可能感兴趣的:(C)