C语言 笔记2

OrzMiku / 2023-08-20 / 原文

枚举

常量符号化

我们可以用下面代码将常量符号化

const int red = 0;
const int yellow = 1;
const int blue = 2;

用枚举可以简写成

enum = colors {red,yellow,blue};

此时,red => 0 ,yellow => 1 ,blue => 2

枚举

  • 枚举是一种用户定义的数据类型,他用关键词enum以如下语法来声明:
enum 枚举类型的名字 {名字0,名字1,名字2...};
  • 枚举类型名字通常并不真的使⽤,要⽤的是在⼤括号⾥的名字,
    因为它们就是就是常量符号,它们的类型是int,值则依次从0
    到n。如:
enum colors {red,yellow,blue};
  • 枚举量可以作为值
  • 枚举类型可以跟上enum作为类型
  • 但是实际上是以整数来做内部计算 和外部输⼊输出的

自动计数的枚举

enum colors {red,yellow,blue,num};

此时num=3,可以用于计数

枚举量

enum colors {red=0,yellow=5,blue=8};

声明枚举量时可以指定值

  • 枚举类型可以当作类型使⽤,但是实际上 很(bu)少(hao)⽤
  • 如果有意义上排⽐的名字,⽤枚举⽐const int⽅ 便
  • 枚举⽐宏(macro)好,因为枚举有int类型

结构类型

声明结构类型

声明形式

struct <结构名称>{
    数据类型 成员名称;
    数据类型 成员名称;
	数据类型 成员名称;
} <变量名>;
    
eg: 
struct date{
    int year;
    int month
    int day;
} today;

eg:
struct date{
    int year;
    int month
    int day;
};
struct date today;

声明位置

  • 声明在函数内部,只能在函数内部使用
  • 声明在函数外部,可以被多个函数使用

结构的初始化

struct date{
    int year;
    int month
    int day;
};

struct date today = {2022,10,5};
struct date yesterday = {.month = 10,.day = 4}

结构的使用

  • 结构和数组有点像
  • 数组用 [] 访问其成员,结构用 . 来访问其成员
struct date{
    int year;
    int month
    int day;
};

struct date today = {2022,10,5};
printf("Today is %d/%d/%d\n",today.year,today.month,today.day);

结构运算

  • 要访问整个结构,直接使用结构变量的名字
  • 对于整个结构,可以赋值,取地址,也可以传递参数给函数
    • day1 = (struct date){2022,10,5};
    • day2 = day1;

结构指针

  • 和数组不同,结构变量的名字并不是结构变量的地址,需要使用&运算符
    • struct date *pDate = &today;

结构与函数

结构作为函数参数

函数类型 函数名(struct 结构名 变量名,...){}
  • 结构的值可以直接作为参数传入

  • 此时是在函数内新建了一个结构,并复制传入的值

  • 传入函数的结构在函数中只在值上等于原结构

  • 函数可以return一个结构

函数可以返回一个结构

struct 结构名 函数名(...){
	struct 结构名 变量名;
	return 变量名;
}

举个例子

#include<stdio.h>
struct info getInfo(void);

struct info {
    char name[5];
    int age;
    int id;
};

int main(){
    struct info student;
    student = getInfo();
    printf("姓名\t年龄\t学号\n%s\t%d\t%d\n",\
            student.name,student.age,student.id);
    return 0;
}

struct info getInfo(void){
    struct info t;
    scanf("%s%d%d",t.name,&t.age,&t.id);
    return t;
}

在这个例子中,getInfo返回了一个结构,并赋给了student变量.

结构指针作为参数

  • 相对于上面的方法,结构指针作为参数更推荐使用.

K & R

"If a large structure is to be passwd to a func, it's generally more efficent to pass a pointer than to copy whe whole structure"

  • 对于一个函数指针,可以用 -> 运算符访问指针所指结构下的成员.

因此,我们可以把上一个的例子修改为:

#include<stdio.h>
struct info* getInfo(struct info *t);
void printInfo(struct info *t);

struct info {
    char name[5];
    int age;
    int id;
};

int main(){
    struct info student;
    printInfo(getInfo(&student));
    return 0;
}

