十二、结构类型
🎈enum / 枚举
在定义几个独立的const常量时 可以使用枚举
枚举是一种用户定义的数据类型 关键字是enum
用于以更方便的方式定义多个可以排列的名字
语法:enum 枚举类型的名字 {名字1,名字2 ... 名字n};
比如:
const int ONEVALUE=0;
const int TWOVALUE=1;
const int THREEVALUE=2;
可以改为:
enum MYVALUE {ONE,TWO,THREE};
// 在这里ONE默认就是0 TWO默认就是1 THREE默认就是2
枚举类型的名字并不经常使用 而是直接使用大括号内定义的名字
这些名字它们就是常量符号 类型为int
值依次从0至n递增
枚举的意义 就是给一些排列的常量起名字
比如 enum MYVALUE{ONE,TWO,THREE} 的意思就是声明一种数据类型名为MYVALUE
可以将其当作一种数据类型来使用 但使用时必须带上enum关键字
比如void f(enum MYVALUE m) 或 enum MYVALUE m=TWO
由于其本质就是int 因此可以作为int来输入输出(%d)
用的时候 可以在最后加上一个计数器 用于表示枚举量共有多少:
enum MYVALUE{ONE,TWO,THREE,countVALUE}
在声明枚举量的时候 还可以指定值:
enum MYVALUE{ONE=2,TWO,THREE=6}
// 此时ONE是2 TWO是3 THREE是6 没有4和5了
然而 枚举实际上很少用…
🎈struct / 结构
若需要同时表达多个数据 或 表达出一个整体(比如一个人有姓名性别年龄之类的)
此时 需要用到结构
结构就是复合的数据类型 在其中可以有很多各种类型的成员 用一个变量来表示这些数据
(结构其实就像Java中的封装思想 将多个属性封装成了一个类)
简单例子:
#include <stdio.h>
// 声明一个类型为student的结构 里面有name属性和age属性
struct student
{
char* name;
int age;
};
int main(int argc,char const *argv[])
{
struct student student1;
student1.name="陈涛";
student1.age=18;
printf("%s\n",student1.name);
printf("%i\n",student1.age);
return 0;
}
和本地变量一样 在函数内部声明的结构类型只能在函数内部使用
因此 通常是在函数外部声明结构类型 这样即可被多个函数使用了
在声明结构变量(在Java中是创建对象)的时候 前面要加上struct
关键字 代表这是一个结构而不是自带的类型
struct dog
{
char* name;
int age;
}
struct dog dog1,dog2;
还有另一种方法来声明无名结构 (有点类似于JS的匿名函数…):
只是想要两个变量 而不关注其名字
struct
{
char* name;
int age;
} dog1,dog2;
还可以既声明结构名字又声明结构变量:
struct dog
{
char* name;
int age;
} dog1,dog2;
🚩结构初始化
直接用花括号来赋初始值
会按花括号内的值的顺序来依次赋值
struct student student1={"陈涛",18};
printf("%s\n",student1.name); // 陈涛
printf("%i\n",student1.age); // 18
还可以给具体的值赋值:
在属性值前面加上一个点.
即可
若未给整数赋值 则自动为0
若为给字符串复制 则自动为NULL
#include <stdio.h>
struct student
{
char* name;
int age;
};
int main(int argc,char const *argv[])
{
struct student student1={.age=18};
printf("name = %s\n",student1.name); // name = (null)
printf("age = %i\n",student1.age); // age = 18
return 0;
}
🚩结构运算
可以对整个结构赋值 取地址 也可以传递给函数作为参数
比如:
struct dog
{
char* name;
int age;
};
int main(int argc,char const *argv[])
{
struct dog d1,d2;
d1=(struct dog){"汪汪",2}; // 强制类型转换
d1.age=3;
d2=d1;
}
🚩结构指针
和数组不同 结构变量的名字并不是结构变量的地址
因此 若要取结构变量的地址 必须使用&运算符
struct dog
{
char* name;
int age;
};
int main(int argc,char const *argv[])
{
struct student student1;
struct student *pStudent=&student1;
printf("%p",&pStudent); // 0061FEC4
}
🚩结构与函数
结构可以传给函数作参数
int calcDog(struct dog d);
当作为函数的参数传入的时候 此时是在函数内新建了一个相同类型的结构变量 然后复制传入的结构的值
函数也可以返回一个结构作为返回值
#include <stdio.h>
struct student
{
char name;
int age;
};
struct student getStruct(void);
int main(int argc,char const *argv[])
{
struct student s1;
s1=getStruct();
printf("%s\n",&s1.name);
printf("%d\n",s1.age);
return 0;
}
struct student getStruct(void)
{
struct student s;
scanf("%s",&s.name);
scanf("%d",&s.age);
return s;
}
🚩指向结构的指针 -> 箭头符号
通常是传递结构的指针 而不是直接传递结构进函数
因为传递结构是拷贝的过程 在函数内创建新的一模一样的结构是比较耗费空间和时间的
在C中 可以使用(*p).xxx来表示结构指针中的某个成员
当然 还有更好的方法 那就是箭头符号
->
箭头符号 (arrow) 来表示指针所指的结构变量中的成员
#include <stdio.h>
struct student
{
char *name;
int age;
} s1;
int main(int argc,char const *argv[])
{
struct student *p=&s1;
(*p).name="张涛";
printf("%s\n",(*p).name); // 张涛
// 箭头符号
p->age=22;
printf("%d",p->age); // 22
return 0;
}
🚩结构数组
结构可以定义成数组的形式:
struct student students[3];
也可以赋初始值:
#include <stdio.h>
struct student
{
char *name;
int age;
};
int main(int argc,char const *argv[])
{
struct student students[]={
{"陈涛",18},
{"张涛",22},
{"王涛",16}
};
printf("%s",students[1].name); // 张涛
return 0;
}
🚩结构中的结构
在结构可以 不仅可以有基础类型 还可以有结构
但是被包括的结构 必须定义在用到该结构的结构上面
比如:
#include <stdio.h>
struct dog
{
char *name;
int age;
};
struct student
{
char *name;
int age;
struct dog dog;
};
int main(int argc,char const *argv[])
{
struct dog d={"汪汪",2};
struct student s={"陈涛",18,d};
printf("%s",s.dog.name); // 汪汪
return 0;
}
自定义数据类型 / typedef
在C中 提供了typedef
来声明一个已有的数据类型的新名字
格式:
typedef 旧类型名 新类型名
比如:
typedef int Myint; // 使得Myint成为int的别名
或
typedef *char[10] strings; // 使得strings成为*char[10]的别名
这样 即可使用新名字来定义或参数声明了
Myint a,b;
Myint numbers[10];
这样 可以使自定义的结构也改为一个新名字 这样就无需每次使用结构都在前面加上struct关键字了
typedef struct student
{
char *name;
int age;
} Mystudent;
Mystudent s={"陈涛",18,d};
也可以不提供结构的名字:
typedef struct
{
char *name;
int age;
} Mystudent;
Mystudent s={"陈涛",18,d};
🎈union / 联合
使用union
关键字来定义一个联合
union student
{
char c;
int i;
};
只不过和结构的区别是 联合里面的每一个成员都使用同一个内存空间 而不是分开的
同一时间只有一个成员是有效的 且union的大小是其最大的成员
联合通常的用处是得到整数内部的各个字节
可以利用union的这种共用的特性 作为文件读写的中间媒介