1.结构体
1.如何创建结构体数据类型
//定义结构体语句
struct 结构体名字
{
属性1;
属性2;
属性3;
.......
};
//(学生)集合属性:
1.姓名 char name[SIZE]; //字符数组和字符串是标配
2.身高 int height; //基本数据
3.三门成绩 float scores[3];//数组
//定义一个学生的结构体
struct student
{
char name[20];
int height;
float scores[3];
};
2.如何创建结构体变量
#include <stdio.h>
//定义一个学生的结构体数据类型
struct student
{
char name[20];
int height;
float scores[3];
};
//定义一个结构体数据类型,该名字叫struct student
int main(void)
{
//类型名 变量名;
//定义一个结构体变量并进行初始化
struct student s1={"lisi",183,{90,89,78}};
return 0;
}
3.如何访问变量的值
#include <stdio.h>
//定义一个学生的结构体数据类型
#define N 20
#define M 3
struct student
{
char name[N];
int height;
float scores[M];
};
//定义一个结构体数据类型,该名字叫struct student
int main(void)
{
//类型名 变量名;
//定义一个结构体变量并进行初始化
struct student s1={"lisi",183,{90,89,78}};
int i=0;
//输入
printf("请输入姓名,身高,三门成绩\n");
scanf("%s%d",s1.name,&s1.height);
for(i=0;i<M;i++)
{
scanf("%f",&s1.scores[i]);
}
//输出:
printf("%s %d ",s1.name,s1.height);
for(i=0;i<M;i++)
{
printf("%5.0f",s1.scores[i]);
}
printf("\n");
return 0;
}
4.如何操作结构体的指针
//定义一个指向int的指针
int * pi=NULL; //sizeof(pi)=8 pi+1 sizeof(int)
//定义一个指向结构体(struct student)的指针
struct student * ps=NULL; //sizeof(ps)=8 ps+1 (struct student)
2.内存管理
3.在堆区分配空间和释放空间
1.分配空间
#include <stdlib.h>
//参数:你要分配空间的大小
//返回值:void * void (表示空) void * (任何数据类型的地址)
//分配成功返回空间的首地址,失败则返回NULL
//malloc分配的空间未进行清空
void *malloc(size_t size);
2.释放空间
#include <stdlib.h>
//参数1:释放空间的首地址
void free(void *ptr);
#include <stdio.h>
#include <stdlib.h> //malloc的头文件
int main(void)
{
//int * pi=NULL; //栈区
//pi=(int *)malloc(4); //堆区,分配4个字节的空间
//pi=(int *)malloc(sizeof(int)); //堆区,分配4个字节的空间
//1.分配空间
int * pi=(int *)malloc(sizeof(int));
//2.出错判断
if(NULL==pi)
{
perror("malloc error:"); //标准出错,会将错误原因显示出来
return -1; //-1:一般表示异常结束
}
printf("请输入一个整数\n");
scanf("%d",pi);
//*pi=5;
printf("%d\n",*pi);
//3.释放空间
free(pi);
pi=NULL;
return 0;
}
4.结构体和堆区空间关联起来
1.在堆区创建5个存结构体的空间
#include <stdio.h>
#include <stdlib.h>
#define N 20
#define M 3
#define SIZE 5
//该句话是前两句话的简化
typedef struct student
{
char name[N];
int height;
float scores[M];
}Stu;
int main(void)
{
Stu * ps=NULL;
//1.分配空间
//再堆区创建5个存结构体的空间
ps=(Stu *)malloc(sizeof(Stu)*SIZE);
//2.出错判断
if(NULL==ps)
{
perror("malloc error");
return -1;
}
//3.释放
free(ps);
ps=NULL;
return 0;
}
2.编写一子函数,对ps指向的空间进行输入和输出
#include <stdio.h>
#include <stdlib.h>
#define N 20
#define M 3
#define SIZE 5
//该句话是前两句话的简化
typedef struct student
{
char name[N];
int height;
float scores[M];
}Stu;
void menu(void);
void menu(void)
{
printf("1---------input\n");
printf("2---------output\n");
printf("3---------calPMaxheight\n");//获得身高最高人的地址
printf("4---------calpMinheight\n");//获得身高最低人的地址
printf("5---------swap(Stu *pMax,Stu * pMin)\n");//获得身高最低人的地址
printf("6---------sortByHeight\n");//按照身高排序
printf("7---------sortByName\n"); //按照姓名排序
printf("8---------sortBySumScore\n");//按照总分排序
printf("-1--------exit\n");
printf("请输入选项\n");
}
//编写一子函数,实现对ps指向的空间进行输入
//参数1:该空间的首地址 Stu * ps
//参数2:元素的个数 int n
//返回值:void
void input(Stu * ps,int n);
void input(Stu * ps,int n)
{
//输入
int i=0,j=0;
for(j=0;j<n;j++)
{
printf("请输入姓名,身高,三门成绩\n");
scanf("%s",ps->name);
scanf("%d",&ps->height);
for(i=0;i<M;i++)
{
scanf("%f",&ps->scores[i]);
}
ps++; //自增到下一个学生的首地址
}
}
//编写一子函数,对ps指向的空间进行输出
//参数1:该空间的首地址 Stu * ps
// 参数2:元素的个数 int n
// 返回值:void
void output(Stu * ps,int n);
void output(Stu * ps,int n)
{
int i=0,j=0;
for(j=0;j<n;j++)
{
//输出
printf("%10s",ps->name);
printf("%5d",ps->height);
for(i=0;i<M;i++)
{
printf("%5.0f",ps->scores[i]);
}
printf("\n");
ps++;
}
}
int main(void)
{
int op=0;
Stu * ps=NULL;
//再堆区创建5个存结构体的空间
ps=(Stu *)malloc(sizeof(Stu)*SIZE);
if(NULL==ps)
{
perror("malloc error");
return -1;
}
while(1)
{
menu();
scanf("%d",&op);
if(-1==op) break;
switch(op)
{
case 1:
input(ps,SIZE);
break;
case 2:
output(ps,SIZE);
break;
}
}
free(ps);
ps=NULL;
return 0;
}
编写一子函数,获得身高最高的人地址
Stu *calpmaxheight(Stu *ps,int n);
Stu *calpmaxheight(Stu *ps,int n)
{
//1.定义一个结构体指针,用它来身高最高的人的首地址
Stu *pmax=NULL;
//2.假设第一个为最高,将第一个人的首地址赋值给了pmax
pmax=ps;
int i=0;
for(i=1;i<n;i++)
{
ps++; //移动指针
//pmax指向的值和后面的每个元素的身高进行比较
if(pmax->height<ps->height) //若小于
{
pmax=ps; //将其地址赋值给pmax
}
}
return pmax;
}
编写一子函数,按照身高进行排序
//函数功能:身高排序
//参数1:空间的首地址: stu * 参数2:元素的个数
//返回值:void
void sortHeight(Stu * ps,int n);
void sortHeight(Stu * ps,int n)
{
int i,j;
//冒泡排序
for(i=0;i<n-1;i++)
{
for(j=0;j<n-1-i;j++)
{
if((ps+j)->height<(ps+j+1)->height) //交换的是这个结构体
{
Stu temp; //定义一个结构体变量接着
temp=*(ps+j);
*(ps+j)=*(ps+j+1);
*(ps+j+1)=temp;
}
}
}
}
//函数功能:身高排序
//参数1:空间的首地址: stu * 参数2:元素的个数
//返回值:void
void sortHeight(Stu * ps,int n);
void sortHeight(Stu * ps,int n)
{
int i,j;
//冒泡排序
Stu * ptemp=ps; //定义一个结构体指针初始化为ps
for(i=0;i<n-1;i++)
{
ps=ptemp; //ps重置为第一个元素的首地址
for(j=0;j<n-1-i;j++)
{
if(ps->height>(ps+1)->height) //交换的是这个结构体
{
Stu temp; //定义一个结构体变量接着
temp=*ps;
*ps=*(ps+1);
*(ps+1)=temp;
}
ps++;
}
}
}
自定义头文件
1.自定义头文件的要求.h
2.如何引入自定义头文件
include "stu.h"
3.“” 和<>的区别
“”和<>的区别
“”: 编译器从用户的工作路径开始搜索头文件
<>: 编译器从标准库路径开始搜索头文件
4.条件编译
1.作用:避免头文件被重复引入
2.语法
//stu.c
#ifndef _STU_H
#define _STU_H
//<1>.引入库头文件
//<2>.宏定义
//<3>.结构体类型的定义
//<4>.枚举类型的定义
//<5>.函数声明
//<1>.引入库头文件
#include <stdlib.h>
//<2>.宏定义
#define N 20
#define M 3
#define SIZE 5
//<3>.结构体类型的定义
//该句话是前两句话的简化
typedef struct student
{
char name[N];
int height;
float scores[M];
}Stu;
//<4>.枚举类型的定义
//<5>.函数声明
void output(Stu * ps,int n);
void menu(void);
void input(Stu * ps,int n);
Stu *calpmaxheight(Stu *ps,int n);
void sortHeight(Stu * ps,int n);
#endif
gcc工作原理
1.分阶段执行
1.预处理
gcc -E main.c -o main.i
2.编译
gcc -S main.i -o main.s
3.汇编
gcc -c main.s -o main.o
4.链接
在连接阶段将输入的机器代码文件*.o(与其它的机器代码文件和库文件)汇集成一个可执行的二进制代 码文件
Make工程管理器 (多文件编译)
1.make工作原理
2.Makefile
3.Makefile中假目标
1.执行假目标
2.假目标出现的问题
3.如何解决和假目标同名的问题
4.Makefile变量
1.自动变量
$@ 目标文件
$^ 所有的依赖文件
$< 第一个依赖文件
2.预定义变量
Makefile预定义变量包含了常见编译器,汇编器的名称及其编译选项
CC C编译器的名称,默认为cc
CFLAGS C编译的选项,无默认值
RM 文件删除程序的名称,默认值为rm -f
3.自定义变量
5.Makefile中变量的展开方式
递归展示方式
简单展开方式
函数指针
1.如何定义函数指针
//定义一个指向int的指针
int * pi; (int)
//定义一个指向int的指針的指針
int ** ppi; (int *)
//定义一个指向char的指针
char * pc; (char)
//定义一个指向数组的指针,该数组是一个长度为5的int的数组
int (*parr) [5]; (int [5]) int arr[5]
int (*parr) [5]
//定义一个指向结构体的指针,该结构体的类型(Stu)
Stu * ps; (Stu)
//定义一个指向函数的指针,该函数参数为两个int,返回值為一个int的函数
函数的类型: 返回值类型 (参数列表)
int (int,int) int add(int,int)
int (*pfun) (int,int)
#include <stdio.h>
int add(int num1,int num2)
{
return num1+num2;
}
int sub(int num1,int num2)
{
return num1-num2;
}
int mul(int num1,int num2)
{
return num1*num2;
}
int div(int num1,int num2)
{
return num1/num2;
}
int main(void)
{
//定义一个函数的指针 int (int,int)
int (* pfun) (int,int)=NULL;
//pfun=函数的首地址
pfun=&add; //add<===>*pfun
printf("%d\n",add(45,67));
printf("%d\n",(*pfun)(45,67));
return 0;
}
#include <stdio.h>
int add(int num1,int num2)
{
return num1+num2;
}
int sub(int num1,int num2)
{
return num1-num2;
}
int mul(int num1,int num2)
{
return num1*num2;
}
int div(int num1,int num2)
{
return num1/num2;
}
int main(void)
{
//定义一个函数的指针 int (int,int)
int (* pfun) (int,int)=NULL;
//pfun=函数的首地址
pfun=&add; //add<===>*pfun
//函数名也可以代替函数的首地址
pfun=add;
printf("%d\n",add(45,67));
printf("%d\n",(*pfun)(45,67));
//函数名也可以代替函数的首地址,
printf("%d\n",pfun(45,67));
return 0;
}
定义一个长度为4的数组,该数组中的每个元素是个函数的指针
#include <stdio.h>
int add(int num1,int num2)
{
return num1+num2;
}
int sub(int num1,int num2)
{
return num1-num2;
}
int mul(int num1,int num2)
{
return num1*num2;
}
int div(int num1,int num2)
{
return num1/num2;
}
int main(void)
{
/*int a;
int arr[4];
int * par;
int * parr[4]*/
//int brr[3][4]; 定义一个长度为3的数组,该数组中的每个元素int [4]
//定义一个函数的指针 int (int,int)
int (* pfun) (int,int)=NULL; //----> int (*)(int,int)
//定义一个长度为4的数组,该数组中的每个元素是个函数的指针
int ( *pfunArr[4] ) (int,int )={add,sub,mul,div};
//pfunArr[0]-->add pfunArr[1]->sub pfunArr[2]-->mul pfunArr[3]--div
int i=0;
for(i=0;i<4;i++)
{
printf("%d ",pfunArr[i](12,4)); //函数指针数组
}
printf("\n");
return 0;
}
函数参数可以是函数指针
#include <stdio.h>
int add(int num1,int num2)
{
return num1+num2;
}
int sub(int num1,int num2)
{
return num1-num2;
}
int mul(int num1,int num2)
{
return num1*num2;
}
int div(int num1,int num2)
{
return num1/num2;
}
//定义一个函数
//参数1:一个函数指针 函数类型(int (int ,int )) 参数2 int ,参数3 int
//返回值:int
int pfunaction(int (*pfun)(int,int),int num1,int num2);
int pfunaction(int (*pfun)(int,int),int num1,int num2)
{
return pfun(num1,num2);
}
int main(void)
{
printf("add:%d\n",pfunaction(add,12,3)); //对后面两个数进行求和
printf("sub:%d\n",pfunaction(sub,12,3)); //对后面两个数进行求差
printf("mul:%d\n",pfunaction(mul,12,3)); //对后面两个数进行求积
printf("div:%d\n",pfunaction(div,12,3)); //对后面两个数进行求商
return 0;
}
函数指针也可以取别名 (typedef )
int (*pfun) (int,int);
int ( *pfunArr[4] ) (int,int )={add,sub,mul,div};
int pfunaction(int (*pfun)(int,int),int num1,int num2)
{
return pfun(num1,num2);
}
//给函数指针取了别名
typedef int (*PFUN) (int,int ); //给函数指针取了别名 int (*) (int,int) ---->PFUN
类型名
int (*pfun) (int,int);
PFUN pfun; 类型名 指针变量名;
int ( *pfunArr[4] ) (int,int )={add,sub,mul,div};
PFUN pfunArr[4]={add,sub,mul,div};
int pfunaction(int (*pfun)(int,int),int num1,int num2)
{
return pfun(num1,num2);
}
int pfunaction(PFUN pfun,int num1,int num2)
{
return pfun(num1,num2);
}
存储类型
1.register 寄存器
2.auto (默认)
存储类型 类型名 变量名
3.extern 外部的
1.变量
局部变量 :定义在函数体内部的变量,称为叫局部变量
作用域:自定义开始到最近}结束,函数作用域 ,块作用域
生命周期:函数调用分配,函数结束释放
全局变量:定义在函数体外部的变量,称为叫全局变量
作用域:自定义开始到文件 文件作用域
//show1.c
#include <stdio.h>
int a=10; //全局变量
void show1(void)
{
a+=10;
printf("show1 a=%d\n",a);
2.extern修饰全局变量
//show2.c
#include <stdio.h>
extern int a; //使用外部变量a
void show2(void)
{
a+=20;
printf("show2 a=%d\n",a);
}
3.extern修饰函数
#include <stdio.h>
//extern修饰函数:使用外部的函数
extern void show1(void);
extern void show2(void);
int main(void)
{
show1();
show2();
}
4.static 静态的
1.static修饰全局变量 (隐藏)
2.static修饰函数 (隐藏)
3.static局部变量:延长变量的生命周期
共用体
大小端
//测试计算机是大端序还是小端序
#include <stdio.h>
union un
{
int a;
char c;
};
int main(void)
{
union un u1;
u1.a=0x12345678;
if(u1.c==0x78)
{
printf("小端序\n");
}else
{
printf("大端序\n");
}
return 0;
}
枚举:(语义化)定义常量的一种方式
//1.定义一个枚举的数据类型
enum timeDate
{
MONDAY=1,TUESDAY,WEDSDAY,THURSDAY,FRIDAY //默认是从开始的整数
};
//定义一个枚举数据类型,该数据类型的名字叫enum timeDate
//2.定义枚举的变量
enum timeDate d1;
d1的值可以是MONDAY,TUESDAY,WEDSDAY,THURSDAY,FRIDAY 任意一个
#include <stdio.h>
//定义一个枚举数据类型
enum timeDate
{
MONDAY=1,TUESDAY,WEDSDAY,THURSDAY,FRIDAY //默认从0开始,后面依次加1
};
int main(void)
{
//定义一个枚举数据变量
int date=0;
enum timeDate d1;
while(1){
printf("请输入时间\n");
scanf("%d",&date);
d1=date;
switch(d1)
{
case MONDAY:
printf("我是周一\n");
break;
case TUESDAY:
printf("我是周二\n");
break;
case WEDSDAY:
printf("我是周三\n");
break;
case THURSDAY:
printf("我是周四\n");
break;
case FRIDAY:
printf("我是周五\n");
break;
default:
printf("我是周末\n");
}
}
}
字节对齐:分配空间时候一次性分配多少个字节
1.基本类型:自然对齐方式
2.结构体的对齐方式:成员当中最大的那个
位域(位段)
#include <stdio.h>
#define N 20
typedef struct mydate
{
unsigned int year:11; //int的11位:
unsigned int month:4;
unsigned int day:5;
}Date; //缺点:不能通过scanf()输入
typedef struct student
{
char name[N];
int height;
Date birday;
}Stu;
int main(void)
{
Stu s1={"zhangsan",183,{2000,9,9}};
printf("%10s %5d ",s1.name,s1.height);
printf("%04d/%02d/%02d\n",s1.birday.year,s1.birday.month,s1.birday.day);
printf("sizeof(Date)===%ld\n",sizeof(Date));
return 0;
}
递归
一个数的阶乘
#include <stdio.h>
int jiecheng(int n)
{
if(n==1)
return 1;
else
return n*jiecheng(n-1);
}
int main(void)
{
int n=0;
printf("请计算某个数的阶乘\n");
scanf("%d",&n);
printf("%d\n",jiecheng(n));
}
斐波那契数列