struct info* getInfo(struct info *t){
    scanf("%s%d%d",t->name,&t->age,&t->id);
    return t;
}

void printInfo(struct info *t){
    printf("姓名\t年龄\t学号\n%s\t%d\t%d\n",\
            t->name,t->age,t->id);
}

结构中的结构

结构数组

  • 结构数组的声明与访问和其他数组相似.

  • 结构数组中每个成员都是一个结构.

  • 使用 变量名[下标].成员名 来访问结构数组中结构的成员.

struct info {
    char[5] name;
    int age;
    int id;
}

struct info StudentList[3] = {
    {"张三",18,20221001}
    {"李四",18,20221002}
    {"王麻子",19,20221003}
}

printf("%s%d%d",StudentList[0].name,StudentList[0].age,StudentList[0].id);

结构中的结构

结构的成员也可以是一个变量

声明方法

struct sa {
    int i;
    ...
}

struct sb {
    struct sa a;
    ...
}

struct sb test{{1,...},...};

访问方法

printf("%d\n",test.a.i);

注意事项

如果有一个结构指针,可以使用 -> 来访问其成员。但成员如果是结构,访问结构成员的成员就不能用用 -> 了,因为 -> 是操作指针的运算符,不能操作结构变量.

struct sb *ptest = &test;
[√] ptest->a
[×] ptest->a->i
[√] ptest->a.i

结构中的结构的数组

😡😡😡套娃是吧,再套就不礼貌了

类型定义

typedef

当我们声明了一个结构之后,每次在使用的时候都要 struct 结构名 变量名 ,每次都要加一个struct,比较麻烦。这是,我们的主角typedef登场了。

C 语言提供了 typedef 关键字,您可以使用它来为类型取一个新的名字。比如 typedef int zs ,以后就可以用zs来定义一个int型了。

同理,typedef 可以给结构起一个新的名字,所以我们可以这样声明一个结构。

typedef struct {
    int id;
    char name[5];
    int age;
} info;

注意,此时info不再是一个变量,而是这个结构的别名。此后就可以使用info作为一种类型了。

define与typedef的异同

#define 是 C 指令,用于为各种数据类型定义别名,与 typedef 类似,但是它们有以下几点不同:

  • typedef 仅限于为类型定义符号名称,#define 不仅可以为类型定义别名,也能为数值定义别名,比如您可以定义 1 为 ONE。
  • typedef 是由编译器执行解释的,#define 语句是由预编译器进行处理的。

联合

联合体

union和struct很相似,他的定义方法为:

union data{
    int n;
    char ch;
    double f;
};
union data a, b, c;

但是与struct不同的是,在使用union时,所有成员共用一块内存空间。这块内存空间的大小取决与所有成员中最大的那一个。

下面有一个例子,可以直观的看到这一特点:

#include<stdio.h>
#include "style.h"
//hr()是style.h中的一个函数,用来创建分割线,这里我就不写出style.h里的内容了

typedef union info{
    int a;
    char b;
    float c;
} info;

int main(){
    info test;
    test.a = 123;
    hr('*',30);
    printf("test.a = 123\n\
print: test.a -> %d\n",test.a);
    test.b = 'a';
    hr('*',30);
    printf("test.b = 'a'\n\
print: test.a -> %d\n\
print: test.b -> %c\n",test.a,test.b);
    test.c = 123.456;
    hr('*',30);
    printf("test.b = 'a'\n\
print: test.a -> %d\n\
print: test.b -> %c\n\
print: test.c -> %f\n",test.a,test.b,test.c);
    hr('*',30);

    return 0;
}

返回结果:

******************************
test.a = 123
print: test.a -> 123
******************************
test.b = 'a'
print: test.a -> 97
print: test.b -> a
******************************
test.b = 'a'
print: test.a -> 1123477881
print: test.b -> y
print: test.c -> 123.456001
******************************

因为所有成员共用一块内存空间,所以union在初始化时不能像struct一样同时初始化多个成员。也就是说,联合体只有一个成员有效。

结构作为联合体的成员

我们可以在联合体中套一个结构。

union info{
	int id;
    char name[5];
    struct scores{
        int subjectID;
        int score;
    };
};