结构体
C语言结构体(Struct)从本质上讲是一种自定义的数据类型,只不过这种数据类型比较复杂,是由 int、char、float
等基本类型组成的。你可以认为结构体是一种聚合类型。
在C语言中,可以使用结构体(Struct)来存放一组不同类型的数据。
结构体的定义形式为:
struct 结构体名{
结构体所包含的变量或数组
};
#include <stdio.h>
int main(){
struct{
char *name; //姓名
int num; //学号
int age; //年龄
char group; //所在小组
float score; //成绩
} stu1, stu2 = { "Tom", 12, 18, 'A', 136.5 };
//给结构体成员赋值,或逐个赋值
stu1.name = "Tom";
stu1.num = 12;
stu1.age = 18;
stu1.group = 'A';
stu1.score = 136.5;
//读取结构体成员的值
printf("%s的学号是%d,年龄是%d,在%c组,今年的成绩是%.1f!\n",
stu1.name, stu1.num, stu1.age, stu1.group, stu1.score);
return 0;
}
需要注意的是,结构体是一种自定义的数据类型,是创建变量的模板,不占用内存空间;结构体变量才包含了实实在在的数据,需要内存空间来存储。
共同体
在C语言中,还有另外一种和结构体非常类似的语法,叫做共用体(Union)共用体有时也被称为联合或者联合体,这也是 Union 这个单词的本意。
它的定义格式为:
union 共用体名{
成员列表
};
union data{
int n;
char ch;
double f;
} a, b, c;
//union data a, b, c;
//如果不再定义新的变量,也可以将共用体的名字省略:
结构体与共同体的异同
区别在于:1,结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。
,2,结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能会存在缝隙),共用体占用的内存等于最长的成员占用的内存。共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。
相同点:1,都是一种自定义类型,可以通过它来创建变量。2,不再定义新的变量,也可以将共用/结构体的名字省略。
共同体的应用
共用体在一般的编程中应用较少,在单片机中应用较多。
例如:设计一个包含共用体的结构体
#include <stdio.h>
#include <stdlib.h>
#define TOTAL 4 //人员总数
struct{
char name[20];
int num;
char sex;
char profession;
union{
float score;
char course[20];
} sc;
} bodys[TOTAL];
int main(){
int i;
//输入人员信息
for(i=0; i<TOTAL; i++){
printf("Input info: ");
scanf("%s %d %c %c", bodys[i].name, &(bodys[i].num),
&(bodys[i].sex), &(bodys[i].profession));
if(bodys[i].profession == 's'){ //如果是学生
scanf("%f", &bodys[i].sc.score);
}else{ //如果是老师
scanf("%s", bodys[i].sc.course);
}
fflush(stdin);
}
//输出人员信息
printf("\nName\t\tNum\tSex\tProfession\tScore / Course\n");
for(i=0; i<TOTAL; i++){
if(bodys[i].profession == 's'){ //如果是学生
printf("%s\t%d\t%c\t%c\t\t%f\n", bodys[i].name,
bodys[i].num, bodys[i].sex,
bodys[i].profession, bodys[i].sc.score);
}else{ //如果是老师
printf("%s\t%d\t%c\t%c\t\t%s\n", bodys[i].name,
bodys[i].num,bodys[i].sex,
bodys[i].profession, bodys[i].sc.course);
}
}
return 0;
}
函数/库函数
C语言在发布时已经为我们封装好了很多函数,它们被分门别类地放到了不同的头文件中,使用函数时引入对应的头文件即可。这些函数都是专家编写的,执行效率极高。
C语言自带的函数称为库函数(Library Function)。库(Library)是编程中的一个基本概念,可以简单地认为它是一系列函数的集合,在磁盘上往往是一个文件夹。C语言自带的库称为标准库(Standard Library),其他公司或个人开发的库称为第三方库(Third-Party Library)。
C语言无参函数的定义
#include <stdio.h>
int sum(){
int i, sum=0;
for(i=1; i<=100; i++){
sum+=i;
}
return sum;
}
int main(){
int a = sum();
printf("The sum is %d\n", a);
return 0;
}
有的函数不需要返回值,或者返回值类型不确定(很少见),那么可以用 void 表示,例如:
void hello(){
printf ("Hello,world \n");
//没有返回值就不需要 return 语句
}
C语言有参函数的定义
int sum(int m, int n){
int i, sum=0;
for(i=m; i<=n; i++){
sum+=i;
}
return sum;
}
C语言不允许函数嵌套定义;也就是说,不能在一个函数中定义另外一个函数,必须在所有函数之外定义另外一个函数。main() 也是一个函数定义,也不能在 main() 函数内部定义新函数。
#include <stdio.h>
void func2(){
printf("C语言小白变怪兽");
}
void func1(){
printf("http://c.biancheng.net");
func2();
}
int main(){
func1();
return 0;
}
func1()、func2()、main() 三个函数是平行的,谁也不能位于谁的内部,要想达到「调用 func1() 时也调用 func2()」的目的,必须将 func2() 定义在 func1() 外面,并在 func1() 内部调用 func2()。
有些编程语言是允许函数嵌套定义的,例如 JavaScript,在 JavaScript 中经常会使用函数的嵌套定义,所以说JavaScript具有灵活性。
自定义函数
除了库函数,我们还可以编写自己的函数,拓展程序的功能。自己编写的函数称为自定义函数。自定义函数和库函数在编写和使用方式上完全相同,只是由不同的机构来编写。
c语言中用户自定义函数的格式:
函数返回类型 函数名(参数列表)
{
代码段;
return 函数返回值;
}
例如:
int test(int value)
{
value += 10;
return value;
}
上面示例定义了一个名为test的函数,其返回值为int型,参数为int型,
返回值为参数与10之和。
注:函数类型为void时,不可有return语句。
来个样例程序(输入两个zhi数,求最大公约数)
#include <stdio.h>
#include <stdlib.h>
int a,b;
int gcd(int x,int y)
{
if (x%y==0)
return y;
else
return gcd(y,x%y);
}
int main()
{
scanf("%d%d",&a,&b);
printf("%d\n",gcd(a,b));
return 0;
}
函数声明以及函数原型
C语言代码由上到下依次执行,原则上函数定义要出现在函数调用之前,否则就会报错。但在实际开发中,经常会在函数定义之前使用它们,这个时候就需要提前声明。
所谓声明(Declaration),就是告诉编译器我要使用这个函数,你现在没有找到它的定义不要紧,请不要报错,稍后我会把定义补上。
函数声明的格式非常简单,相当于去掉函数定义中的函数体,并在最后加上分号;,如下所示:
#include <stdio.h>
//函数声明
int sum(int m, int n); //也可以写作int sum(int, int);
int main(){
int begin = 5, end = 86;
int result = sum(begin, end);
printf("The sum from %d to %d is %d\n", begin, end, result);
return 0;
}
//函数定义
int sum(int m, int n){
int i, sum=0;
for(i=m; i<=n; i++){
sum+=i;
}
return sum;
}
函数声明给出了函数名、返回值类型、参数列表(重点是参数类型)等与该函数有关的信息,称为函数原型(Function Prototype)。函数原型的作用是告诉编译器与该函数有关的信息,让编译器知道函数的存在,以及存在的形式,即使函数暂时没有定义,编译器也知道如何使用它。
函数声明的作用
有了函数声明,函数定义就可以出现在任何地方了,甚至是其他文件、静态链接库、动态链接库等,平常调用函数也多用到。