感觉自己对结构体的使用还不太熟练,趁有空总结一下,多熟悉一些,以后好在实际的项目中更灵活的运用。
1,结构体的声明
struct Info //这里info是结构体的类型名
{
unsigned long identifier; //学号
char name[20]; //名字
unsigned int year; //入学年份
unsigned int years;//学制
}
2,结构体的定义
int main(void)
{
struct Info info; //这里info是结构体变量名,注意区分类型名和变量名
}
或者
struct Info //这里info是结构体的类型名
{
unsigned long identifier; //学号
char name[20]; //名字
unsigned int year; //入学年份
unsigned int years;//学制
}info; //注意 此时info是全局变量
int main(void)
{
...
}
3,初始化结构体
struct Info info={
20191101,
"Harris",
2019,
4
}; //感觉结构体初始化方式和数组初始化类似
4,对齐
#include <stdio.h>
int main(void)
{
struct A
{
char a;
int b;
char c;
}a={'a',10,'o'};
printf("size of a =%d\n",sizeof(a));
return 0;
}
运行结果:
size of a=12;
so what?
1+4+1=6, 总共是6字节,实际用了12字节。 在计算机中结构体的储存是采用字节对齐的方式储存的。
再比如:
#include <stdio.h>
int main(void)
{
struct A
{
char a;
char b;
int c;
}a={'a','o',10};
printf("size of a=%d\n",sizeof(a));
return 0;
}
运行结果:
size of a=8;
根据对齐理论,char a和char b共占用4字节,int c占用4字节,so一共8字节。
(具体是怎么保存的还待研究 是 a 0 b 0 c1 c2 c3 c4 ???)
5,结构体的嵌套
struct Date
{
unsigned int year;
unsigned int month;
unsigned int day;
}; //注意定义完打分号
struct Info
{
unsigned long identifier;
char name[20];
struct Date date;
unsigned int years;
};
int main(void)
{
struct Info info;
//使用的时候访问成员 info.date.day 。
printf("请输入学生的学号:");
scanf("%d", &info.identifier);
printf("请输入学生的姓名:");
scanf("%s", info.name); //直接用数组名
printf("请输入学生的入学年份:");
scanf("%d", &info.year);
printf("请输入学生的学制:");
scanf("%d", &info.years);
printf("\n数据录入完毕\n\n");
printf("学号:%d\n姓名:%s\n入学年份:%d\n学制:%d\n毕业时间:%d\n", \
info.identifier, info.name, info.year, info.years, info.year + info.years);
return 0;
}
运行结果如下:
请输入学生的学号:20191101
请输入学生的姓名:Harris
请输入学生的入学年份:2019
请输入学生的学制:4
数据录入完毕
学号:20191101
姓名:Harris
入学年份:2019
学制:4
毕业时间:2023
6,结构体数组。
定义结构体数组以下两种方式
struct A
{
unsigned char a;
unsigned char b;
unsigned int c;
}a[3];
或者:
struct A
{
unsigned char a;
unsigned char b;
unsigned int c;
};
struct A a[3];
7,结构体的指针
sturct Info* pinfo;
pinfo=&info;
通过结构体指针访问结构体成员的两种方法
1.(*结构体指针).成员名
2.结构体指针->成员名
我喜欢用第二种
第一种方法:
#include <stdio.h>
...
int main(void)
{
struct Info *p;
p = &info;
printf("学号:\n", (*p).identifier);
printf("姓名:\n", (*p).name);
printf("入学时间:%d/%d/%d\n", (*p).date.year, (*p).date.month, (*p).date.day);
printf("学制:\n", (*p).years);
return 0;
}
第二种方法:
#include <stdio.h>
...
int main(void)
{
struct Info *p;
p = &info;
printf("学号:\n", p -> identifier);
printf("姓名:\n", p -> name);
printf("入学时间:%d/%d/%d\n", p -> date.year, p -> date.month, p -> date.day);
printf("学制:\n", p -> years);
return 0;
}
8,结构体变量的传递
同类型名的结构体对象可以相互赋值,结构体也可以作为函数参数传递,也可以作为返回值返回。
直接将结构体作为参数传递会占用太大内存,应当传递结构体的指针。如下:
#include <stdio.h>
struct Date
{
unsigned int year;
unsigned int month;
unsigned int day;
};
struct Info
{
unsigned long identifier;
char name[20];
struct Date date;
unsigned int years;
};
void getInput(struct Info *info);
void printInfo(struct Info *info);
void getInput(struct Info *info)
{
printf("请输入学号:");
scanf("%d", &info->identifier);
printf("请输入姓名:");
scanf("%s", info->name);
printf("请输入入学年份:");
scanf("%d", &info->date.year);
printf("请输入月份:");
scanf("%d", &info->date.month);
printf("请输入日期:");
scanf("%d", &info->date.day);
printf("请输入学制:");
scanf("%d", &info->years);
}
void printInfo(struct Info *info)
{
printf("学号:%d\n姓名:%s\n入学时间:%d/%d/%d\n学制:%d\n毕业时间:%d\n", \
info->identifier, info->name, \
info->date.year, info->date.month, info->date.day, \
info->years, info->date.year + info->years);
}
int main(void)
{
struct Info i1 = {};
struct Info i2 = {};
printf("请录入第一个同学的信息...\n");
getInput(&i1);
putchar('\n');
printf("请录入第二个学生的信息...\n");
getInput(&i2);
printf("\n录入完毕,现在开始打印...\n\n");
printf("打印第一个学生的信息...\n");
printInfo(&i1);
putchar('\n');
printf("打印第二个学生的信息...\n");
printInfo(&i2);
return 0;
}
9,动态申请结构体
结构体可在堆里面动态申请,如下:
#include <stdio.h>
...
int main(void)
{
struct Info *i1;
struct Info *i2;
i1 = (struct Info *)malloc(sizeof(struct Info)); //申请结构体空间
i2 = (struct Info *)malloc(sizeof(struct Info)); //申请结构体空间
if (i1 == NULL || i2 == NULL)
{
printf("内存分配失败!\n");
exit(1);
}
printf("请录入第一个同学的信息...\n");
getInput(i1);
putchar('\n');
printf("请录入第二个学生的信息...\n");
getInput(i2);
printf("\n录入完毕,现在开始打印...\n\n");
printf("打印第一个学生的信息...\n");
printInfo(i1);
putchar('\n');
printf("打印第二个学生的信息...\n");
printInfo(i2);
free(i1);
free(i2);
return 0;
}
10,单链表
链表和数组的区别,链表中的个数据在计算的储存可以是离散的,通过一个个结点相互连接在一起。二数组的变量在内存中是连续的,不可拓展的。
头插法加入新结构体
struct Info
{
unsigned long identifier;
char name[20];
struct Date date;
unsigned int years;
struct Info* next;
};
在单链表中插入元素
void addInfo(struct Info** students)//students是头指针
{
struct Info *info, *temp;
info = (struct Info*)malloc(sizeof(struct Info));
if (info == NULL)
{
printf("内存分配失败!\n");
exit(1);
} //这里创建一个info的对象
getInput(info); //输入结构体成员
if (*students != NULL) //如果头指针不为空,表示该链表不为空
{
temp = *students; //吧头指针指向新建的info结构体
*students = info;
info->next = temp; //把info的中的next指针指向原students的指针指向的结构体
}
else
{
*students = info; //如果结构体为空,则直接把students指针指向新建的结构体
info->next = NULL;
}
}
由于students存放的是头指针,因此我们需要传入它的地址传递给函数,才能够改变它本身的值。而students本身又是一个指向Info结构体的指针,所以参数的类型应该就是struct Info**。
打印链表
void printStu(struct Info* students)
{
struct Info* info;
int count = 1;
info = students;
while (book != NULL)
{
printf("Student%d:\n", count);
printf("姓名:%s\n", info->name);
printf("学号:%d\n", info->identifier);
info = info->next;
count++;
}
}
释放空间
void releaseStu(struct Info** students)
{
struct Info* temp;
while (*students != NULL)
{
temp = *students;
*students = (*students)->next;
free(temp);
}
}
尾插法加入新结构体
void addInfo(struct Info** students)
{
struct Info* info, *temp;
info = (struct Info*)malloc(sizeof(struct Info));
if (info == NULL)
{
printf("内存分配失败!\n");
exit(1);
}
getInput(info);
if (*students != NULL)
{
temp = *students;
*students = info;
//定位到链表的末尾的位置
while (temp->next != NULL) //这里需要循环判断释放到达结尾位置
{
temp = temp->next;
}
//插入数据
temp->next = info;
info->next = temp;
}
else
{
*students = info;
info->next = NULL;
}
}
以上尾插法比较复杂,改进如下
void addInfo(struct Info** students)
{
struct Info* info, *temp;
static struct Info* tail;//设置静态指针
info = (struct Info*)malloc(sizeof(struct Info));
if (info == NULL)
{
printf("内存分配失败!\n");
exit(1);
}
getInput(info);
if (*students != NULL) //如果链表不为空
{
tail->next = info; //则把尾部中的tail中的next指针指向向尾部添加的info结构体
info->next = NULL; //info结构体中的next指针指向空
}
else
{
*students = info; //如果链表为空,
info->next = NULL;
tail=info; //这句是本人所加,在初次时tail指针应和头指针重合。
}
}
搜索单链表
struct Info *searchInfo(struct Info* students, long* target)
{
struct Info* info;
info = students;
while (info != NULL)
{
if (info->identifier == target)
{
break;
}
info = info->next;
}
return book;
};
void printInfo(struct Info* info)
{
...
}
...
int main(void)
{
...
printf("\n请输入学生学号:");
scanf("%d", input);
info = searchInfo(students, input);
if (info == NULL)
{
printf("抱歉,未找到相关结果!\n");
}
else
{
do
{
printf("相关结果如下:\n");
printInfo(book);
} while ((info = searchInfo(info->next, input)) != NULL);
}
releaseInfo(...);
return 0;
}
插入结点到指定位置
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int value;
struct Node* next;
};
void insNode(struct Node** head, int value)
{
struct Node* pre;
struct Node* cur;
struct Node* New;
cur = *head;
pre = NULL;
while (cur != NULL && cur->value < value)
{
pre = cur;
cur = cur->next;
} //这里查找要插入的店的位置,如果查到value>=cur->value .则停止
New = (struct Node*)malloc(sizeof(struct Node)); //新建一个结构体
if (New == NULL)
{
printf("内存分配失败!\n");
exit(1);
}
New->value = value; //新的结构体VALUE=VALUE
New->next = cur;
if (pre == NULL)
{
*head = New;
}
else
{
pre->next = New;
}
}
void printNode(struct Node* head)
{
struct Node* cur;
cur = head;
while (cur != NULL)
{
printf("%d ", cur->value);
cur = cur->next;
}
putchar('\n');
}
int main(void)
{
struct Node* head = NULL;
int input;
printf("开始插入整数...\n");
while (1)
{
printf("请输入一个整数,输入-1表示结束:");
scanf("%d", &input);
if (input == -1)
{
break;
}
insNode(&head, input);
printNode(head);
}
return 0;
}
删除结点
void delNode(struct Node** head, int value)
{
struct Node* pre;
struct Node* cur;
cur = *head;
pre = NULL;
while (cur != NULL && cur->value != value)
{
pre = cur;
cur = cur->next;
}
if (cur == NULL)
{
printf("未找到匹配项!\n");
return ;
}
else
{
if (pre == NULL)
{
*head = cur->next;
}
else
{
pre->next = cur->next;
}
free(cur);
}
}
11,typedef
给结构体起名
typedef struct date
{
int year;
int month;
int day;
} DATE;//为了区分,一般用全大写
int main(void)
{
DATE* date;
...
}
12,共用体
共用体的每一个成员共用一段内存,那么这也就意味着它们不可能同时被正确地访问。
union data
{
int i;
char ch;
float f;
};
i,ch,f共用内存
13,枚举
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};
14,位域
#include <stdio.h>
int main(void)
{
struct Test
{
unsigned int a : 1;
unsigned int b : 1;
unsigned int c : 2;
} test;
test.a = 0;
test.b = 1;
test.c = 2;
printf("a = %d, b = %d, c = %d\n", test.a, test.b, test.c);
printf("size of test = %d\n", sizeof(test));
return 0;
}