这里还只是讲一部分关于结构体的内容,更详细的内容在进阶—自定义类型详解中。
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
数组是一些相同类型的集合。
结构体是不同类型变量的集合。
我们已经学习了char shor int long float double类型对数据进行描述。
在生活中我们有些复杂对象无法用单一类型进行描述,例如:
人有名字,年龄,电话,住址
书有名字,作者,出版社,定价
在c语言中,为了描述复杂对象,创建了struct关键字。
struct tag
{member-list; //成员列表
}variable-list; //变量列表
tag结构体类型的名字
例如描述一个学生:
struct student
{char name[20];//名字int age;//年龄char sex[5];//性别int hight;//身高
}s1,s2,s3;
这里的s1就是一个学生s2一个学生s3一个学生。
不过这种写法比较少见,因为这里创建的变量s1s2s3是全局变量,一般我们定义为局部变量,不在此定义变量。
struct student
{char name[20];//名字int age;//年龄char sex[5];//性别int hight;//身高
};
定义变量
struct student
{char name[20];//名字int age;//年龄char sex[5];//性别int hight;//身高
}s1,s2,s3;//在创建类型同时定义全局变量struct student s5; //全局变量
int main()
{struct student s4;//局部变量
}
结构的成员可以是标量、数组、指针,甚至是其他结构体。
#include
struct student
{char name[20];//名字int age;//年龄char sex[5];//性别int hight;//身高
};struct pos
{int x;int y;
};
int main()
{struct pos p = { 10,20 };struct student s = { "zhangsan",20,"男",180 };printf("%d %d\n", p.x, p.y);printf("%s %d %s %d\n", s.name, s.age, s.sex, s.hight);
}
//-------------------
//编译器运行结果为
//10 20
//zhangsan 20 男 180
结构体中再嵌套一个结构体
#include
struct student
{char name[20];//名字int age;//年龄char sex[5];//性别int hight;//身高
};struct pos
{int x;int y;
};struct s
{char c;struct pos p;double d;char str[20];
};
int main()
{struct s ss = { 'x',{100,200},3.14,"hehe" };printf("%c %d %d %lf %s\n", ss.c, ss.p.x, ss.p.y, ss.d, ss.str);
}
//-------------------
//编译器运行结果为
//x 100 200 3.140000 hehe
结构体如何进行指定顺序赋值(不多使用)
#include struct pos
{int x;int y;
};struct s
{char c;struct pos p;double d;char str[20];
};
int main()
{struct s ss = { .d = 3.14,.c = 'x',.p.x=10 };printf("%c %d %d %lf %s\n", ss.c, ss.p.x, ss.p.y, ss.d, ss.str);
}
//------------------
//编译器运行结果为
//x 10 0 3.140000
进行指定赋值,且不完全初始化赋值。
当字符串里面全部都是0的时候,就不打印。
结构体外指定赋值
错误写法
#include
struct S
{char name[20];int age;
};
int main()
{struct S s = { .age = 20,.name = "zhangsan" };printf("%s %d\n", s.name, s.age);s.age = 30; //可行s.name = "zhangsanfeng"; //不可行return 0;
}
name是数组名,是首元素的地址,地址是一个门牌号,我们做的应该是把字符串放到地址所指向的空间里,而不是改变地址。
另一种错误写法
*(s.name)="zhangsanfeng";
s.name是数组首元素的地址,name是char类型数组,*(s.name)访问的的是一个字节的首元素空间,放不下一个字符串。
正确写法
#include
struct S
{char name[20];int age;
};
int main()
{struct S s = { .age = 20,.name = "zhangsan" };printf("%s %d\n", s.name, s.age);s.age = 30; //可行strcpy(s.name, "zhangsanfeng");printf("%s %d\n", s.name, s.age);return 0;
}
//----------------------
//编译器运行结果为
//zhangsan 20
//zhangsanfeng 30
值传递方式
#include
struct S
{int date[1000];char buf[100];
};
void print(struct S ss)
{int i = 0;for (i = 0; i < 10; i++){printf("%d ", ss.date[i]);}printf("%s\n", ss.buf);
}
int main()
{struct S s = { {1,2,3},"hehe" };print(s);return 0;
}
//------------------------
//编译器运行结果为
//1 2 3 0 0 0 0 0 0 0 hehe
原理
这里采用的是值传递,直接将变量s的整个内容传递给print函数,将print函数中的ss作为s的一份临时拷贝,进行打印。
同样了解如何打印整型数组和字符数组
#include
struct S
{int date[1000];char buf[100];
};int main()
{struct S s = { {1,2,3},"hehe" };//结构体成员为整型数组时的打印方式int i = 0;for (i = 0; i < 10; i++){printf("%d ", s.date[i]);}printf("\n");//结构体成员为字符数组时的打印方式printf("%s", s.buf);return 0;
}
//------------------------
//编译器运行结果为
//1 2 3 0 0 0 0 0 0 0
//hehe
址传递方式
#include
struct S
{int date[1000];char buf[100];
};
void print(struct S* ps)
{int i = 0;for (i = 0; i < 10; i++){printf("%d ", ps->date[i]);}printf("%s\n", ps->buf);
}
int main()
{struct S s = { {1,2,3},"hehe" };print(&s);return 0;
}
//------------------------
//编译器运行结果为
//1 2 3 0 0 0 0 0 0 0 hehe
结构体成员访问方法
结构体变量.结构体成员名
结构体指针->结构体成员名
传值调用和传址调用比较
传值调用:形参是实参的一份临时拷贝,如果实参占用的空间很大,那么形参占用的空间也很大。是一种空间上的浪费。
传址调用:只传过去了结构体变量的地址,所以优先选择传址调用。
函数传参的时候,参数是需要压栈的。
如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降
结论:
结构体传参的时候,要传结构体变量的地址。
结语:
初阶结构体的东西就这么多,C语言初阶我们也算是基本介绍完了,接下来我们下一章会讲解C语言进阶的知识,欲知后事如何,请听下回讲解。
上一篇:官方:利物浦与17岁后卫卢卡斯-皮特签下首份职业合同 官方:利物浦与17岁后卫卢卡斯-皮特签下首份职业合同
下一篇:多次表态想打!澳大利亚公布奥运22人初选名单 西蒙斯落选 多次表态想打!澳大利亚公布奥运22人初选名单 西蒙斯落选