构造类型
数据类型
-
基本类型/基础类型/简单类型
-
整型
-
短整型:short -- 2字节
-
基本整型:int -- 4字节
-
长整型:long -- 32位系统4字节/ 64位系统8字节
-
长长整型:long long 8字节(大多数现代机器,旧机器可能超过8字节),C99新增
-
注意:以上类型又分为signed(默认) 和 unsigned
-
-
浮点型
-
单精度型:float --4字节
-
双精度型:double --8字节
-
长双精度型:long double -- 16字节(视平台而定),C99新增
-
-
字符型: char --1字节
-
-
指针类型
-
数据类型*:32位系统4字节,64位系统8字节
-
void*:通用指针类型(万能指针)32位系统4字节,64位系统8字节
-
-
空值类型
-
void:无返回值,无形参(不能修饰变量)
-
-
构造类型(自定义类型)
-
结构体类型:struct
-
共用体/联合体类型:union
-
枚举类型:enum
-
结构体
结构体定义【定义类型】
-
定义:自定义数据类型的一种,关键字struct。
-
语法:
struct 结构体名 // 结构体名:自定义的数据类型名字 类似于int,double之类的
{
数据类型1 成员名称1; // 结构体中的变量叫做成员
数据类型2 成员名称2;
...
};
-
注意:结构体中定义的变量,称之为成员变量(成员属性)
-
格式说明:
-
结构体名:合法的标识符,建议首字母大写(所谓的结构体名,就是自定义类型的类型名称)
-
数据类型n:C语言支持的所有类型(包括函数,函数在这里用函数指针表示)
-
成员名称n:合法的表示,就是变量的命名标准
-
数据类型n 成员名称n:类似于定义变量,定义了结构体中的成员
-
-
注意:
-
结构体在定义的时候,成员不能赋值,示例:
-
struct Cat
{
int age = 5; // 错误,结构体定义的时候,并未在内存中申请空间,因此无法进行赋值
double height; // 正确
void (*run)(void);// 正确
};
-
常见的定义格式:
-
方式1:常规定义(命名结构体,只定义数据类型)
struct Student { int num; // 学号 char name[20]; // 姓名 char sex; // 性别 int age; // 年龄 char address[100]; // 籍贯 void (*info)(void);// 信息输出(函数指针) };
-
方式2:匿名结构体(常用于作为其他结构体的成员使用)
struct Dog // 命名结构体 { char *name; // 姓名 int age; // 年龄 struct // 匿名结构体 { // 定义结构体时不能省略成员,否则编译报错 int year; // 年 int month;// 月 int day; // 日 } bithday; // 年龄,匿名结构体一定要提供成员名称,否则无法访问 };
-
注意:定义匿名结构体的同时必须定义结构体成员,否则编译报错;结构体可以作为另一个结构体的成员。
总结:
-
结构体可以定义在局部位置(函数作用域、块作用域),也可以定义在全局位置(推荐,可以复用)
-
全局位置的结构体名和局部位置的结构体名可以相同,遵循就近原则(和变量的定义同理)
-
-
结构体类型的使用:
利用结构体类型定义变量、数组,也可以作为函数的返回值和参数;结构体类型的使用与基本数据类型的使用类似。
-
结构体变量定义【定义变量】
三种形式定义结构体变量
说明:结构体变量也被称作结构体对象或者结构体实例。
-
第一种方式:
① 先定义结构体(定义数据类型)
② 然后定义结构体变量(定义变量)
示例:
// 定义结构体(定义数据类型) struct A { int a; char b; }; // 定义结构体实例/变量(定义变量) struct A x; // A就是数据类型,x就是变量名 struct A y; // A就是数据类型,y就是变量名
-
第二种方式:
① 在定义结构体的同时,定义结构体变量(同时定义数据类型和变量)
语法:
struct 结构体名 { 数据类型1 数据成员1; ... } 变量列表;
示例:
struct A { int a; char b; } x, y; // A就是数据类型,x,y就是变量名
-
第三种方式:
① 在定义匿名结构体的同时,定义结构体变量。
示例:
struct { int a; char b; } x, y;
此时定义了一个没有名字的结构体(匿名结构体),x,y是这个结构体类型的变量。
匿名结构体
-
优点:少写一个结构体名称
-
缺点:只能使用一次,定义结构体类型的同时必须定义变量。
-
应用场景:
-
当结构体的类型只需要使用一次,并且定义类型的同时定义了变量。
-
作为其他结构体的成员使用。
struct Cat { int age; char color[20]; } cat;
-
-
结构体成员部分初始化,大括号不能省略
-
结构体成员,没有默认值,是随机值,和局部作用域的变量一致。
案例:
#include <stdio.h>
/**
* 先定义结构体,再定义结构体变量(实例)
*/
void fun1()
{
// 定义结构体
struct A
{
int a;
char b;
};
// 定义结构体变量
struct A x;
struct A y;
struct A x1,y1;
}
/**
* 定义结构体的同时定义结构体变量
*/
void fun2()
{
struct A
{
int a;
char b;
} x,y;
struct A z;
struct A x1,y1;
}
/**
* 定义匿名结构体的同时定义结构体变量
*/
void fun3()
{
struct
{
int a;
char b;
} x,y;
struct
{
int a;
char b;
} z;
}
int main(int argc,char *argv[])
{
fun1();
fun2();
fun3();
return 0;
}
结构体变量的使用【变量使用】
结构体变量访问成员
语法:
结构体变量名(实例名).成员名;
① 可以通过访问成员进行赋值(存数据)
② 可以通过访问成员进行取值(取数据)
-
结构体变量未初始化,结构体成员的值是随机的(和局部作用域的变量和数组同理)
-
建议用大括号
{}
标明数据的范围。#include <stdio.h> /** 定义全局的结构体,方便被多个函数访问*/ struct Dog { char *name; // 名字 int age; // 年龄 char sex; // 性别 M:公,W:母 void (*eat)(void); // 吃狗粮 }; void eat() { printf("狗狗正在吃狗粮!\n"); } /** * 方式1:先定义,再初始化 ---> 结构体变量访问成员 */ void fun1() { // 定义结构体变量 struct Dog dog; // 结构体变量成员赋值 dog.name = "旺财"; dog.age = 5; dog.sex = 'M'; dog.eat = eat; // 结构体变量成员访问 printf("%s,%d,%c\n", dog.name, dog.age, dog.sex); // 访问成员方法(函数) dog.eat(); } /** * 方式2:定义的同时初始化,给变量成员初始化 */ void fun2() { // 定义结构体变量的同时,给变量成员初始化 struct Dog d1 = {"旺财", 5, 'M', eat}; // 完整初始化,按照顺序赋值 struct Dog d2 = {.name = "莱德", .sex = 'M'}; // C99之后,支持部分成员初始化,未初始化的成员自动填充0 struct Dog d3 = {"旺财"}; // C99之后,可以默认初始化第一个成员,其他成员用0填充 // 结构体变量成员访问 printf("%s,%d,%c\n", d1.name, d1.age, d1.sex); printf("%s,%d,%c\n", d2.name, d2.age, d2.sex); printf("%s,%d,%c\n", d3.name, d3.age, d3.sex); } int main(int argc, char *argv[]) { fun1(); printf("\n------------\n"); fun2(); return 0; }
结构体数组的定义【数组定义】
什么时候需要结构体数组
比如:我们需要管理一个学生对象,只需要定义一个
struct Student yifanjiao;
假如:我们需要管理一个班的学生对象,此时就需要定义一个结构体数组
struct Student stus[50];
定义
存放结构体实例的数组,称之为结构体数组。
四种形式定义结构体数组
- 第一种方式:
// 第一步:定义一个结构体数组
struct Student
{
char *name; // 姓名
int age; // 年龄
float scores[3]; // 三门课程的成绩
} stus[3];
// 第二步:赋值
stus[0].name = "张三";
stus[0].age = 21;
stus[0].scores[0] = 89;
stus[0].scores[1] = 99;
stus[0].scores[2] = 87;
stus[1].name = "李四";
stus[1].age = 22;
stus[1].scores[0] = 66;
stus[1].scores[1] = 77;
stus[1].scores[2] = 88;
- 第二种方式:
// 第一步:定义一个学生结构体(定义数据类型) struct Student { char *name; // 姓名 int age; // 年龄 float scores[3]; // 三门课程的成绩 }; // 第二步:定义结构体实例(定义结构体实例) struct Student zhangsan = {"张三", 21, {89,99,87}}; struct Student lisi = {"李四", 22, {66,77,88}}; // 第三步:定义结构体数组 struct Student stus[] = {zhangsan, lisi};
-
第三种方式:
// 第一步:定义一个学生结构体(定义数据类型) struct Student { char *name; // 姓名 int age; // 年龄 float scores[3]; // 三门课程的成绩 }; // 第二步:定义结构体数组并初始化成员 struct Student stus[] = { {"张三", 21, {89,99,87}}, {"李四", 22, {66,77,88}} };
-
第四种方式:
// 第一步:定义一个结构体数组,并初始化 struct Student { char *name; // 姓名 int age; // 年龄 float scores[3]; // 三门课程的成绩 } stus[] = { {"张三", 21, {89,99,87}}, {"李四", 22, {66,77,88}} };
结构体数组的访问【数组访问】
语法:
结构体成员.成员名 结构体指针 -> 成员名 // -> 结构体指针成员访问符
举例:
// 方式1:结构体成员访问 (*p).成员名 // 方式2:结构体指针访问 p -> 成员名
案例:
#include <stdio.h> /* 定义全局的Student结构体 */ struct Student { int id; // 编号 char *name; // 姓名 int age; // 年龄 float scores[3]; // 三门课成绩 void (*info)(char*,int); // 信息输出 }; void info(char* name, int age) { printf("大家好,我是%s,今年%d岁!\n", name, age); } int main(int argc, char *argv[]) { // 定义结构体实例并初始化 struct Student zhangsan = {1, "张三", 21, {78,88,98}, info}; struct Student lisi = {2, "李四", 22, {90,98,91}, info}; // lisi.info = info // 定义结构体数组并初始化 struct Student stus[] = {zhangsan, lisi}; // 计算数组的大小 int len = sizeof(stus) / sizeof(stus[0]); // 用一个指针进行遍历 struct Student *p = stus; // 表格-表头 printf("序号\t姓名\t年龄\t语文\t数学\t英语\n"); for (; p < stus + len; p++) { // 结构体成员访问,不推荐 // printf("%d\t%s\t%d\t%.2f\t%.2f\t%.2f\t\n",(*p).id, (*p).name, (*p).age, (*p).scores[0], (*p).scores[1], (*p).scores[2]); // (*p).info((*p).name, (*p).age); // 结构体指针访问,推荐 printf("%d\t%s\t%d\t%.2f\t%.2f\t%.2f\t\n",p->id, p->name, p->age, p->scores[0], p->scores[1], p->scores[2]); // 函数调用 p->info(p->name, p->age); } printf("\n"); return 0; }
结构体类型
结构体数组
案例
-
需求:对候选人得票进行统计,设有三个候选人,每次输入一个得票的候选人名字,最后输出个人得票的结果。
#include <stdio.h> #include <string.h> #define LEN 3 struct Person { char name[20]; int count; }; /* *定义候选人数组并初始化 */ struct Person persons[] = { {"小帅",0}, {"小张",0}, {"小黄",0} }; int main(int argc,char *argv[]) { //定义循环变量 register int i,j; //创建数组用来接收控制台录入的候选人名字 char leader_name[20]; //使用一个for循环,模拟10个人参与投票 printf("投票系统\n"); for ( i = 0; i < 10; i++) { printf("请输入目标投票人的名字:\n"); scanf("%s",leader_name); //从候选人列表中匹配被投票的人 count++ for (j = 0; j < LEN; j++) { //判断两个字符串是否相等 if (strcmp(leader_name, persons[j].name) == 0) { persons[j].count++; //票数+1 } } } printf("\n"); printf("\n投票结果:\n"); struct Person *p = persons; //指针p指向数组persons的第一个元素 //遍历数组:使用指针变量 for ( ; p < persons + LEN; p++) { printf("%s:%d\n",p ->name, p ->count); } printf("\n"); //遍历数组:使用指针 for ( i = 0; i < LEN; i++) { printf("%s:%d",(persons + i)->name,(persons + i) ->count); } //遍历数组:使用下标 for ( i = 0; i < LEN; i++) { printf("%s:%d",persons[i].name,persons[i].count); } return 0; }