1 结构体初识篇
C语言的结构体其实就相当于C++里的类
c
#include <stdio.h>
#include <string.h>
1.创建结构体
结构体类型-->描述结构化数据
struct 标识符
{
特征--->基本数据类型描述
};
struct MM
{
char name[20];
int age;
int num;
char addr[20];
};
1.1 C语言不允许空的结构体存在
//struct empty
//{
//};
-----------------------------------------------------------------------------------------
2.怎么访问数据
2.1 结构体中数据必须要通过结构体变量访问
2.2 怎么创建结构体变量 类型+变量名;
2.3 访问方式
结构体变量 变量.成员
结构体指针 指针->成员
int main()
{
//创建结构体变量
struct MM girl;
//数组不能不能直接赋值需要strcpy
//girl.name = "sdfg";
strcpy_s(girl.name, 20, "小美");
girl.age = 38;
//指针用-> 一般不这样写
(&girl)->num = 1001;
strcpy_s(girl.addr, 20, "我家");
printf("%s\t%d\t%d\t%s\n", girl.name, girl.age, girl.num, girl.addr);
//类型* 变量名;
struct MM* pMM = NULL;
//有问题 NULL里面没有age
//pMM->age = 123;(错误)
pMM = &girl;
printf("%s\t%d\t%d\t%s\n", (*pMM).name, (*pMM).age, (*pMM).num, (*pMM).addr);
//-> 指针指向运算符 这种好看
printf("%s\t%d\t%d\t%s\n", pMM->name, pMM->age, pMM->num, pMM->addr);
return 0;
}
2 结构体的创建与初始化
c
#include <stdio.h>
struct MM
{
char name[20];
int age;
double score;
};
-----------------------------------------------------------------------------------------
2.结果体变量创建
struct MM g_mm = { "全局",18,1.2f };//先创建再初始化
struct Data
{
char name[20];
int age;
double score;
}value = {"全局",18,1.0f},arr[3],a,b;
//value是变量名
//value ,a,b 都是一个结构体变量
//arr[3] 结构体数组
-----------------------------------------------------------------------------------------
3.typedef 与结构体创建(可以简化代码,目前觉得鸡肋,代码长了就有用了)
typedef struct Test
{
char name[20];
int age;
int score;
}Test,*PTest,ARRAY[3];
//Test,*PTest,ARRAY[3] 都是类型别名
//typedef struct Test Test,
//typedef struct Test *PTest,
//typedef struct Test ARRAY[3];
void test_typedef_struct()
{
struct Test t1;
Test t2; //struct Test t2
struct Test* p1 = NULL;
PTest p2 = NULL; // struct Test *p2
struct Test array1[3];
ARRAY array2; // struct Test array2[3]
}
-----------------------------------------------------------------------------------------
4 特殊结构体定义
struct //没有名字的结构体这个结构体只有一个变量
{
int num;
int key;
}SingleTon;
typedef struct //有typedef,就有了别名,可以随意创建变量
{
int num;
int key;
}Type;
void test()
{
Type a = { 1,2 };
Type b = { 2,3 };//可以无限定义变量
SingleTon.num = 23;
SingleTon.key = 123;//只有这两个
}
-----------------------------------------------------------------------------------------
int main()
{
//1.可以创建变量的时候用大括号方式初始化(局部的)
struct MM mm1 = { "小帅",18,1.234 };
struct MM mm2 = { "小美"}; //age和score默认为0
struct MM mm3 = { .age = 12,.name = "小花",.score = 1.2f };
printf("%d\t%.2lf\n", mm2.age, mm2.score);
printf("%s\t%d\t%.1lf\n", mm3.name, mm3.age, mm3.score);
test_typedef_struct()
//测试3
struct black_red_node* p = (struct black_red_node*)malloc(sizeof(struct black_red_node));
RBNode* p1 = (RBNode*)malloc(sizeof(RBNode));
return 0;
}
3 结构体数组
c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
struct MM
{
char name[20];
int age;
char addr[20];
};
//1 输入和打印
void test()
{
struct MM arr[3];
printf("input mm(3):");
for (int i = 0; i < 3; i++)
{
//scanf("%s%d%s", arr[i].name,&arr[i].age, arr[i].addr);
scanf_s("%s%d%s", arr[i].name, 20, &arr[i].age, arr[i].addr, 20);//scanf_s要加尺 寸,别的编译器不用
}
printf("姓名\t年龄\t编号\n");
for (int i = 0; i < 3; i++)
{
printf("%s\t%d\t%s\n", arr[i].name, arr[i].age, arr[i].addr);
}
}
-----------------------------------------------------------------------------------------
//2 结构体数组的冒泡排序(传函数指针的方式)
void bubble_sort(struct MM* arr, int arrayNum,bool(*compare)(struct MM,struct MM))
{
for (int i = 0; i < arrayNum; i++)
{
for (int j = 0; j < arrayNum - i - 1; j++)
{
//比较规则,剥洋葱
if (compare(arr[j],arr[j+1]))
{
//memcpy
struct MM temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
void print_mm(struct MM arr[], int arrayNum)
{
printf("姓名\t年龄\t编号\n");
for (int i = 0; i < arrayNum; i++)
{
printf("%s\t%d\t%s\n", arr[i].name, arr[i].age, arr[i].addr);
}
}
//可以自己写按什么方式去比较(用函数指针升级一下)
bool compare_by_age(struct MM one, struct MM two)
{
return one.age > two.age;
}
bool compare_by_name(struct MM one, struct MM two)
{
return strcmp(one.name,two.name)>0;
}
bool compare_by_addr(struct MM one, struct MM two)
{
return strcmp(one.addr, two.addr)>0;
}
-----------------------------------------------------------------------------------------
int main()
{
struct MM data[5] =
{ "4小芳",18,"6地球",
"2小花",48,"776号" ,
"1小美",28,"8海南" ,
"4小李",38,"9天津" ,
"6小小",58,"0西藏"
};
bubble_sort(data, 5,compare_by_age);
print_mm(data, 5);
bubble_sort(data, 5, compare_by_name);
print_mm(data, 5);
bubble_sort(data, 5, compare_by_addr);
print_mm(data, 5);
return 0;
}
4 位段
以后可能会看见,但自己很少用(做特别精小的软硬件)
c
#include <stdio.h>
#include <stdlib.h>
struct Flag
{
//:后面的数字代表的是变量占用内存是多少个二进制位
unsigned int a : 3; //3个二进制位 _ _ _ 最小000 最大111
unsigned int b : 2; //2个二进制位 _ _ 最小00 最大11
unsigned int c : 3; //3个二进制位
};
int main()
{
//溢出:超过存储范围
struct Flag flag;
flag.a = 5;
flag.b = 1;
flag.c = 8; //_ _ _ _ 1000
printf("溢出:%u\n", flag.c);//无符号打印%u,打印后三位就是0
printf("a=%u,b=%u\n", flag.a, flag.b);//打印5,1
flag.c = 9; //1001
printf("溢出:%u\n", flag.c);//打印1
return 0;
}
5 枚举类型和共用体
c
#include <stdio.h>
#include <string.h>
1.创建枚举
//enum 标识符{符号...}符号常量
enum Color{Red,Blue,Yellow,Green};
//默认值 Red=0 Blue=1 Yellow=2 Green=3
-----------------------------------------------------------------------------------------
2干啥用,咋用
//程序中需要大量具有相同含义数字------>推箱子
2.1枚举菜单项
enum Menu {Insert,Delete,Modify,Sort,Search};
void keyDown()
{
int key;
scanf_s("%d", &key);
switch (key)
{
case Insert:
break;
case Delete:
break;
case Modify:
break;
case Sort:
break;
case Search:
break;
}
}
2.2初始化规则------>没有初始化的是前面的加1
enum Dir {Left=75,Right,Up=80,Down,Mid};
//Right: 75+1
//Down: 80+1
//Mid:Down+1=80+2
-----------------------------------------------------------------------------------------
3.C语言枚举类型当函数参数,也是可以传入整形变量
void print_value(enum Dir a)
{
printf("%d\n", a);
}
-----------------------------------------------------------------------------------------
共用体 union
union Value
{
char name[20];
int age;
};
void test_union()
{
//共同体 -->也叫联合体
//所有变量共用同一块内存,一段内存给两个变量用
//union Value value = { "A",65}; //不能同时初始化两个变量
union Value value;
strcpy_s(value.name, 20, "A");
puts(value.name);
printf("%d\n", value.age); //65
//value.age = 65;
//printf("%d\n", value.age);
//puts(value.name);
}
-----------------------------------------------------------------------------------------
int main()
{
//1
printf("Red:%d\n", Red);//1
printf("Blue:%d\n", Blue);//2
//2
printf("Mid:%d\n", Mid);//82
//3
print_value(999);
print_value(Left);
//共用体
test_union();
return 0;
}
6 结构体嵌套
c
#include <stdio.h>
#include <stdlib.h>
//推荐嵌套
struct Score
{
int math;
int english;
int py;
};
struct Info
{
char name[20];
int age;
char addr[20];
char tel[14];
};
struct Student
{
struct Info info;
struct Score score;
};
-----------------------------------------------------------------------------------------
//直接包含(个人感觉有一点别扭)
struct A
{
int a;
struct B
{
int age;
int num;
}b;//一般这里跟一个变量
};
-----------------------------------------------------------------------------------------
int main()
{
struct Student stu = { {"小芳",18,"火星","18934873456"},{88,89,99}};
printf("%s\t%d\t%s\t%s\t%d\t%d\t%d\n",
stu.info.name,
stu.info.age,
stu.info.addr,
stu.info.tel,
stu.score.math,
stu.score.english,
stu.score.py);
struct A object = { 1,{23,45} };
printf("%d\t%d\t%d\n", object.a, object.b.age, object.b.num);
return 0;
}
7 结构体中的指针
时刻考虑内存问题
c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
struct MM
{
char* name;
int age;
};
//返回一个堆区的结构体变量
struct MM* create_mm(const char* name, int age)
{
struct MM* temp = (struct MM*)malloc(sizeof(struct MM));
assert(temp);
//temp->name = name;
int length = strlen(name) + 1;
temp->name = (char*)malloc(length);
strcpy_s(temp->name, length, name);
temp->age = age;
return temp;
}
-----------------------------------------------------------------------------------------
int main()
{
struct MM one = { "ILoveyou",18 };
struct MM two = { "小花",28 };
struct MM temp = one;
one = two;
two = temp;
printf("%s\t%d\n", one.name, one.age);
printf("%s\t%d\n", two.name, two.age);
//这个操作就是错误的
// name是指针,没有内存
//strcpy_s(one.name, 20, "小可爱");
one.name = (char*)malloc(20);
assert(one.name);
strcpy_s(one.name, 20, "小可爱");
printf("%s\t%d\n", one.name, one.age);
struct MM* p = create_mm("小宝贝", 18);
printf("%s\t%d\n", p->name, p->age);
return 0;
8 结构体内存问题
(有学业需求的)封装------>减少内存,传输数据就少点
c
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <assert.h>
1
//具体占用内存多少其实不是那么重要,
//怎么写才省内存才是重要的。
-----------------------------------------------------------------------------------------
2 内存对齐
(按成员最长字节对齐)
//char 可以拆分
//char可以和int以及float填补
struct MM
{
char name[20]; //8+8+ 多4可以和下面的补一起
int age; //4+上面的多4
double num; //8
//8+8+4+4+8=32
};
struct Data
{
char name[20]; //8+8 多4不能和下面补,要多补4
double num; //8
int age; //4+补4
//8+8+4+4+8+4+4=40
};
一样的东西,写法顺序不一样,内存多占8位,数据特别大的时候流量就用的多了
-----------------------------------------------------------------------------------------
struct Value
{
char name[3]; //3 补1
int age; //4
char id[2]; //2 补2
};
struct Test
{ //64位中,指针占8个字节
char name[9]; //8+1+补7
char* p; //8
int age; //4 +补4
//8+1+7+8+4+4=20
};
-----------------------------------------------------------------------------------------
int main()
{
//1
//自己写代码一个sizeof就行了,自己不用算内存是多少
printf("%zd\n", sizeof(struct MM));
struct MM* p = (struct MM*)malloc(sizeof(struct MM));
assert(p);
//2
printf("MM:%zd\n", sizeof(struct MM));
printf("Data:%zd\n", sizeof(struct Data));
printf("Value:%zd\n", sizeof(struct Value));
printf("Test:%zd\n", sizeof(struct Test));
return 0;
}
#pragma pack(8)写在头文件中------>代表着指定每个成员按照8字节对齐