1、结构体定义
自定义数据类型
结构体:
struct 类型名
{
各成员
};
用数据类型定义单个变量:
定义内置类型举例:
int main()
{
int a = 10;
double b = 11.2;
int *p1 = &a;
double *p2 = &b;
int arr[10] = {1,2,5};
//...
return 0;
}
定义结构体举例:
struct Student//定义Student数据类型
{
//数据成员
char name[20];
int age;
};//定义完成后,其地位和内置类型一样
注意:结构体定义完成后,其地位和内置类型一样
所以以下代码可实现:
struct A
{
int a;
int b;
// struct B bb;//error,不合法
};
struct B
{
double c;
struct A d;//合法,可实现
//struct B e;//error,不合法
//struct B *f;//合法,例如设计列表的结点
};
struct Node//链表的结点
{
int date;
struct Node *next;
};
2、结构体指针和成员访问
结构体普通变量通过".“访问其成员;
结构体指针变量通过”->"访问其成员;
struct Student stu2;
struct Student *ps = &stu2;
//*ps.age = 15;//error,'*'优先级低于'.'
//(*ps).age = 15;//可行,但太过麻烦
ps->age = 15;
*ps.age = 15;报错:
测试代码:
struct A
{
int a;
int b;
};
struct B
{
double c;
struct A d;//合法,可实现
};
struct Student//定义Student数据类型
{
char name[20];
int age;
};//定义完成后,其地位和内置类型一样
int main()
{
int a = 10;
double b = 11.2;
int *p1 = &a;
double *p2 = &b;
*p1 = 100;
int arr[10] = {1,2,5};
//定义单个变量及初始化
struct Student stu1 = {"yasuo",21};
struct Student stu2;//不初始化,内容为随机值
struct Student stu3={"jie"};//只初始化一部分,剩余部分为0
//将stu3的年龄改为25
stu3.age = 25;
//输出stu3的信息
printf("%s,%d\n",stu3.name,stu3.age);
//类比:int *p1 = &a;
struct Student *ps = &stu2;
//stu2.name,stu2.age..
//通过ps将stu2的信息改为bulong,15
printf("原来的:%s,%d\n",stu2.name,stu2.age);
//*ps.age = 15;//error,'*'优先级低于'.'
//(*ps).age = 15;//可行,但太过麻烦
ps->age = 15;
//ps->name = "bulong";//error,数组不能整体复制
strcpy(ps->name,"bulong");
printf("更改后的:%s,%d\n",stu2.name,stu2.age);
return 0;
}
运行结果:
什么时候使用’.‘什么时候使用’->'相关例子
代码:
//会出现大量非法访问的问题和野指针,但暂时不管
struct A
{
int a;
double *b;
};
struct B
{
long *c;
struct A d;
};
//练习'.'和'->'
int main()
{
struct B aa;
struct B *bb = &aa;
//通过变量aa或bb访问其成员a,b,c
aa.c;//访问自己内部的成员,所以使用'.'
aa.d.a;
aa.d.b;
bb->c;
bb->d.a;
bb->d.b;
return 0;
}
结构体传参:
因为结构体一般比较大,所以传参要比较注意:
结构体进行参数传递时,都是传递指针,不传本身,节约空间;
示例代码:
struct Student//定义Student数据类型
{
char name[20];
int age;
};
void Show1(struct Student stu)
{
printf("%s,%d\n",stu.name,stu.age);
}
void Show2(const struct Student *pstu)
{
printf("%s,%d\n",pstu->name,pstu->age);
}
int main()
{
struct Student stu1={"yasuo",21};
printf("%s,%d\n",stu1.name,stu1.age);
Show1(stu1);//设计 不好,传递的数据(实参24字节)太大
Show2(&stu1);
return 0;
}
运行结果:
3、结构体数组
使用示例:
struct Student//定义Student数据类型
{
char name[20];
int age;
};
struct Student arr[3]={"caocao",20,"liubei",25,"sunquan",18};
图形结构:
使用示例代码:
struct Student//定义Student数据类型
{
char name[20];
int age;
};
void Show1(struct Student stu)
{
printf("%s,%d\n",stu.name,stu.age);
}
void Show2(const struct Student *pstu)
{
printf("%s,%d\n",pstu->name,pstu->age);
}
void Show(const struct Student *parr,int len)
{
for(int i=0;i<len;++i)
{
printf("%s,%d\n",parr[i].name,parr[i].age);
printf("%s,%d\n",(parr+i)->name,(parr+i)->age);
}
}
int main()
{
struct Student stu1={"yasuo",21};
struct Student arr[3]={"caocao",20,"liubei",25,"sunquan",18};
arr[1].age = 26;
//输出arr的内容
for(int i=0;i<sizeof(arr)/sizeof(arr[0]);++i)
{
printf("%s,%d\n",arr[i].name,arr[i].age);
}
Show(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
运行结果:
4、相关例题
1)投票器的实现
代码实现:
struct Person
{
char name[20];//候选人姓名
int count;//票数
};
void Show(const struct Person *arr,int len)
{
for(int i=0;i<len;i++)
{
printf("候选人:%s的票数为:%d\n",arr[i].name,arr[i].count);
}
}
//计票函数
void Ticket(struct Person *arr,int len)//仅实现基础功能,未进行优化
{
char name[20];//从键盘读票
for(int i=0;i<5;i++)
{
scanf("%s",name);
for(int j=0;j<len;j++)//遍历候选人列表
{
if(strcmp(arr[j].name,name)==0)
{
arr[j].count++;
break;
}
}
}
}
int main()
{
struct Person arr[]={"caocao",0,"liubei",0,"sunquan",0};
Ticket(arr,sizeof(arr)/sizeof(arr[0]));
Show(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
运行结果:
2)学生信息的读写及排序
代码:
struct Student//定义Student数据类型
{
int id;//学号
char name[20];//姓名
int score;//分数
};
//从键盘读取学生信息
void Input(struct Student *arr,int len)
{
for(int i=0;i<len;i++)
{
scanf("%d%s%d",&arr[i].id,arr[i].name,&arr[i].score);//arr[i].name不需要加取地址符,因为数组名本身表示地址
}
}
//void BubbleSort(int *arr,int len)
//{
// int tmp;
// for(int i=0;i<len-1;i++)
// {
// for(int j=0;j+1<len-i;j++)
// {
// if(arr[j]<arr[j+1])
// {
// tmp =arr[j];
// arr[j]=arr[j+1];
// arr[j+1]=tmp;
// }
// }
// }
//}
//分数从高到低排序(冒泡,从大到小)
void Sort(struct Student *arr,int len)
{
struct Student tmp;
for(int i=0;i<len-1;i++)//趟数
{
for(int j=0;j+1<len-i;j++)//j+1,小小心越界
{
if(arr[j].score < arr[j+1].score)
{
tmp =arr[j];
arr[j]=arr[j+1];
arr[j+1]=tmp;
}
}
}
}
//输出信息
void Show(const struct Student *arr,int len)
{
for(int i=0;i<len;i++)
{
printf("学号:%d 学生:%s的成绩为:%d\n",arr[i].id,arr[i].name,arr[i].score);
}
}
int main()
{
struct Student arr[5];
Input(arr,sizeof(arr)/sizeof(arr[0]));
Show(arr,sizeof(arr)/sizeof(arr[0]));
Sort(arr,sizeof(arr)/sizeof(arr[0]));
printf("------------\n");
Show(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
运行代码:
C语言有两个自带*的符号
"[]“和”->"自带解引用
因为:
p[i] == *(p+i)
p->age == (*p).age