color/0=黑色8=灰色1=蓝色9=淡蓝色2=绿色A=淡绿色3=浅绿色B=淡浅绿色4=红色C=淡红色5=紫色D=淡紫色6=黄色E=淡黄色7=白色F=亮白色system("color40");//通过system改变cmd的颜色system("cls");//清屏
快捷键:复制ctrl+c粘贴ctrl+v怎么打开CMDwindows键+R打开运行界面然后键入cmd回车怎么样打开文件windows+E可以直接打开文件管理器怎么回到桌面windows+D回到桌面
*怎么样生成一个别人能用的EXE:第一步debug改成release第二步在项目属性C/C++代码生成运行库改成MT这个EXE发给别人就可以直接在对方的电脑上运行
intmain(){/*下面代码直接用可能会关机请看注释。*/system("shutdown-sat22:00");//如果加上at那么会定时关机
system("shutdown/s");//一分钟之内关机system("shutdown-a");//取消关机计划
预科班dany03:基本数据类型
一、基本数据类型简介分为三类基本数据类型四种基本数据类型整数小数字母整型浮点型字符型intfloatdoublechar
int对应整型win32当前编译环境下占内存大小4字节正整数负整数和0数据范围-2^31-2^31-1一字节=8位4字节=32位通过第一位的符号位(0表示正数1表示负数)剩下31位用来表示数据大小00000000000000000000000000000000=0float单精度的浮点数(小数)(实型)4字节double双精度的浮点数8字节float数据范围-1.17*10^38-3.4*10^38double数据范围-2.22*e^308-1.8*e^308
e表示10**精度描述的是数据存放在内存中的精度而不是输出的精度**double和float输出都是6位float的精度6-7位PI=3.1415926535用float3.1415923.141593double的精度是16-17位
char字符型表示符号和字母1字节(-128-127)实际上在计算机里面是ASCII码表char类型实际上是整型ASCII码表上字母、符号和数字一一对应字符'0'对应的是48字母A对应的是65字母a对应的是97大写字母和小写字母差32数字0+48=字符'0'
计算机里面只有0和1表示别的东西只能通过数字二进制
二、变量什么是变量inta;实际上是在内存中开辟一段长度为4字节的空间用来存放a在内存中开辟一个存储空间用来存放不确定的数怎么定义变量数据类型变量名intfloatdoublecharinta;charc;floatf;doubled;
三、什么是常量整型常量一个或多个数字组成110111111实型常量十进制的小数形式1.23***.23=0.23***指数形式e或者E和阶码组成阶码只能是整数e或者E前面必须有数字后面必须是整数符号常量通过一个标识符表示一个常量称之为符号常量结合预处理#defineSEVEN7全大写颜色不一样一般就是系统预留的符号常量
初始化如果一个变量定义之后没有初始化然后使用了之后最好的情况是报错最坏的情况不报错但是程序运行出问题
1.通过常量来初始化2.通过相同类型的变量来初始化
四、变量命名规范标识符的规范标识符其实就是变量名1.只能由字母数字下划线$四种组成26*20-9_$摁住shift-删除键左边的左边那颗键输入法英文状态下_________________---------________-
2.必须用字母或者下划线开头2a$aa2_1_2_$aa
3.不能和系统预留的关键字一样intint;floatint;
五、变量命名的方法1.驼峰命名法除第一个单词外所有首字母大写iPhoneiPadiPadMini2.大驼峰命名法所有单词首字母大写SummerSeven3.匈牙利命名法在变量前加上一个前缀用来表示类型1.提示变量的类型2.增强代码的可读性intsummerSeven;inti_summerSeven;intm_Member;intn_number;
#include
intmain(){printf("float的取值范围:%e---%e\n",FLT_MIN,FLT_MAX);//floatprintf("double的取值范围:%e---%e\n",DBL_MIN,DBL_MAX);//doublereturn0;}
预科班day04:二进制
整数的十进制和二进制怎么转换正数原码反码补码都一样十进制——————>二进制碾转相除倒序排列十进制的40二进制101000十进制的55二进制110111
二进制——————>十进制位权相乘逐位相加101000---->4040=4*10^1+0*10^0101000=1*2^5+0*2^4+1*2^3+0*2^2+0*2^1+0*2^0int32位char8位存储过程中会引入一个符号位最高位(第一位)作为符号位符号位用来描述正负如果符号位为0为正数为1为负数
01111111:1+2+4+8+16+32+64=127
负数反码是人为引入为了计算的补码也叫取反加一码十进制——————>二进制1.得到相应的正数的二进制然后把符号位置为1原码2.把这个八位二进制除符号位外全部变为取反1变成00变成1反码3.末位+110000001补码-401.得到400010100010101000-40的原码2.11010111-40的反码3.11010111+111011000-40的补码***-128计算机特殊规定10000000******补码的作用在计算机计算的过程中只有补码***计算机底层只有加法器四则运算都没有只有加法减法的实质是加法40-40=40+(-40)=00101000+11011000=00010100011011000100000000=0浮点数二进制float32位第一位符号位中间八位无符号指数位23位尾数位指数位用来指示次幂用来描述小数点移动的位数用这个得到的指数+127得到浮点数的指数
100.23====科学计数法1.0023*10^20.00123=====1.23*10^-3100.23-0.001231.0023*10^2-1.23*10^-3
3.23
1.先把小数部分和整数部分分开11+0.23分别计算两边的二进制纯小数的二进制怎么计算乘二取整数部分0就是01就是1减掉整数部分乘尽就在后面添0补齐32位否则就继续算1.50.5*2=100000000
取的位数就是尾数0.230.460.921.841.681.360.72001110然后重新把整数部分和小数部分整合保留小数点11.001110---1.100111010.01111.001110.010110002.得到指数11.001110+1让小数点前面只有一个1可以不存这个1可以在小数点后面多存一位提高了精度把小数点移动让小数点前有且仅有一个1移动的位数就是实际的指数(往左为正往右为负)然后+127得到计算机的指数11.0001110---1.10001110小数点左移一位实际的指数是1指数是128---转换成二进制100000003.尾数小数点后面的就是尾数尾数是1001110
0100000001001110………………补满32位
00000000~~~~111111110~255-1-->11--->0
8.76010000010000110000101……1.8+0.76=10000.761.521.040.080.160.320.641.280.561.121100001011000.110000101……2.1.000110000101……小数点左移了三位实际的指数是3+127计算计算机的指数130100000103.尾数000110000101……010000010000110000101……
-8.76110000010000110000101……
预科班day05:运算符
1.运算符操作数在运算符左边的操作数称之为左操作数(左值)在运算符右边的操作数称之为右操作数(右值)一个运算符单目运算符双目运算符三目运算符单目运算符表示只有一个操作数可以在左边也可以在右边双目运算符表示有两个操作数一个左边一个右边三目运算符表示有三个操作数算术运算符+-+-*/%++--正表示是正数-1负表示是负数-1+3负1+3%取余左操作数对右操作数做除法保留余数5%3=22%7=2如果能除就除然后保留余数2/7=0----2如果左操作数没有右操作数大那么结果就是左操作数(-5)%3=-2(-5)%3(-)5%3=-25%(-3)=25/(-3)----3*-1=3+2=55=(-1)*(-3)+2(-5)%(-3)=-2***%操作符要求左右操作数都是整型***5%2.0这个表达式不符合规则5/((int)2.0)++自增(--自减)分为前置自增和后置自增让操作数+1++a先自增再赋值(执行操作)a++先赋值再自增
位运算符都要转换成二进制来做要从末位开始对齐前面没有的就补0简单的记忆一下2的各个次幂的值^|&<<>>按位异或^英文状态下的shift+6双目运算符左操作数和右操作数不同时返回1否则返回0010^1=11^0=10^0=01^1=08^5=1000^101=110116^15=10000^1111=11111=3115^15=0位或运算|双目运算符左操作数和右操作数都为0返回0否则返回10|0=00|1=11|0=11|1=18|5=110116|15=11111
位与运算&双目运算符左操作数和右操作数都为1返回1否则返回01&1=11&0=00&1=00&0=08&5=016&15=10000&1111=0
位左移<
关系运算符计算机里面判断的时候非0即1><<=>=!===都是双目运算符左操作数的关系和右操作数的关系满足关系运算符返回1否则返回01>0=11>2=0!=不等于a!=b如果a不等于b返回1否则返回0==等于a==b如果a等于b返回1否则返回0满足条件返回1不满足返回0逻辑运算符&&||!逻辑与是双目运算符如果左操作数和右操作数都为1返回1否则返回0a&&ba=1b=1a&&b=1逻辑或是双目运算符如果左操作数和右操作数都为0才返回0否则返回1a||ba=0b=0a||b=0a>b||a>=^=&=|=a=5;右结合性表达式从右往左计算a+=b;---a=a+b;a<<=2;a=5;a=5<<2;三目运算符非0即10为假1为真?:表达式1?表达式2:表达式3如果表达式1为真执行表达式2如果表达式1为假执行表达式30?2:3成员结构体成员.->数组成员[]提升优先级的()2.优先级+-*/本身存在优先级通常的:单目:+-++--!~正负双目:+-*/%>><<^&|&&||加减三目::单目运算符高于双目运算符高于三目运算符在双目运算符里面算术最高关系逻辑
3.举例子a+b传入计算机一系列的指令包含数据操作符
预科班day06:进制转换
1.八进制和十六进制
八进制01234567用数字前的O来表示八进制的标志
十进制相互转换
从十进制得到八进制:碾转相除倒序排列5062从八进制得到十进制:位权相乘逐位相加0626*8^1+2*8^0=50
二进制相互转换
从二进制得到八进制:把三位整合在一起表示一位八进制八进制最大值是7用几位二进制可以表示711110110111=26710000001=201
从八进制得到二进制:把一位换算成三位二进制255=010101101111=001001001
十六进制在数字前用ox/OX表示十六进制0123456789ABCDEF大小写都可以16---1015---ff+1---10十进制相互转换从十进制得到十六进制:碾转相除倒序排列(余数)5032从十六进制得到十进制:位权相乘逐位相加ff15*16^1+15*16^0=25510---1615---16+5=21
怎么打开计算器windows+r打开运行窗口输入calc打开计算器
二进制相互转换从二进制得到十六进制:把四位二进制整合成一位十六进制十六进制最大值是15二进制来表示1511111000111111=23f23f-1=23e23f-10=22f23f-A=235abc-d=aafabc-daaf
从十六进制得到二进制:把一位十六进制转换成四位二进制在十六进制转换成二进制的过程中可以直接一位一位写过去
adc=101011011100你们要看题目丫
2.基本输出格式
printf("要输出的东西");printf("helloworld!");在printf的一对双引号内直接打要输出的东西
printf("",);printf("%d",10);%d叫做占位符,后面的是变量如果前面没有占位符逗号后面的变量没有意义
占位符intcharfloatdoubleunsigned---关键字用来描述变量表示无符号的%d%c%f%lf%u控制输出无符号的数字%f%lf输出的小数点后都只有6位
unsigned所有位都用来表示数据没有符号位0~2^80~2^32
3.控制输出1.占位符2.转义字符有一些符号被系统占用作为转义字符如果想输出这些符号需要打两个%\
特殊一些组合\n表示换行\t表示制表符键盘上的TABC语言里面表示四个空格\b表示退位符键盘上的删除键\a表示响铃\0表示字符串的结尾如果想输出符号配合\无刻上面没有字
3.控制输出格式
%3d%-3d%.3f{inta=10;printf("%d\n",a);//20打印出10进制printf("%x\n",a);//14打印出十六进制printf("%o\n",a);//24打印出八进制
return0;}
预科班day07:复习
1.一个数转换为二进制:intmain(){inta;intn=10;while(n--){scanf("%d",&a);printf("%d\n",!(a&(a-1)));}return0;}
2.判断一个数是否为2的幂或者被2整除:intmain(){inta;intn=20;while(n--){scanf("%d",&a);printf("%d\n",((a|(a-1))==(a+a-1)));}
return0;}*/
1.占位符char%c打印单个字符单引号用来描述一个字符单引号中如果有多个字符会报错int%dfloat%fdouble%lf八进制%o十六进制%x无符号%uunsignedintchar字符串%s打印一串字符双引号用来描述字符串输出地址%p输出地址的十六进制%e科学计数法%g在%e和%p之间取一个较短的
定义数据的时候每次分配的内存是随机的定义变量的时候实际上是去内存中找一个空着的空间然后放进去
\n转义字符表示换行
2.输入时候一些不同于输出1.scanf("占位符",&变量名);把一个占位符格式的数据放到变量名内在输入的时候必须要&只能对内存操作把数据放到对应的内存里printf("%d",a);2.在scanf里面最后一个不能有\n如果在scanf里面有\n需要键入\n在输入多个数据的时候中间可以有\n但是不建议写最后一个数据不能有\n如果有必须要输入一个一样的\n3.输入多个数据的时候两个占位符之间scanf里面写了什么就必须按照格式输入
4.scanf不会读入空格如果多个数据两个占位符之间什么都没有直接用空格隔开
5.scanf其实是从终端获取数据从键盘键入数据会先进入键盘缓冲区如果想在输入别的东西之后继续输入字符在输入之前写一行清空缓冲的代码fflush(stdin);//清空缓冲区
6.%*4d表示不要几位scanf("%3d%*4d%4d",&a,&b);printf("%d****%d\n",a,b);输入多个%c是不需要用空格隔开不然某个%c会读到空格
3.scanfscanf_s安全生命周期
scanf_s("%s",str2,5);//第三个参数描述的是输入多少个字符注意\0
fflush(stdin);//清空缓冲区
输出转换为密码形式:scanf("%3d%*4d%4d",&a,&b);printf("%d****%d\n",a,b);
预科班day08:推箱子项目
#include
//放音乐需要下面两个头文件#include
/*0空地1墙壁3目的地4箱子5人物7箱子在目的地8人在目的*/
/*
///路径有两种描述方式/\\
1.二维数组用来描述推箱子的地图
2.函数把一些代码块封装起来可以反复的调用1+2+3+4+5intsum(inta,intb){intc=a+b;}
3.循环反复的做同一件事情while(n--){printf("%d",n);}4.分支判断是否满足条件
*/
//intch;//*//键码在键盘上分为两种//第一种是字符ASCII码表上可以找到对应关系的//第二种是功能键上下左右F1F2//通过两个值第一个是224第二个是真实的ASCII码值
//*///while(1)//{//ch=getch();//printf("%d\n",ch);//printf("---\n");//}
//地图下标是0开始最大到n-1(8-1=7)intMap[8][8]={0,0,0,1,1,1,0,0,0,0,0,1,3,1,0,0,1,1,1,1,0,1,0,0,1,3,4,0,4,1,1,1,1,1,1,5,4,0,3,1,0,0,1,4,1,1,1,1,0,0,1,3,1,0,0,0,0,0,1,1,1,0,0,0};
voidGame_InitMap();//加载地图voidGame_Paint();//画地图voidGame_Play();//操作intGame_Judgment();//判断游戏结束
IMAGEBackImage,WallImage;//背景墙IMAGEBox;//箱子IMAGETag;//目的地IMAGEBoom;//箱子推到目的地IMAGEPer;//人IMAGEEND;//奖励
//载入图片voidGame_InitMap(){//背景墙人空地目的地人在目的地箱子箱子在目的地//背景loadimage(&BackImage,"res/Background.jpg",550,550);//墙loadimage(&WallImage,"res/Wall.jpg",69,69);//箱子loadimage(&Box,"res/Box.jpg",69,69);//目的地loadimage(&Boom,"res/Boom.jpg",69,69);//箱子在目的地上loadimage(&Tag,"res/Tag.jpg",69,69);//人物loadimage(&Per,"res/xx.jpg",69,69);//最后的图片loadimage(&END,"res/XiaQi.jpg",550,550);
}
//贴图voidGame_Paint(){inti,j;for(i=0;i<8;++i)//i从0开始进入循环判断i<8是否成立如果满足进入循环否则跳出//执行循环语句每次执行完之后让i++//判断i是否仍然满足i<8如果满足继续执行否则跳出循环{for(j=0;j<8;++j){/*0空地1墙壁3目的地4箱子5人物7箱子在目的地8人在目的*///通过分支语句去判断当前位置是什么然后贴相应的图片switch(Map[i][j])//访问二维数组的方式通过两个下标{case0://如果是空地break;case1://如果是墙壁putimage(69*j,69*i,&WallImage);break;case3://如果是目的地putimage(69*j,69*i,&Tag);break;case4://箱子putimage(69*j,69*i,&Box);break;case5://人物putimage(69*j,69*i,&Per);break;case7://箱子在目的地上putimage(69*j,69*i,&Boom);break;case8://箱子在目的地上putimage(69*j,69*i,&Per);break;}}}
voidGame_Play(){charch;intx,y;Game_InitMap();while(true){BeginBatchDraw();//开始批量绘图cleardevice();putimage(0,0,&BackImage);//背景if(!Game_Judgment())//判断游戏是否结束{Game_Paint();FlushBatchDraw();//完成未完成的绘制任务
//弹出一个窗口然后执行相应的操作MessageBox(GetHWnd(),"闯关成功\n","闯关提示",MB_OK);putimage(0,0,&END);FlushBatchDraw();Sleep(10000);//停留10000ms10s
closegraph();exit(0);//退出程序}Game_Paint();EndBatchDraw();
//做人物操作
//首先要找到人物for(x=0;x<8;++x){for(y=0;y<8;++y){if(Map[x][y]==5||Map[x][y]==8){break;//提前跳出当前循环}}if(Map[x][y]==5||Map[x][y]==8){break;}}//此时人就在Map[x][y]ch=getch();//获得键盘消息
switch(ch){case'w':case72://向上if(Map[x-1][y]==0||Map[x-1][y]==3){Map[x][y]-=5;Map[x-1][y]+=5;}elseif(Map[x-1][y]==4||Map[x-1][y]==7){if(Map[x-2][y]==0||Map[x-2][y]==3){Map[x-2][y]+=4;Map[x-1][y]+=1;Map[x][y]-=5;}}break;case75://向左if(Map[x][y-1]==0||Map[x][y-1]==3){Map[x][y]-=5;Map[x][y-1]+=5;}elseif(Map[x][y-1]==4||Map[x][y-1]==7){if(Map[x][y-2]==0||Map[x][y-2]==3){Map[x][y-2]+=4;Map[x][y-1]+=1;Map[x][y]-=5;}}break;case80://往下if(Map[x+1][y]==0||Map[x+1][y]==3){Map[x][y]-=5;Map[x+1][y]+=5;}elseif(Map[x+1][y]==4||Map[x+1][y]==7){if(Map[x+2][y]==0||Map[x+2][y]==3){Map[x+2][y]+=4;Map[x+1][y]+=1;Map[x][y]-=5;}}break;case77://向右if(Map[x][y+1]==0||Map[x][y+1]==3){Map[x][y]-=5;Map[x][y+1]+=5;}elseif(Map[x][y+1]==4||Map[x][y+1]==7){if(Map[x][y+2]==0||Map[x][y+2]==3){Map[x][y+2]+=4;Map[x][y+1]+=1;Map[x][y]-=5;}}break;}}}
intGame_Judgment(){inti,j;for(i=0;i<8;++i){for(j=0;j<8;++j){if(Map[i][j]==4)//判断有没有箱子在空地上{return1;}}}return0;}
intmain(){initgraph(550,550);//创建窗口/*//getch();//获得控制台的输入getchar获得一个字符返回音乐wav导入资源文件添加头文件如果想要导入资源文件必须是用wav格式只能用playsound第一种不导入资源文件PlaySound("res/BGM.wav",NULL,SND_ASYNC);//第一个参数表示路径第二个参数缺省第三个参数表示播放的方法//SND_ASYNC表示异步播放第二种导入资源文件PlaySound((LPCTSTR)IDR_WAVE1,GetModuleHandle(NULL),SND_RESOURCE|SND_ASYNC);*/PlaySound((LPCTSTR)IDR_WAVE1,GetModuleHandle(NULL),SND_RESOURCE|SND_ASYNC);
Game_Play();
正课:
一:进制转换
计算机在内部只有补码所有的原码反码都是不存在的计算机只有二进制通过最高位来表示符号位正数的原码反码补码都是本身1.原码就是数字本身用0表示正数用1表示负数011110000002.反码针对负数除符号位外逐位取反10001111-15的原码11110000-15的反码正数的反码就是本身3.补码通过反码+111110001-15的补码0000111115的补码100000000=0
正数三码合一负数取反+1得到补码
二进制八进制十六进制*****二进制:计算机只有二进制正数:从十进制得到二进制:碾转相除余数倒序排列23的二进制00010111二进制得到十进制:每一位乘以当前的权值求和123=1*10^2+2*10^1+3*10^0从末尾开始用第n位的数值乘以2的n-1次方000101111*2^0+1*2^1+1*2^2+0*2^3+1*2^4
负数:1.以正数为模型符号位置为12.除符号位外逐位取反3.+1-230001011123的原码10010111-23的原码11101000-23的反码11101001-23的补码
*****浮点数:3.14float32位double1.分成整数部分和小数部分分别转换成二进制2.把整数部分的二进制和小数的连在一起保留小数点3.移动小数点让小数点前只有一个1记录小数点移动的位数nn+127的操作得到一个无符号的指数无符号第一位不表示正负表示大小0~2554.保留余下的小数点后的位数标记为尾数1位符号位8位指数位23位尾数位
3.143=000000110.14小数部分反复乘2取整数部分顺序排列00100011一般会乘不尽要补满23位尾数一般是后面添0
32位111.0010001左移两位+20.00011000右移四位-4-4+127=12301111011左移标记为正数右移标记为负数11.001000111.100100011左移一位然后舍去第一位1指数+1+127=128转换成二进制指数10000000
100100011剩下的尾数符号位指数位尾数位补的001000000010010001100000000000000-3.14在3.14的基础上符号位变为111000000010010001100000000000000
八进制和十六进制n进制以n为进位标志0~70~151111111第一个八进制和十六进制和二进制的相互转换第二个八进制和十六进制和十进制的相互转换八进制用三位二进制来描述在八进制数字的开头0只需要一位八进制变成三位二进制就可以了二进制转换成八进制三位二进制组合在一起00010111027---2*8^1+7*8^0=23000101110X17---1*16^1+7*16^0=23如果不够往前面添0011000111027---0101110X17---00010111
****所有的C语句都以;(英文状态下的分号)结尾输出:printf("输出的内容");
printf("格式控制",输出列表);格式控制---占位符%d整型%c字符型%ffloat%lfdouble%o八进制%x十六进制%u无符号%p输出地址得到十六进制要配合&使用%s字符串%e科学计数法%g%e和%lf之间最短的一个
\转义字符\a响铃\b退位删除键\n换行\t表示制表符TAB四个空格
下面这串代码很危险不要碰可以让朋友玩while(1){printf("HELLO\a");}
*****标识符:给变量起名字我们存放变量是需要用标识符x+y=101.只能由下划线_数字字母(区分大小写)$四种组成2.必须以下划线或者字母开头3.不能和系统保留的一些关键字冲突32个关键字看一下分别是哪几个_summerseven0uguangSummer7intfloat
标识符的长度c89是31位c99是63位
一些全大写的一般是系统预留的宏
floatc=3.14f;//如果没有f自动转换成double类型//float4字节double8字节//计算机的隐式转换printf("%o\n",c);//直接输出printf("%.3f\n",c);//控制输出三位小数printf("%10.3f\n",c);//右对齐printf("%-10.3f***\n",c);//左对齐
二:基本数据类型
变量的作用域:局部变量的作用范围是{}全局变量的作用范围是整个文件
2.基本数据类型intfloatdoublechar整型单精度浮点型双精度浮点型字符型数字一共就只有十个
1字节=8位1kb=2^10b1mb=2^10kb32G=2^102^102^1030G=100010001000整型家族int有符号整型占四个字节32位数据范围:-2^31~2^31-1
short有符号短整型占两个字节16位-2^15~2^15-1
unsignedint无符号的整型占四个字节32位0~2^32-1longlong长整型占8个字节64位-2^63~2^63-1在不同的编译器下可能是有区别的long和int是一样的long也是四字节32位有些编译器下long也是8字节
11111111111111111111111111111111
浮点型小数点后取值范围(负-正)float单精度46~7位3.4*10^38double双精度816~17位1.7*10^308float只有32位23位尾数91001999999double64位52位尾数位floatdouble取舍对精度要求特别高数据很大的时候0.000001运算速度要求高的时候精度不是很高
char字符类型ASCII码表:让计算机识别字符通过数值的形式计算机里面只有二进制描述除数字之外的东西char字符---数值一一对应-128~127a97A65'0'48实际上char也是整型占一个字节-128~127字符常量'a''A'单引号字符串常量"Hello"双引号在单引号内可以存放最多四个字母不论大小写如果向打印对应的符号有两种方法直接打印%c对应的字符打印%c对应的ASCII码值
sizeof()运算符返回()内的数据所占内存的大小()内可以直接放数据类型名可以放变量名都会返回相应的大小
错误是不能通过编译的警告是可以通过编译在特殊的情况下是会出错的
3.输入输出
4.标识符字母数字下划线$四种$$$$$不能和关键字冲突必须以下划线或者字母开头
命名方法驼峰除第一个单词外所有首字母大写iPhoneiPadMini大驼峰SummerSevenOuGuang匈牙利加前缀来描述变量的属性inti_summercharc_Summer
三:运算符
根据运算符的种类:算术运算符位运算符关系运算符赋值运算符逻辑运算符条件运算符
操作数:在运算符的两侧可能会有数值左侧左操作数或者左值右侧右操作数或者右值1+2+运算符1为左操作数2为右操作数
根据运算符的操作数个数单目运算符一个操作数双目运算符两个操作数三目运算符有且只有一个:ab:c
算术运算符+-+-*/%++--正号负号自增自减%取余左操作数对右操作数取余做除法保留余数5%2=1-5%2=-15%(-2)=1-7%2=-1
++自增自己增加1前置自增++a自增符号在操作数前面先执行自增再赋值运算后置自增a++自增符号在操作数后面先赋值运算再执行自增
--自减自己减少1
位运算符<<>>|&^~左移右移或与异或取反a<
a>>b把左操作数转换成二进制右移右操作数位数算术右移计算机做的是算术右移如果为负数符号位1在a前面补b个符号位会保留正负逻辑右移不管正负补0
在计算机中非0即1按位或|左右操作数只有同时为0才返回0否则为1a|b=0|0=00|1=11|0=11|1=1左右操作数各自转换成二进制然后做或运算逐位相或按照规则该是1就是1是0就是0-1|-110000001111111101111111111111111|11111111=11111111=-13|7=00000011|00000111=00000111=7如果一个负数和一个整数做或运算结果是否一定为负
按位与&左右操作数只有同为1才返回1否则返回00&0=00&1=01&0=01&1=1左右操作数各自转换成二进制然后做与运算逐位相与按照规则该是1就是1是0就是03&7=00000011&00000111=00000011=3-1&7=11111111&00000111=00000111=7如果int就是32位longlong64位
按位异或^只有左右操作数不同才返回1否则返回01^0=10^1=10^0=01^1=0左右操作数各自转换成二进制然后做异或运算逐位异或按照规则该是1就是1是0就是03^7=00000011^00000111=00000100=4-1^7=11111111^00000111=11111000=-81111011110001000
取反~全部取反转换成二进制所有位0变11变0~0=~00000000=11111111=-1
关系运算符><<=>===!=><<=>=if(3 ==判断如果左边等于右边返回1否则返回03==3----1if(*p==NULL)判断赋值是否成立if(*p=='\0')'\0'是字符串结尾的标志用来判断一个字符串是否到结尾if(map[x][y]==5)break; if(5==map[x][y])把常量放在左边避免==写成一个等号赋值右结合性如果左边为常量常量是不可改变的 !=不等于如果左边等于右边返回0否则返回11!=2----1 if(4!=map[i][j])判断游戏结束的时候是否有空箱子 赋值运算符=-=+=*=/=%=<<=>>=^=|=赋值运算符=右结合性从右边开始往左边运算把右操作数的值给左操作数a=3a+=3;a=a+3=6;a*=3a=a*3;a>>=3a=a>>3;a右移三位然后把右移三位的值赋值给a逻辑运算符&&||!逻辑与&&左边和右边同时为1才为1否则为0一般的逻辑运算符会和关系运算符结合a=3a>=3&&a<5[3,5) 逻辑或||左边和右边同时为0才为0否则为1逻辑运算符的短路从左往右的时候如果计算到当前位置可以让逻辑运算符返回值那么不会执行剩下的语句&&如果左边就返回0那么不会去执行右边的语句||如果左边就返回1那么不会执行右边的 逻辑非!aa为1返回0如果a为0返回1 三目运算符表达式1表达式2:表达式3判断表达式1是否为真如果为真执行表达式2否则执行表达式3 abcmax=a>ba:b;max=max>cmax:c; 未定义式a=i+++i++;a=++i+++i+++i;++i;++i;++i;a=i+i+i;a=i+i;i++;i++; C标准里面根据编译器自行处理 逗号表达式,a=3,4,5;如果没有括号返回第一个如果有括号返回最后一个 ()[].->{}()1.提升优先级2.形参列表[]数组的成员访问map[i][j]{}1.作用域2.定义域.分量运算符结构体变量的成员 优先级1.不要刻意记优先级2.可以通过括号提升想要先做的3.考试面试单目>双目>三目 四则运算符(算术)关系逻辑==!= 四:分支语句 分支语句 1.if(表达式1){语句块;}判断表达式1的真假如果为真执行语句块否则跳过 表达式可以是一个变量判断变量是否为1如果是一个表达式判断表达式的返回值 2.if(表达式1){语句块1;}else否则{语句块2;}如果否则 3.if的嵌套 else一定要注意逻辑是和相应的if匹配的如果匹配错逻辑就会错误 else是必须跟在if后面的 4.if(表达式1){语句块1;}elseif(表达式2){语句块2;}elseif(表达式3){语句块3;}else{语句块4;} 划分自然数负数0正数ifa>0正数elseifa<0负数else05.if(表达式1){语句块1;}if(表达式2){语句块2;}多个单独的if等级是一样的相互不影响 判断闰年闰年有两种能被4整除但是不能被100整除能被400整除1900%4==01900%400!=0 switch switch(变量名){case常量表达式1:语句块1;break;case常量表达式2:语句块2;break;}用switch里面的变量去匹配case的情况如果匹配成功就执行case之后的语句 inta=3;switch(a){case3:printf("HelloWorld!\n");break;}a进入switch之后会去匹配相应的值如果匹配成功就执行相应的内容在case后面必须有break用来跳出当前switch开关转换鞭子break只能用于循环或者开关语句也就是switch 会逐个判断如果匹配到就会执行如果全部判断完没有匹配成功就会结束 两个case的值不能相同 break跳出如果没有breakcase语句的穿透性如果匹配成功而且没有break会直接执行下一个case并且不需要匹配直到breakdefault也会穿 switch的注意事项: 未初始化的局部变量未定义的标识符 五:循环语句 goto无条件执行直接跳转到相应的语句任何条件都会执行只要程序走到goto这一行 可以在语句前面给出一个标签一个名字:不论这个标签在哪里只要goto执行了都会执行标签语句 不建议使用goto有一个好处:可以直接跳出多重循环 whilewhile(表达式){循环体;调整语句;}1.判断表达式是否成立如果成立执行循环体一次,回到表达式判断是否成立2.表达式不成立跳过循环 循环内判断条件循环体调整语句调整语句调整的是判断条件的变量判断条件可以是变量判断变量为0还是1可以是表达式判断表达式的返回值调整语句可以写在循环体内也可以直接写在判断条件上 break跳出循环直接执行循环后的语句continue结束当前次循环返回到判断条件只能作用于最内层循环tips: 错误分为两种语法错误:编译器会报错 逻辑错误:语法正确但是不能执行相应的功能循环嵌套外层循环执行一次内层循环执行n次外层循环想执行第二次必须等到内存循环执行完 dowhiledo{循环体;}while(表达式); while后面的小括号后必须有分号 先执行循环体,然后判断表达式是否为真如果为真继续执行循环体否则跳出循环 dowhile和while的区别一定会执行一次循环体不论表达式是否为真 MSDN微软的帮助文档在线版本一个函数不了解用法选中函数F1如果浏览器没有带翻译功能就是全英文的离线版本14G for for(表达式1;表达式2;表达式3){循环体;}表达式1初始化条件表达式2判断条件表达式3调整语句先执行初始化条件,把循环变量初始化,判断条件是否为真如果为真执行循环体,执行调整语句,再判断条件是否为真如果为假就跳出循环 tips:1.for构成死循环第一个没有调整语句判断条件不会改变第二个判断条件永真或者永假第三个没有判断条件 2.for相比于while的优势如果要看明白一个while是怎么执行的看明白一个for只需要看小括号内while转汇编的时候比for少一行代码 3.for循环的时候表达式123都可以缺省但是分号不能缺省 什么时候用什么循环循环是有适用的 知识点回顾:goto:无条件跳转while:避免永真永假dowhile:一定会先执行一次循环体for:for(;;)即使表达式缺省分号不可省 六:数组1 数组:数组:一堆具有相同数据类型的数据的集合如果一个标识符被变量用过了那么数组就不能再用了 访问数组元素:数组名[访问的位置(其实就是下标)];数组的下标是从0开始的inta[5];a[0]a[1]a[2]a[3]a[4]0~数组大小-1在内存中是连续的a[2]=5; 初始化: inta;//定义一个整型变量标识符变量的名字为aintbrr[5];//定义一个整型的数组标识符数组的名字为b大小为5floatc[20];//定义了一个float的数组名字叫c有20个元素 数组元素的初始化:inta[5]={1,2,3,4,5};//可以按顺序对整个数组赋值inta[5]={0};//只对第一个元素赋值缺省其他元素的值inta[6]={1,2,3,4,5};inta[5]={};//可以缺省所有值inta[]={1,2,3,4,5};//可以在前面缺省数组大小,但是在初始化列表给出所有元素的初值inta[5]={1,2,3,4,5};inta[]={};编译器:你要定义什么---错误inta[5];//不进行初始化就调用,会输出垃圾值---没意义inta[5]; 数组的赋值只能是逐个赋值://1.逐个枚举单独赋值//2.循环逐个赋值 inta[5]={0};printf("%d\n",sizeof(a));//得到的是数组的大小4*5=20printf("%d\n",sizeof(a)/sizeof(a[0]));//sizeof(int) 字符串是一个特殊的字符数组默认最后一个位置似乎\0字符串数组字符数组数组 intmain(){chara[10]={"helloworl"};//只能存储9个最后一个为'\0'//a[9]='l';charb[10]={'h','e','l','l','o','w','o','r','l',''};//能存储10个charc[]={"helloworld"};//针对字符数组如果用字符串去初始化那么要注意//字符串的结尾默认为'\0'占一个位置//如果数组大小为10那么只能用9个单位长度的字符串去初始化//如果用字符去初始化那么遵照数组的原则 冒泡排序:1.从头开始,相邻数据进行比较,如果前者比后者大交换,否则不交换2.从第一对开始,比较到最后一对为止,最大的数据就到最后了3.对未排序的数继续上述操作重复124.得到有序数组 3254101234第一次:23541235412345123415第二次:2341523415231455个数字第一轮比较4次得到最大值第二轮比较3次得到次大值第三轮比较2次得到第三大值 //冒泡排序inta[10]={13,590,650,28,19,120,567,73,90,278};printf("before排序:\n");for(inti=0;i<10;i++){printf("%d\t",a[i]);}printf("\n");for(inti=0;i<10;i++){for(intj=i+1;j<10;j++){if(a[i]>a[j]){inttemp=a[i];a[i]=a[j];a[j]=temp;}}}printf("after排序:\n");for(inti=0;i<10;i++){printf("%d\t",a[i]);}printf("\n"); 交换两个数的方法:加减法:a=b-a;//a=b-ab=b-a;//b=b-a=b-(b-a)=b-b+a;a=a+b;乘除法:异或法:0^0=01^0=1a^0=aa^a=05^0=00000101^00000000=00000101=55^5=00000101^00000101=00000000=0a=a^b;b=a^b;//b=a^b=a^b^b=aa=a^b;//a=a^b=a^b^a=a^a^b=b 七:数组2 二维数组: *************** 以行为主序每读一行读5列 inta[3]={*****,*****,*****};intb[5]={*****};b[0]~b[4] a[3]={b[5],b[5],b[5]};inta[3][5]={*****,*****,*****};a[0][0]~a[2][4]; inta[2][4];a[1][3];********通用定义方式:数据类型数组名[第一维][第二维];inta[3][5];三行五列数组名可以理解为是数组的首地址数组第一个元素的地址地址不可变 内存:a[15]连续的第二行会接在第一行的地址后面实际上是同一行的第二行的第一个元素和第一行的最后一个元素是相邻的&a[0][4]+4=&a[1][0] inta[6]={1,2,3,4,5,6};&a[2]=&a[1]+sizeof(int)访问:访问到具体元素a[0][0];第一行第一列a[1][0];第二行第一列如果要访问元素需要给出两个下标 一维数组的一维数组a[3]3*a[5];inta[3][5];如果要访问某行的第一个位置表示某一行a[0]----第一行a[1]----第二行a[1]实际上也是一个数组a[1][2] a[3][5]----3*b[5];a[0]a[1]a[2] C语言默认行主序 初始化用一对花括号表示一行看着方便定义二维数组的时候只有最高维可以缺省如果想跳过一行不赋值,必须用{0}表示默认为0,,之间必须有数值不能是空格数组名可以理解为是数组的首地址printf("%p\n",&c[1]);printf("%p\n",c[1]);printf("%p\n",&c[1][0]); 根据概念去理解然后去计算intarr[4][2]={1,2,3,4,5,6,7,8};//假设arr数组的起始位置是1000//arr//arr+2//arr[3]//arr[2]-1//&arr[1][2] printf("%d\n",arr);printf("%d\n",arr+2);//2*2*4//2*2*sizeof(int)2*2*4//2*sizeof(arr[0])2*4*2printf("%d\n",arr[3]);//地址3*2*4arr+3arr[3]+0printf("%d\n",arr[2]-1);//2*2*4-4//a[1][1]如果只给出数组名那么加减法作用在第一维上如果给出第一维坐标那么加减法作用在第二维上 arr[4][2];printf("%d\n",&arr[1][2]);arr[2][0]; printf("%d\n",&arr[2][-1]);arr[1][1];arr[4][2]; 八:指针一在32位系统下不论是什么指针都是四个字节如何定义指针指针类型指针没有初始化访问有两种情况 inta;//定义一个变量整型在内存中申请一块空间int*pa;//指针的大小pa=&a;//把a的地址放到pa里*pa;//解引用返回指针指向的地址的值a=3;printf("%d\t%d\n",a,*pa);//33printf("%p\t%p\n",&a,pa);//3地址 3.14存放在内存中也是二进制那么按照整型的读法是一个大整数为什么能够反馈出来是3.14而不是一个整数因为地址是有类型的不能简单的通过看值来判断类型 1.指向一个不可用的地址,报错内存错误2.指向一个有数据的地址,一个合法的地址 空指针NULLnullptr指针必须是在变量的地址上不能直接访问地址的数值charch='a';char*cp=&ch;ch;//'a'97cp;//ch的地址&ch;//ch的地址*cp;//'a'97*cp+1;//b*(cp+1);//下一个地址的值printf("%p\t%p\n",cp,cp+1); inta=5;//0x10int*pa=&a;*pa+1;//6*(pa+1);//0x14//当前地址+1*sizeof(int)printf("%p\t%p\n",pa,pa+1);printf("%d\t%d\t%d\n",*pa,*pa+1,*(pa+1)); 内存四区:代码区:放代码的地方全局,静态,常量数据区:栈区:数组,变量不需要手动释放会随着程序的结束自动结束堆区:需要手动申请手动释放,malloc申请动态内存 **不允许对NULL指针解引用 指针的运算指针只有两种运算:算术运算:+-+:在指针的基础上+整型+整型*sizeof(数据类型)-:原则上,任意指针之间都可以做减法操作但是,如果要有意义,只有同一个数组的指针做减法才有价值同一个数组的指针相减,返回中间的元素个数关系运算:<><=>=用指针之间的关系运算来返回帮助判断循环或者分支 二级指针指针是指向变量的变量:存放的是变量的地址二级指针:指针的指针,存放的是指向变量的指针的地址 intmain(){intn=5;//定义一个变量叫n是个整型int*pn=&n;//定义了一个指针变量叫pn指向整型int**ppn=&pn;intm=7; *pn=67;*ppn=&m;//修改pn的指向//ppn=&pn;//*ppn=pn=&n; 九:指针二 数组指针指针数组 一级指针可以指向二维数组那为什么要引入数组指针?为了提高代码的可读性 数组指针数组的指针int(*p)[5]指向列数固定的二维数组 指针数组指针的数组int*p[10]一个元素个数为10个的数组每一个元素都是指针 常量指针指针常量常量指针常量 常量指针指向常量的指针指向可以改但是不能通过指针修改指向的值常量指针只能规定当前指针不能修改指向的值,不能确保别的指针不改 指针常量指向变量的不可修改的指针指向不能改但是可以通过指针修改指向的值 常量指针常量指向常量的不可修改指向的指针不可以改指向,也不可以改指向的值 数组名不是指针数组名不是指针数组名不是指针为什么数组名可以代替地址在有数组名参与的表达式里面大多数情况下会为数组名生成一个首地址的指针常量两种情况下不是:sizeof(a)/sizeof(int)当做整个数组来用 intmain(){inta[5]={1123,2354,23,75,12};int*pa=a;&a当做数组来使用pa=&a[0];int*p[10]; 数组指针for(inti=0;i<5;i++)//输出行{for(intj=0;j<3;j++)//输出列{printf("%d\t",*(*(pb1+i)+j));//第一次解引用找到行//第二次解引用找到列}}数组指针:可以指向所有列为5的数组可以指向二维数组必须一模一样列数必须相同 char*keyword[]={//这是一个指针数组"do","for","while","return","switch"}; intmain(){inta=5;//定义一个变量int*pa=&a;//定义一个普通的指针//const//用来表示不可改变的量不可修改的量intconst*pa1=&a;//常量指针constint*paaa;//这个形式和上面一样 intb=7;int*constpa2=&a;//指针常量 printf("%d\n",a);*pa=4;//可以通过指针修改指向的数值printf("%d\n",a);//*pa1=7;//常量指针不能修改指向的值printf("%d\n",*pa2);*pa2=7;printf("%d\n",*pa2);printf("%d\n",*pa1); inta=5;intconst*constpa;常量指针常量 字符串结尾是'\0'所以可以用来判断是否是结束charstr[30]="TanzhouLiushuaiSummerseven";char*s=str;//用指针指向数组intlen=0;//初始化长度为0while(*s++!='\0')//判断当前字符串是否到结尾{len++;}printf("%d\n",len);return0; 十:指针三 实现:strcpy intmain(){charstr1[20]="HelloSummerSeven";charstr2[20];char*s=str1;char*s2=str2;//for(inti=0;*s!='\0';i++)//{//*s2=*s;//s++;//s2++;//}////没有字符串结尾的\0//*s2='\0';//手动的在字符串结尾添加\0强行结束 while((*s2++=*s++)!='\0');//首先执行++然后执行*然后执行=然后执行!=然后循环//实际上循环条件判断的是s2里面的\0而不是s的\0//所以能把\0也拷贝过去 puts(str2); inta; //==运算符获取到的是scanf函数的返回值而不是内容//scanf输入成功就是1失败就是0if(scanf("%d",&a)==1){printf("Helloworld\n");} intmain(){//inta[5]={1234,123,45,5467,658}; //printf("%d\t%d\n",a[2],2[a]);////讲这些东西的目的要认识它要知道它不好不能写 ////inta[10];a[n]////*(&a[0]+sizeof(int)*n)////int*p=a;p=&a[0]*(p+sizeof(int)*n)////*(a+2*4)==*(2*4+a) //intb[5][5]={0};//printf("%d\t%d\n",&b[3][0],&b[3,4]);//不一样//printf("%p\t%p\n",&b[4][0],&b[3,4]);//一样//逗号表达式运算符inta=0;a=3,4,5;//a=3a=(3,4,5);//a=5printf("%d\n",a); intmain(){//输入输出的时候//%*nd自动丢弃n位//inta,b;//scanf("%d~~~~~~%d",&a,&b);//printf("%d\t%d\n",a,b); inta[3][3];//charc=getchar(); int*pa[3];//这是一个数组pa[0]=a[0];pa[1]=a[1];pa[2]=a[2]; for(inti=0;i<3;i++){for(intj=0;j<3;j++){scanf("%d",(*(pa+i)+j));}} for(inti=0;i<3;i++){for(intj=0;j<3;j++){printf("%d\t",*(*(pa+i)+j));}printf("\n");} 十一:函数一 函数基本形式 返回值类型函数名(参数列表){函数体;} 返回值类型规定函数返回的值的类型函数名调用的时候要用的名字参数列表传参给函数的时候要传的参数函数体函数的功能{}作用域 定义intMyadd(inta,intb){intsum=a+b;returnsum;} 函数名随便起遵循标识符的规则返回值类型规定了函数的返回值的类型voidintdoublefloatcharint*结构为什么要返回值根据写函数的需求来定的如果是有返回值的函数真函数返回值本身就是根据需求写的 如果有返回值可以参与语句可以直接成为语句如果没有返回值可以直接成为语句 return----功能上类似循环中的break如果函数执行到return会直接返回return0正常的返回 定义的时候必须写变量名 tips:函数体内可以定义变量没问题如果函数没有要求传参最好在参数列表写上void如果没有给出返回值类型,函数默认返回int而且可以执行 C语言的函数所有参数传递都是传值调用.传值调用----传址调用 传入函数为地址的值的时候做交换操作的时候c=&ad=&b1.传递给函数的标量参数是传值调用2.传递给函数的指针参数是把地址的值传值调用 intmax(inta,intb,intc)//返回值类型为int函数名叫Myadd//参数列表为inta,intb需要传两个参数都是int 函数参数列表是形参形式参数main内调用函数内是实参实际参数形参不会影响实参的值 voidMyswap(int*a,int*b)//定义一个交换函数{inttemp=*a;*a=*b;*b=temp;//printf("%d\t%d\n",a,b);} voidMyswap1(int*a,int*b)//参数列表为两个指针{inttemp=*a;//取出a的值*a=*b;//把b的值给a*b=temp;//把a放在temp里的值给b} #include intYouradd(inta,...)//给出多少个数的加法{intsum=0;//求和va_listvar_arg;//定义一个va_list类型的变量intcount=0;//定义个数va_start(var_arg,a);//准备开始接收不确定的部分//给出变量名以及访问的参数个数for(count=0;count 十二:函数二#include 1.函数指针指针函数指针函数:返回值为指针的函数不能返回临时变量的地址函数指针:指向函数的指针 函数指针的规则:1.返回值类型和参数列表共同决定了这个函数指针能指向的函数只要返回值类型和参数列表和函数指针的一样那么就可以被这个指针指向2.(*p)3.函数名前(&)可加可不加 intaddintjianintchengintchu 2.递归迭代:循环--从起点出发逐步的接近终点循环的判断条件调整语句让循环变量逐步接近判断条件保证不是死循环 递归:函数不断的调用自己---从终点出发回到起点递归的终点就是结束递归的条件(循环的判断条件)不断的迫近递归终点 写一个递归递归的终点一定要先写----不是死循环然后要保证递归的变量在变---要有一个调整的过程 阶乘5!=5*4*3*2*1;5!=5*4!=5*4*3!;n!=n*(n-1)!;n=0; 迭代和递归的取舍:递归的优势在于提高代码的可读性牺牲运行时的开销迭代减少开销可读性不高迭代是人递归是神 char*Mystrcpy(char*des,char*res){char*temp=des; while(*temp++=*res++);returndes;} intmain(){charstr1[20]="helloworld!";charstr2[20];char*s1=str1;char*s2=str2; void(*p2)();p2=print;p2(); char*(*p)(char*s1,char*s2); return0;}递归intfac(intn){if(n==0)//递归的终点标志0!=1return1;elsereturnn*fac(n-1);} intmain(){//求5!intn=5;intsum=1;for(inti=1;i<=n;i++){sum*=i;}intsum2=fac(n);printf("%d\t%d\n",sum,sum2);return0;}*/ //把一个整型的数用递归求每一位 voidMyadd(unsignedintvalue){unsignedinttemp; temp=value/10;//调整语句if(temp!=0)//递归的终点{Myadd(temp);}putchar(value%10+'0');//printf("%c",value%10+'0');//输出一个字符} intmain(){unsigneda=23456;Myadd(a);printf("\n"); char*Mystrcpy(char*des,charconst*s2){char*temp=des;//定义一个临时指针指向目标字符串//让这个临时指针来做拷贝操作让目标字符串的首地址保持//因为最后要返回目标字符串的首地址//在copy过程中需要移动指针导致目标字符串的首地址找不到了//目标字符串 while((*temp++=*s2++)!='\0');returndes;***不能在函数中返回临时变量的地址} //拷贝完之后前面是烫后面是内容intmain(){charstr1[20]="helloSeven";//源字符串charstr2[20];//目标字符串 char*s1=str1;char*s2=str2; s2=Mystrcpy(s2,s1);puts(s2);return0;} 十三:结构体 结构体 数组是一堆具有相同数据类型的数据的集合 结构体可以把有不同的数据类型的数据存放在一起聚合数据类型数组结构体 结构体把它的值称为成员 structtag{memberlist;}variable-list; 直接访问间接访问:.直接访问用于结构体变量访问结构体成员->间接访问用于结构体指针访问结构体成员 赋值初始化四种方法第一不能在结构体里赋值第二初始化方法1.类似数组的初始化方法={}; 2.枚举逐个赋值自引用 typedef起别名 内存对齐要求结构体内定义变量的顺序从大到小排列从小到大排列structdanny*summerseven;//自引用////不论是什么指针大小都是4 //printf("%d\n",sizeof(structdanny));//20内存对齐//内存对齐机制对齐补齐//会以最大的基本数据类型为标准//410=4+4+2+1+1--->124*3+4=20 structdanny{unsignedinta:3;//意味着这个a只能占两位111001000`3//floatd;unsignedcharb:5;//structdanny*summerseven;//自引用//不论是什么指针大小都是4}ouguang;//怎么写位段直接在变量后写:加上一个值//这个值是二进制的位数的意思//一般地写位段的时候最好给出unsigned或者signed ouguang.a=8;//10101保留有效位数//int占几个字节//不同的数据类型会首先参照对齐规则printf("%d\n",sizeof(structdanny));//4//位段的作用让结构体的内存更紧凑//约束输入的数的范围 typedefstructdanny{inta;charc;doubled;}laosiji,*summerseven; typedefstructdannylaosiji1; 十四: 解决问题:指针数组函数问题在哪里问题描述出来哦一个个讲解 1.函数数组结合返回指针然后输出2.这个问题没看明白函数里是不是全是重要的东西---3.为什么说指针不安全程序关心的是数据指针提供了另一种访问数据的方式不确定用指针去访问数据的时候别人会不会做不安全的操作提供const保障一定的安全4.指针解引用是不是不带*5.const和指针的作用 6.参数列表如果是指针 7.两个指针能指同一个地方吗inta=5;int*pa=&a;//二狗子int*pb=&a;//大狗子printf("%d\t%d\t%d\n",a,*pa,*pb);*pa=11;//只对某一个指针修改操作会改变其他的值printf("%d\t%d\t%d\n",a,*pa,*pb); 8.什么是函数,函数的作用把一系列具有某个功能的代码封装起来方便以后调用只需要简单的调用就可以实现一样的功能而不需要重新写每个功能写一个函数提高可读性 9.字符数组,字符串和指针的结合--这个问题描述的清楚一点字符串是一个特殊的字符数组,数组和指针数组名在某些情况下是一个指向首地址的常量指针 10.函数内容和主函数衔接第一个没有返回值的函数只有在函数内部直接和主函数的东西发生关系第二个有返回值的函数第一种在函数内部和主函数发生关系第二种通过返回值修改一些东西 11.函数返回值,什么时候可以改变形参,什么时候用完就释放局部变量出了作用域就会释放一对花括号表示作用域在一个作用域定义的局部变量到另一个作用域内是不能使用的 12.结构体有数组结构体有这个结构体--这个其实昨晚结构体正课讲了13.函数有没有规定的定义格式函数的格式就是想写什么就写什么14.字符串数组的应用 十五:单链表1 #include 单链表:内存不连续,添加节点和删除节点很简单,查找会相对困难中间添加删除也可以 内存四区:堆栈全局代码栈区内存会随着程序的死亡而释放堆区内存必须手动申请,手动释放 链表的节点是由两部分组成的:数据域--真正关心的指针域--把链表连起来 增删改查增加节点:头插法尾插法查找节点:必做删除节点选做修改节点 动态内存分配:在堆区申请一块内存,需要用指针接住,因为这块内存没名字malloc在堆区申请一块内存返回首地址的指针返回的是void*如果想要使用必须强制转换类型 inta=5;//空间在栈区int*p=NULL;p=(int*)malloc(sizeof(int));//在堆区申请一块空间*p=5;printf("%d\t%d\n",a,*p);free(p);//释放申请的堆区内存//释放完这块空间之后该指针变为野指针/没有指向空间p=NULL;//因为不能确保p是否会被直接使用//即使误操作对p解引用不会摊上大事情 intb[5]={1,2,3,4,5};intn;scanf("%d",&n);//此时这个数组就是一个动态的int*pb=(int*)malloc(sizeof(int)*n);//申请空间//intb[5];//一次性申请的内存是连续的for(inti=0;i<5;i++)//赋值{*(pb+i)=i+5;}for(inti=0;i<5;i++)//打印{printf("%d\n",*(pb+i));}//这是一个良好的习惯free(pb);pb=NULL; pa=(structtag*)malloc(sizeof(structtag));//sizeof是多少就会申请多大的堆区内存pa->b='A';printf("%c\n",pa->b);free(pa);pa=NULL;inta=5;floatb=3.14f;//f表示float否则会隐式转换成都doubleint*pa=&a;float*pb=&b;pa=(int*)pb; structtag//实际上这就是链表的一个节点的结构体{intdata;structtag*next;//自引用}*pa; pa=(structtag*)malloc(sizeof(structtag));pa->data=5;//next指针也要开辟空间 free(pa);pa=NULL;//先开辟的后释放//先申请pa再申请next要先释放next再释放pa /****************************/#include linklist*CreateList_Front();//头插法创建单链表linklist*CreateList_End();//尾插法创建单链表linklist*CreateList_EndTwo();//尾插法创建单链表(优化后有头结点少两次判断)voidShowLinklist(linklist*h);//输出显示链表voidgetdate(linklist*head,intpos);//查找pos位置的值intmodifylist(linklist*head,intpos);//修改pos位置的链表信息intisEmptyList(linklist*head);//判断链表是否为空voiddellist(linklist**head,charch);//删除链表某个节点 intmain(){intchoice;linklist*head;//head=(linklist*)malloc(sizeof(linklist)); while(1){printf("单链表的创建\n");printf("1.使用头插法创建单链表\n");printf("2.使用尾插法创建单链表\n");printf("3.链表输出显示\n");printf("4.修改链表信息\n");printf("5.删除链表某元素\n");printf("8.退出\n");printf("9.清除屏幕\n");printf("做出选择:\n");scanf("%d",&choice);switch(choice){//头插法case1:head=CreateList_Front();break;//尾插法case2://head=CreateList_End();head=CreateList_EndTwo();break;//输出链表case3:ShowLinklist(head);break;//退出程序case4:{intpos;printf("请输入要修改的位置:\n");scanf("%d",&pos);modifylist(head,pos);break;}case5:{//如果删除头结点head=head->next;charch;printf("请输入要删除的元素\n");rewind(stdin);//清除缓冲scanf("%c",&ch);dellist(&head,ch);//因为要修改头结点所以要传入二级指针break;}case8:return0;break;case9:system("cls");break;default:break;}}getchar();getchar();return0;} /*头插法*/linklist*CreateList_Front(){linklist*head,*p;charch;head=NULL;printf("依次输入字符数据('#'表示输入结束):\n");ch=getchar();while(ch!='#'){p=(linklist*)malloc(sizeof(linklist));p->data=ch;p->next=head;head=p;ch=getchar();}returnhead;} /*不带头结点的尾插法*/linklist*CreateList_End(){linklist*head,*p,*e;//头结点临时节点尾节点charch;head=NULL;e=NULL;printf("依次输入字符数据('#'表示输入结束):\n");ch=getchar();while(ch!='#'){p=(linklist*)malloc(sizeof(linklist));p->data=ch;if(head==NULL)//判断此时链表是否为空//插入的数据是第一个数据也就是头{head=p;}else{e->next=p;//让尾节点的next指向p}//p->next垃圾值e=p;//保持尾节点永远指向链表的尾部ch=getchar();}if(e!=NULL)//如果链表不为空,则最后一个节点的next为空{e->next=NULL;}returnhead;} /*带头结点的尾插法*/linklist*CreateList_EndTwo(){linklist*head,*p,*e;charch;head=(linklist*)malloc(sizeof(linklist));//给head分配内存//如果用这种尾插法创建链表//要避开第一个头结点不输出//p=head->next;e=head;printf("依次输入字符数据('#'表示输入结束):\n");ch=getchar();while(ch!='#'){p=(linklist*)malloc(sizeof(linklist));p->data=ch;//把数据放到链表节点的数据域e->next=p;//让尾节点指向临时节点e=p;//让临时节点变成尾节点ch=getchar();}e->next=NULL;returnhead;//直接返回head->next;} /*显示链表*/voidShowLinklist(linklist*h){linklist*p;p=h;if(p->next==NULL||p==NULL){printf("链表为空\n");return;} while(p!=NULL){printf("%c",p->data);p=p->next;}printf("\n");} /*修改链表某个位置的元素,修改成功返回0否则返回1*///根据节点位置intmodifylist(linklist*head,intpos){linklist*p=head;//这个地方昨天的问题inti=0;if(pos<1){printf("modifylist函数执行,pos值非法\n");return1;}if(head==NULL){printf("modifylist函数执行,链表为空\n");return1;}while(p!=NULL){++i;if(i==pos)break;p=p->next;//移到下一结点}if(i /*删除链表节点,根据元素值*///根据节点元素voiddellist(linklist**head,charch){linklist*p=*head;linklist*temp;//临时指针方便操作if(p->data==ch)//头结点单独处理{*head=(*head)->next;//把表头指针往后移动free(p);//删除了原来的表头的节点}p=(*head)->next;//把p指针指向head之后temp=*head; while(NULL!=p)//从第二个节点开始{//如果已知题目有两个或多个相同元素想删除第几个//flag判断当前是第几个要删除的元素if(p->data==ch)//找到元素匹配到了要删除的元素{temp->next=p->next;//让第一个元素指向第三个free(p);break;}p=p->next;//指针指向下一个元素temp=temp->next;} linklist*dellist1(linklist*head,charch);//可以让返回值为结构体指针类型在主函数用head接住返回值//从而避免使用二级指针 十六:单链表2 #include //typedefstructlinklinklist;typedefstructlink{/*定义单链表结点类型*/chardata;structlink*next;//指向一个结构体因为指针就是4字节//structlinkx;//此时结构体还没定义完内存大小不能确定//inklist*x;这是不允许的因为取别名还在后面}linklist; while(1)//这是一个死循环{printf("单链表的创建\n");printf("1.使用头插法创建单链表\n");printf("2.使用尾插法创建单链表\n");printf("3.链表输出显示\n");printf("4.修改链表信息\n");printf("5.删除链表信息\n");printf("8.退出\n");printf("9.清除屏幕\n");printf("做出选择:\n");scanf("%d",&choice);switch(choice){//头插法case1:head=CreateList_Front();break;//尾插法case2://head=CreateList_End();head=CreateList_EndTwo();break;//输出链表case3:ShowLinklist(head);break;//退出程序case4:{intpos;printf("请输入要修改的位置:\n");scanf("%d",&pos);modifylist(head,pos);break;}case5:{charch;printf("请输入要删除的元素:\n");rewind(stdin);//要清空缓冲scanf("%c",&ch);dellist(&head,ch);//head指针的地址其实就是二级指针break;}case8:return0;break;case9:system("cls");break;default:break;}}getchar();getchar();return0;} /*尾插法1(无头结点)*/linklist*CreateList_End(){linklist*head,*p,*e;charch; head=NULL;e=NULL;printf("请依次输入字符数据('#'表示输入结束):\n");ch=getchar();while(ch!='#'){p=(linklist*)malloc(sizeof(linklist));p->data=ch;if(head==NULL)//先判断输入的是不是第一个节点head=p;elsee->next=p;e=p;//e始终指向输入的最后一个节点ch=getchar();}if(e!=NULL)//如果链表不为空,则最后节点的下一个节点为空e->next=NULL;returnhead;} /*尾插法2(有头结点)*/linklist*CreateList_EndTwo(){linklist*head,*p,*e;charch; head=(linklist*)malloc(sizeof(linklist));e=head;//让e指向头节点ch=getchar();while(ch!='#'){p=(linklist*)malloc(sizeof(linklist));p->data=ch;e->next=p;//把新节点添加到表尾e=p;//把指针指向新节点ch=getchar();}e->next=NULL;//尾节点的指针域置空returnhead;} /*显示链表*/voidShowLinklist(linklist*h){linklist*p; p=h;while(p!=NULL){printf("%c",p->data);p=p->next;}printf("\n");} /*查找链表某位置的元素*/voidgetdate(linklist*head,intpos){linklist*p=head;inti=0;if(pos<1){printf("getdate函数执行,pos值非法\n");return;}if(head==NULL){printf("getdate函数执行,链表为空\n");return;}while(p!=NULL){++i;if(i==pos)break;p=p->next;//移到下一结点}if(i /*修改链表某个位置的元素,修改成功返回0否则返回1*/intmodifylist(linklist*head,intpos){linklist*p=head;inti=0;if(pos<1){printf("modifylist函数执行,pos值非法\n");return1;}if(head==NULL){printf("modifylist函数执行,链表为空\n");return1;}while(p!=NULL){++i;if(i==pos)break;p=p->next;//移到下一结点}if(i //检查单链表是否为空,若为空则返回1,否则返回0intisEmptyList(linklist*head){if(head==NULL){printf("isEmptyList函数执行,链表为空\n");return1;}printf("isEmptyList函数执行,链表非空\n"); /*找到要删除的元素然后执行删除操作*///涉及到要删除头结点//匹配到怎么删头节点要单独讨论要传入二级指针voiddellist(linklist**head,charch){linklist*p=*head;linklist*temp;if(p->data==ch)//匹配到头结点的值是要删除的{*head=(*head)->next;//让头结点指向下一个位置free(p);//释放头结点}p=(*head)->next;//p=p->next;如果进入了if分支此时p已经被释放temp=*head;//head在p前面//不要一上来就开始写代码先思考一下怎么写while(NULL!=p){if(p->data==ch){temp->next=p->next;//图free(p);break;//不能保证整个链表只有一个匹配值}//if如果没有匹配到那么就要继续匹配下一个节点p=p->next;temp=temp->next;}//如果不使用二级指针returnhead;} 十七:预处理(联合枚举) 枚举就是穷举把所有可能列出来放在枚举内的称为标识符实际上是一个整型同一个标识符只能属于一个枚举规则1.只能放标识符不能直接放整型2.同一个标识符只能被一个枚举引用3.默认的第一个枚举的成员会从0开始其后的每一个逐个+14.可以给任意一个赋值 enumWeekday//5以内的整数的枚举{one,two,three=0,four,five//01012}; enumdir{LEFT,RIGHT,UP,DOWN}x; 永远只会表现一个值共用一个内存 规则:结构体内存对齐规则如果超过的会朝4对齐char3--->41.关于内存大小先找到整个联合体内内存最大的单位然后对齐最大的基本数据类型如果超过4但是不是4的整数倍就会对齐朝着比它大的最小的整数倍靠近2.对联合体的初始化只能初始化第一个成员 enumdir{a,b,c,d,e,f,g,h,i,j,k//012......}; unionxx{inta;charb;}m={49}; intmain(){printf("%d\n",m.a);printf("%c\n",m.b);return0;}*/ structdanny{intball;charname[5];}; unionOuguang{//charname[9];//xiainta;//intball;//5floatf;//chard;}x={0}; 预处理: 宏定义#definenamestuff只要在程序中遇到name就会替换成stuff #define机制包括了一个规定,允许把参数替换到文本中 一般的习惯上会大写宏名 如果宏定义过长可以用\来换行(一般会人为的把宏名和内容分成两行) "#value"会输出value 副作用:如果参数带++--那么可能会多次执行从而导致结果不可预测如果宏中带了getchar(); #undef用来取消某个宏作用:1.不想用某个宏2.要改变某个宏 宏函数相较于函数的优点:1.无视类型2.更快速 相较于函数的缺点:1.代码膨胀 如何区别宏函数和函数一般的函数会小写或者遵循标识符规则宏函数会全部大写 条件编译#ifconstant-expressionstatements#endif#if其后可以跟表达式常量条件编译可以嵌套 文件包含#include<>引入库文件""引入自己写的文件***头文件的重复包含问题***因为多文件操作的时候无法保证一个头文件只被一个文件包含会发生头文件重复包含解决方案:1.#pragmaonce放在头文件最前面用来保证头文件只包含一次这个命令随编译器的变化而变化2.#ifndef__A_H__//判断这个宏有没有定义#define__A_H__#endifif(__A_H__==0)如果这个宏没有定义过就是0那么if表达式为真执行其后的语句如果这个宏定义过就是1那么if表达式为假跳过其后的语句直接执行endif 头文件不要包括函数的定义和变量的定义*/ #definePrint(format,value)\printf("thevalueis"format"\n",value) #definePrint2(format,value)\printf("thevalueof"#value"is"format"\n",value) #defineMAX(a,b)(a>ba:b) #defineONEBALL0#undefONEBALL#defineONEBALL8 #include"a.h"#include"b.h" 十八:文件操作1 文件 文件结构体指针FILE 关于文件操作的函数 打开文件fopen(constchar*path,constchar*mode)打开文件第一个参数给出文件名,打开方式第一个参数默认同路径,如果要给别的路径写相对路径绝对路径关闭文件fclose(FILE*fp);关闭文件给出打开的文件指针即可 写入字符fputc(charc,FILE*fp);要写入的字符,文件指针一次写多个字符只会保留最后一个多次写多个字符都会保留读出字符fgetc(FILE*fp);如果读到文件结尾或者出错返回EOF(一般EOF为-1) 写入字符串fputs(char*str,FILE*fp);写入的字符串,文件指针 数组名在大部分情况下可以当做指针常量使用 读出字符串fgets(char*str,intsize,FILE*FP);从文件中获取字符串目标字符串的数组名或者指针,读取的长度,文件指针实际上读到的长度是size-1因为字符串存在默认结尾\0 写入和读取写入文件freadfwrite人为的称为乱码实际上只是正常的 fscanffprintf 流scanf从键盘获得进入缓冲区直接从缓冲区获得数据数据流 intmain(){ FILE*fp=fopen("108.txt","w"); w是write只写如果没有这个文件会创造一个CPP同路径下如果有打开然后写入内容如果文件本身有内容会被清空rread只读必须要有文件aappend以写方式打开追加在原文件之后不会覆盖原来的内容 b二进制文件t文本文件+可读写w+wb+wt+rbrb+rt+ //fputc('12',fp);//2fputc('1',fp);fputc('2',fp);fclose(fp); //FILE*fp1=fopen("108.txt","w");//fputc('M',fp1);//fclose(fp1); FILE*fp1=fopen("108.txt","r");//如果读多个读到一个就停止charch;ch=fgetc(fp1);printf("%c\n",ch);fclose(fp1); FILE*fp=fopen("71.txt","w");fputs("XiaQi",fp);fputs("OuGuang",fp);fclose(fp); FILE*fp1=fopen("71.txt","r");charch[20]={0};//fgets(ch,5,fp1);//因为存在结尾\0所以只能读取4个//printf("%s\n",ch);fgets(ch,1024,fp1);//可以给出一个较大值直接暴力printf("%s\n",ch);fclose(fp1); FILE*fp=fopen("95.txt","w");while(1){scanf("%s%d%d",mystudent.name,&mystudent.age,&mystudent.num);fwrite(&mystudent,sizeof(structSTU),1,fp);//要写入的内容的首地址,写入内容的大小,个数,文件指针printf("是否继续输入(Y/N)\n");fflush(stdin);//清空缓冲intch=getchar();if(ch=='n'||ch=='N'){break;}} fclose(fp); FILE*fp1=fopen("95.txt","r");fread(&mystudent,sizeof(structSTU),1,fp);//要读出的内容的首地址,写入内容的大小,个数,文件指针printf("%s\t%d\t%d",mystudent.name,mystudent.age,mystudent.num);fclose(fp1); FILE*fp=fopen("147.txt","w");scanf("%s%d%d",mystudent.name,&mystudent.age,&mystudent.num);fprintf(fp,"%s\t%d\t%d\t",mystudent.name,mystudent.age,mystudent.num);//文件指针,分别描述其后的参数的占位符,逐个元素//比printf多了第一个参数文件指针fclose(fp);FILE*fp1=fopen("147.txt","r");fscanf(fp1,"%s%d%d",mystudent.name,&mystudent.age,&mystudent.num);//不是简单的叫文件指针实际上是流//输入流输出流//fflush(stdin)---清空输入流//stdout--输出流fprintf(stdout,"%s\t%d\t%d\t",mystudent.name,mystudent.age,mystudent.num);printf("\n----------------------\n");printf("%s\t%d\t%d\t",mystudent.name,mystudent.age,mystudent.num);fclose(fp1); 定位默认打开文件会在文件的首 fseek(FILE*stream,longoffset,intorigin);流偏移量起始地址偏移量:正--正向偏移实际上就是向后负--负向偏移实际上就是向前因为规定形式是long所以要在数字后+L按照给出的偏移量偏移以字节为单位nL---n个字节起始位置:SEEK_SET文件开始位置0SEEK_CUR文件当前位置1SEEK_END文件结尾位置2 rewind把位置指针重新指向流(数据流/文件)的开头rewind(stdin); intmain(){FILE*fp=fopen("98.txt","w");fputs("qwertyuiopasdfghjklzxcvbnm",fp);fclose(fp); FILE*fp1=fopen("98.txt","r");fseek(fp1,20L,SEEK_SET);charstr[10];fgets(str,6,fp1);printf("%s\n",str);fclose(fp1); 十九:文件操作2 《文件操作》文本文件: 1.文本文件也称为ASCII文件. 2.这种文件在磁盘里面存放时每一个字符对应一个字节,用于存储对应的ASCII码. 二进制文件: 1.这种文件时按二进制编码进行存储的. fopen(要打开的文件,打开方式); 打开方式: w只写,文件存在则清空,不存在则创建.(w)writer只读,文件必须存在(r)readr+读写,文件必须存在w+读写,文件存在则清空,不存在则创建.rbwb 关闭文件: intfclose(FILE*_File); 参数是一个文件指针,就是你要关闭的文件指针. fgetc()和fputc() intfputc(int_Ch,FILE*_File); 参数1:要写入的字符参数二:要写入的文件. intfgetc(FILE*_File); 函数的作用:从文件里面读取一个字符 参数:要读取的文件指针. fwrite()和fread() size_tfwrite(void*_Str,size_tSize,size_tCount,FILE*File); 函数的作用:往文件里面写入一个字符串. 参数1:要写的内容参数2:写入的大小参数3:写入的次数参数4:要写入的文件 size_tfread(void*_DstBuf,size_tElementSize,size_t_Count,FILE*_File); 函数的作用:从文件里读取相应字符. 参数1:保存读取的字符参数2:要读取大小参数3:要读取的次数参数4:要读取的文件 fprintf()和fscanf() intfprintf(FILE*_File,constchar*_Format,...); 函数的作用:格式化写入文件. intfscanf(FILE*_File,constchar*_Format,...); 函数的作用:格式化读取文件. intfseek(FILE*_File,long_Offset,int_Origin); 函数作用:设置文件指针的偏移量 参数1:要设置的文件参数2:偏移量参数3:参照位置 参照位置:SEEK_SET文件头部SEEK_CUR文件指针当前位置SEEK_END文件指针尾部 longftell(FILE*_File); 函数作用:获取文件指针的位置 参数:要获取文件指针位置的文件。 二十:排序一#include 简单排序默认从小到大排列 交换排序:冒泡排序快速排序插入排序:直接插入排序二分插入排序希尔插入排序选择排序:选择排序堆排序冒泡排序快速排序选择排序插入排序 C语言实现的最基础的4个排序算法:冒泡快排插入选择 稳定性:如果数组中存在两个相同的元素如果排序后仍然按照原来的位置排序那么我们称这个排序方法是稳定的 稳定的排序:直接插入冒泡归并基数(桶)不稳定的排序:希尔直接选择堆快排 C语言可以实现8个: 如果想优化一个算法:1.推倒重新写----飞跃失败 2.剪枝---iffor减少判断的次数减少跳转的次数减少算法的复杂度 voidBubblesort(inta[],intn){for(inti=0;i //优化一:添加一个标志用来判断当前数是否已经排序过//如果是就跳过voidBubblesort2(inta[],intn)//优化冒泡{intlow=0;inthigh=n-1;inttemp,j;while(low /*外层循环:两个内循环一个做右边一个做左边外层循环结束的时候:一轮左边比标志小FLAG右边比标志大进入递归 快排的优化:因为取到第一个数可能会降低效率随机取其中的任意一个数作为flag */voidquicksort(inta[],intlow,inthigh){inti,j,flag,m;if(low while(i a[i]=flag;//最后空的位置就是flag的位置quicksort(a,low,i-1);//左边做快速排序quicksort(a,i+1,high);//右边做快速排序}