c的详细学习(9)结构体与共用体的学习(一)
C语言提供了另外两种构造类型:结构体与公用体,用来存储若干个类型不同但彼此组成一个集合的数据总体。
(1)结构体类型与结构体变量
1.定义
其一般形式为:
struct 结构体类型名{
数据类型1 成员名1;
数据类型2 成员名2;
数据类型3 成员名3;
......
}
定义一个结构体变量只是描述结构体的组织形式,并不意味着将分配一段内存单元来存放个数据项成员。它的作用只是告诉编译系统所定义的结构体类型是有哪些类型的成员构成的,各占多少字节,按什么形式存储,并把他们当作一个整体来处理。
2.结构体变量的定义:
结构体类型的变量的定义有三种方法:
1)先定义结构体类型,再定义结构体变量;struct student{省略成员的定义};struct student stu1,stu2;
2)定义结构体类型的同时,定义结构体变量;struct student{省略成员的定义}stu1,stu2;
3)不定义结构体的类型,直接定义变量。(此时结构体是无名的)struct{省略成员的定义}stu1,stu2;
结构体成员也可以是一个结构体变量,即一个结构体的定义中可以嵌套另外一个结构体的结构体的结构体。
struct date{
int year;
int month;
int day;
};
struct student{
long int number;
char name[20];
char sex;
struct date birthday;
char addr[30];
};
3.结构体变量的引用
在定义结构体类型变量以后,就可以引用结构体类型变量,如赋值,存取和运算等。遵循以下规则:
1)不能将结构体变量当作一个整体处理;
2)访问带有结构体变量成员的结构体时应采取逐级访问的方式;
3)结构体的成员变量和普通变量一样可以进行各种运算。
4.结构体变量的初始化
结构体类型是数组类型的扩充,只是它的成员项可以具有不同的数据类型:
struct student{
long num;
char name[20];
char sex;
char addr[20];
}s1={2006001,"MenAngel",'m',"anhui hefei"};
(2)结构体数组
结构体数组与普通的变量的数组大致相同:
初始化:
struct student{}stu1={{括号里与单个结构体初始化方式相同},{},{}......};
1)输入3名学生的信息并输出
#include<stdio.h>
#include<string.h> struct student{
long num;
char name[];
int age;
char sex;
int score;
}; int main(){
struct student stu[];
int i;
printf("学生的数据是:长整型的学号,字符数组的名字,整型的年龄,字符型的性别,整型的分数。\n");
for(i=;i<;i++){
printf("Please input all data of student[%d]\n",i+);
scanf("%ld,%s%d,%c,%d",&stu[i].num,&stu[i].name,&stu[i].age,&stu[i].sex,&stu[i].score);
}
printf("\n num\t name\t age\t sex\t score\n");
for(i=;i<;i++){
printf("%ld\t%s\t%d\t%4c\t%5d\n",stu[i].num,stu[i].name,stu[i].age,stu[i].sex,stu[i].score);
}
return ;
}
本例用是scanf函数输入各成员时,除字符型数组外,其他变量都采用","分隔,而字符数组以回车作为输入的结束。
2)统计候选人得票数。假设有3名候选人,每次输入一个得票人的名字,要求最后输出每个人的得票总数。
#include<stdio.h>
#include<string.h> struct person
{
char name[];
int count;
} leader[]={"Hu",,"Li",,"Ma",};//结构体数组的赋值 int main(){
int i,j;
char leader_name[];
for(i=;i<=;i++){
scanf("%s",leader_name);
for(j=;j<;j++){
if(strcmp(leader_name ,leader[j].name )==){
leader[j].count++;
}
}
}
for(i=;i<;i++){
printf("%5s:%d\n",leader[i].name,leader[i].count);
}
return ;
}
(3)结构体指针
指向结构体的指针称为结构体指针变量。该变量存放结构体变量的起始地址。结构体指针变量也可以指向结构体数组中的元素。
1.结构体指针变量的定义
struct 结构体类型 *结构体指针
例如:
struct student stu1,*p=&stu1;
在访问结构体变量的成员时:p->num等价于(*p).num;
2.结构体数组指针
一个结构体指针变量可以指向结构体数组,即将结构体数组的起始地址赋给指针变量,这种指针就是结构体指针。
struct student stu1[10],*p=stu1;
(4)结构体类型数据在函数间的传递
函数间不仅可以传递简单变量、数组、指针这些类型的数据,还可以传递结构体类型的数据。函数间结构体类型数据的传递和普通变量一样,可以“按值传递”,也可以“按地址传递”。
1.结构体变量作为函数参数
用结构体变量作为函数实参传递数据:
#include<stdio.h> struct Teacher{
char name[];
float salary;
float reword;
float income;
};
void display(struct Teacher p)
{
printf("\n%s %7.2f %7.2f %7.2f",p.name,p.salary,p.reword,p.income);
p.salary=;
p.reword=;
p.income=p.salary+p.reword;
printf("\n%s %7.2f %7.2f %7.2f",p.name,p.salary,p.reword,p.income);
}
int main(){
struct Teacher teacher;
printf("\nInput name:");
scanf("%s",teacher.name);
teacher.salary=;
teacher.reword=;
teacher.income=teacher.salary+teacher.reword;
display(teacher);
printf("\n%s %7.2f %7.2f %7.2f",teacher.name,teacher.salary,teacher.reword,teacher.income);
}
调用函数的实参与被调用函数的形参都是结构体变量名。
形参和实参的结构体类型相同,但运行时分配在不同的存储空间,因此,被调用函数不能修改调用函数的值。
2.结构体指针变量作为函数参数
#include<stdio.h> struct student{
long num;
char name[];
float score[];
}stb1={,"LiYing",67.9,78.5,91.2},stb2={,"YangLi",87.9,97.6,90.0}; void output(struct student *p){
printf("%ld\n%s\n%f\n%f\n%f\n",p->num,p->name,p->score[],p->score[],p->score[]);
printf("\n");
}; int main(){
output(&stb1);
output(&stb2);
return ;
}
3.结构体数组作为函数参数
用结构体数组写一个联系人管理的c程序,包括增删改查,打印所有联系人信息五个功能!
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct contacter{
int num;
char name[];
unsigned long linknumber;
};
struct contacter linkers[];
int count=;
//程序开始时的提醒:
void FirstWarn(){
printf("This is a c program used to manange your address book:\n");
printf("Chose different choice,then you will get disfferent function:\n");
printf("1.Establish and save a new contacter:\n");
printf("2.Delete a contacter:\n");
printf("3.Modify a contacter:\n");
printf("4.Search information of a contacter:\n");
printf("5.Print all of your contacters:\n");
}
//第1个功能,用来新建一个联系人
void newContacters(){
getchar();
if(count==){
printf("There is no storage space any more!\n");
}else if(count>=&&count<){
printf("Please input name:\n");
gets(linkers[count].name);
printf("please input his or her telephone number:\n");
scanf("%ld",&linkers[count].linknumber);
linkers[count].num=+count;
count++;
}
}
//用来验证输入的命令数字
void validate(int* p){
if(*p<|*p>){
printf("Warning: No Such order!\n");
printf("Please input a new order again:\n");
scanf("%d",p);
validate(p);
}
}
//第2个功能,实现删除一个联系人
//(1)用号码来删除
void deleteByNumber(int num){
int n;
n=num-;
for(int i=n;i<count;i++){
strcpy(linkers[i].name,linkers[i+].name);
linkers[i].linknumber=linkers[i+].linknumber;
}
count--;
}
//(2)用名字来删除
void deleteByName(char name[]){
for(int i=;i<count;i++)
if(!strcmp(name,linkers[i].name))
deleteByNumber(+i);
}
//第3个功能,实现输入名称修改联系人的信息
void modifyByName(char *name){
for(int i=;i<count;i++){
if(!strcmp(name,linkers[i].name)){
printf("Please input this linker's telephone:\n");
scanf("%d",&linkers[i].linknumber);
}
printf("After modifing:num=%d name=%s telephone=%ld\n",
linkers[i].num,linkers[i].name,linkers[i].linknumber);
}
}
void modifyByNumber(int num){
printf("Please input this linker's name\n");
gets(linkers[num-].name);
printf("Please input this linkers' telephone\n");
scanf("%ld",&linkers[num-].linknumber);
printf("After modifing:num=%d name=%s telephone=%ld\n",
linkers[num-].num,linkers[num-].name,linkers[num-].linknumber);
}
//第4个功能,实现查询功能
int searchByName(char *name,struct contacter *p,int count){
for(int i=;i<count;i++){
if(!strcmp(name,p[i].name)){
printf("The information of this person:\n");
printf("num=%d,name=%15s,telephone=%ld\n",p[i].num,p[i].name,p[i].linknumber);
return ;
}
}
return ;
}
int searchByNumber(int num,struct contacter *p, int count){
if(<=num-&&num-<=count){
printf("num=%d,name=%15s,telephone=%ld\n",
p[num-].num,p[num-].name,p[num-].linknumber);
}
}
//第5个功能,实现打印信息
void printAll(){
for(int i=;i<count;i++){
printf("第%d位联系人:num=%d; name=%15s; telephone=%ld \n",i+,linkers[i].num,linkers[i].name,linkers[i].linknumber);
}
}
int main(){
//在启动程序时自动创建一个包含100个变量的结构体数组
//记录用户的选择
int choice;
FirstWarn();
while(){
printf("Please input a order:\n");
scanf("%d",&choice);
validate(&choice);
switch(choice){
case :{
newContacters();
break;
}
case :{
printf("Chose the way of deleting linkers:\n");
printf("0.By name\n");
printf("1.By Number:\n");
int temp;
scanf("%d",&temp);
if(temp){
int number;
printf("Input the number:\n");
scanf("%d",&number);
deleteByNumber(number);
}else{
char name[];
printf("Print the name of linker who you want to delete:\n");
scanf("%s",name);
deleteByName(name);
}
break;
}
case :{
int list=;
printf("Chose a way to modyfy the contacter:\n");
printf("1.Modify the telephone only(By name)!\n");
printf("0.Modify both name and telephone(By number)!\n");
scanf("%d",&list);
if(list){
char name[];
printf("Please input the name:\n");
getchar();
gets(name);
modifyByName(name);
}else{
int num;
printf("Please input the number:\n");
scanf("%d",&num);
getchar();
modifyByNumber(num);
}
break;
}
case : {
int list=;
printf("Chose a way to search the contacter:\n");
printf("1.search by name!\n");
printf("0.search by number!\n");
scanf("%d",&list);
if(list){
char name[];
printf("Please input the name:\n");
scanf("%s",name);
if(!searchByName(name,linkers,count)){
printf("no such man!");
}
}else{
int num;
printf("Please input the person's number you want to search:\n");
scanf("%d",&num);
searchByNumber(num,linkers,count);
}
break;
}
case : {printAll();
break;}
default:printf("Errors!");break;
}
}
}
由于屏幕小,测试功能的截屏就是以上那么多!
总结遇到的问题:
1.在从键盘输入数据用scanf("%d",n),忘了加&,然而也不报错,检查半天,痛心!应为scanf("%d",&n);
2.本例用记录数组大小的数count,和结构体数组作为全局变量,事实上这样在每个函数中都可以自由更改它们的值。如果使用值传递的方式是不能更改count的值的,也不能更改结构体数组的值,操作起来非常不方便。
3.在用gets()函数,或者scanf()函数接收字符串时一定要确定前面是否有scanf()函数,如果有,确定用getchar();接收上面输入过程产生的回车符。
4.本例用long型数据存储电话号码,但貌似只能有8位整数,unsigned long貌似只能输入9位,无法达到11位的要求。这里就不在详细追究。事实上可以用字符数组来接收电话号码。
最新文章
- [Swift] 疑难杂症
- cocos2d-x避免手动修改android.mk文件来编译
- Object的增。删。查。改。遍历
- 20141014C#面向对象抽象方法,抽象类,接口
- smarty文件夹,第一个smarty实例总结
- 用大白话扯扯那";神奇";的面向对象编程思维(一)
- 学习python登录demo
- Selenium元素定位之Xpath
- Socket编程 之使用fsockopen()函数
- @RequestParam、@ReqeustBody、@ReponseBody认识
- Best Practices and Recommendations for RAC databases with SGA size over 100GB (文档 ID 1619155.1)
- Lua代码规范
- sklearn调参(验证曲线,可视化不同参数下交叉验证得分)
- http://218.245.4.98:20000/phpmyadmin:2018SCTF--easiest web - phpmyadmin
- 前端之html的常用标签2和css基本使用
- solc 编译Solidity
- php--------使用js生成二维码
- DOMNodeInserted监听div内容改变
- CentOS 7 系统下安装gnome图形界面
- robot framework踩坑记录