结构体
- 基本定义:结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚合)的变量封装在内部,通过一定方法访问修改内部变量。
结构体定义:
第一种:只有结构体定义
struct stuff{
char job[20];
int age;
float height;
};
第二种:附加该结构体类型的“结构体变量”的初始化的结构体定义
//直接带变量名name
struct stuff{
char job[20];
int age;
float height;
}name;
其实这就相当于:
struct stuff{
char job[20];
int age;
float height;
};
struct stuff name;
第三种:如果该结构体你只用一个变量name,而不再需要去定义第二个变量。
struct stuff yourname;
那么,附加变量初始化的结构体定义还可进一步简化出第三种:
struct{
char job[20];
int age;
float height;
}name;
结构体变量的初始化
一般格式:
结构体类型 结构体变量名={初始值表};
方法一:
struct student{
char name[10];
int age;
float score[5],ave;
}stu={“zhangsan”,20,78,92,83,75,69};
方法二:
struct student{
char name[10];
int age;
float score[5],ave;
;
struct student
stu={"zhangsan",20,78,92,83,75,69};
也可以考虑结构体之间的赋值:
struct stuff faker = name;
//或 struct stuff faker2;
// faker2 = faker;
打印,可见结构体的每一个成员变量一模一样
求结构体类型数据的字节数
sizeof(变量名或类型名);
结构体类型数据成员的引用
引用规则:结构体变量除同类型赋值外,只能引用变量成员
引用方式: 结构体变量名.成员变量
stu.name = "dashan";
嵌套结构体中成员的引用
//结构体嵌套时,逐级引用
struct student
{
int num;
char name[20];
struct date
{ int month;
int day;
int year;
}birthday;
}stu1,stu2;
//给出生日期的年份赋值
stu1.birthday.year = 1999;
结构体和指针
结构体指针变量的定义形式:struct 结构体名 *结构体指针名;
struct student *p;
//此时指针变量*p中存放的是--结构体变量在内存的起始地址
//例:
struct student{
int num;
char name[20];
char sex;
int age;
}stu;
struct student *p=&stu;
结构体指针变量的引用(以下三种等价)
- (*结构体指针变量名).成员名
- 结构体指针变量名->成员名
- 结构体变量名.成员名
例:
struct student{
long int num;
char name[20];
char sex;
float score;
}stu1;
struct student *p = &stu1;
stu1.num=101; <=> (*p).num=101; <=> p->num=101;
函数递归
要理解递归,先理解递归。
(1) 递归就是在过程或函数里调用自身;
(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
线性递归
例:计算n!
使用递归的方式,n!可以定义为:
以线性递归的方式计算4!
F(4)=4×F(3) 递归阶段
F(3)=3×F(2)
F(2)=2×F(1)
F(1)=1 终止条件
F(2)=(2)×(1) 回归阶段
F(3)=(3)×(2)
F(4)=(4)×(6)
24 递归完成
以线性递归方式实现阶乘函数的实现:
int fact(int n) {
if(n < 0)
return 0;
else if (n == 0 || n == 1)
return 1;
else
return n * fact(n - 1);
}
实例:打印斐波那契数列前N项
#include <stdio.h>
#define N 10
int fibonaci(int i)
{
if (i == 0)
return 0;
if (i == 1)
return 1;
else
return fibonaci(i - 1) + fibonaci(i - 2);
}
int main(void)
{
int i;
for (i = 0; i < N; i++)
printf("%d\n", fibonaci(i));
return 0;
}
递归的基本思想是把规模大的问题转化为规模小的相似的子问题来解决。在函数实现时,因为解决大问题的方法和解决小问题的方法往往是同一个方法,所以就产生了函数调用它自身的情况。
*尾递归
以尾递归的方式计算4!
int fact(int n, int a)
{
if (n < 0)
return 0;
else if (n == 0)
return 1;
else if (n == 1)
return a;
else
return fact(n - 1, n * a);
}
实际上,尾递归是把变化的参数传递给递归函数的变量,函数在递归调用之前已经把所有的计算已经完毕了,他只要把得到的结果交给子函数就可以了。
F(4,1)=F(3,4)
F(3,4)=F(2,12)
F(2,12)=F(1,24)
F(1,24)=24
当编译器检测到一个函数调用是尾递归的时候,它就覆盖当前的活动记录而不是在栈中去创建一个新的。这样所使用的栈空间就大大缩减了,这使得实际的运行效率会非常高。