《C语言程序设计基础与实践》全套教学课件_第1页
《C语言程序设计基础与实践》全套教学课件_第2页
《C语言程序设计基础与实践》全套教学课件_第3页
《C语言程序设计基础与实践》全套教学课件_第4页
《C语言程序设计基础与实践》全套教学课件_第5页
已阅读5页,还剩143页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第1—2章编程语言概述与C语言入门讲授4学时·实验2学时·教材第1—2章《C语言程序设计基础与实践》配套课件01-编程语言概述与C语言入门.pptx02-C语言基础.pptx03-程序控制结构.pptx04-数组.pptx05-函数.pptx06-指针.pptx07-结构体与共用体.pptx08-文件操作与预处理.pptx09-C语言的高级特性.pptx10-项目实践案例.pptx全套可编辑PPT课件本讲学习目标1了解程序设计语言的发展脉络、分类依据与组成要素2理解编译型与解释型两种执行方式的本质区别3掌握C语言程序的基本框架与书写规范4学会搭建开发环境,独立完成编辑—编译—链接—运行全过程第1—2章编程语言概述与C语言入门2本讲导航两条主线:先认识”语言”,再走进”C语言”第1章编程语言概述1.1程序和程序设计语言1.2编程语言的发展历史1.3编程语言的分类1.4编程语言的组成要素1.5程序的执行方式第2章步入C语言的世界2.1C语言的历史和特点2.2C语言的组成2.3开发环境的搭建2.4编写第一个C语言程序2.5程序的编译和运行第1—2章编程语言概述与C语言入门3什么是程序与程序设计语言1.1程序=数据结构+算法;语言=人与计算机沟通的桥梁程序为解决某一特定问题而编写的、能被计算机识别并执行的有序指令集合。程序设计语言一套有严格语法与语义规则的符号系统,用于描述数据与处理数据的步骤。从”问题”到”结果”的四个环节分析问题→设计算法→编写程序→调试运行1.1程序和程序设计语言4编程语言的发展历史1.2抽象程度不断提高,人越来越”省力”,机器越来越”费力”1940s机器语言二进制指令直接面向硬件1950s汇编语言助记符替代仍依赖机型1957高级语言FORTRAN接近自然语言1972C语言结构化兼顾效率与抽象1980s+面向对象C++/Java封装与复用2000s+现代语言Python/Go开发效率优先C语言诞生于1972年,位于”贴近硬件”与”结构化抽象”的交汇点——这正是它历经半个世纪仍不可替代的原因。1.2编程语言的发展历史5编程语言的分类1.3按抽象层次划分为三代机器语言0和1组成的指令码执行效率最高可读性极差、易错完全依赖具体机型汇编语言用助记符表示机器指令可控制硬件细节需汇编器翻译可移植性差高级语言接近数学与自然语言可读性好、开发快需编译或解释可移植性强1.3编程语言的分类6编程语言的组成要素1.4任何一门语言都由这四类要素构成1数据常量、变量、数据类型——描述”处理什么”2运算运算符与表达式——描述”怎么算”3控制顺序、选择、循环——描述”按什么顺序做”4抽象与封装函数、模块、类型定义——描述”如何组织”1.4编程语言的组成要素7程序的执行方式1.5编译型vs解释型:一次翻译完,还是边翻边做编译型源程序→编译→目标程序→链接→可执行文件一次翻译,反复运行运行速度快、脱离源码执行修改后需重新编译代表:C、C++、Go解释型源程序→解释器逐句翻译并执行边翻译边执行,无独立可执行文件跨平台方便、调试灵活运行时开销较大代表:Python、JavaScript1.5程序的执行方式8C语言的历史与影响力2.1.1为编写UNIX而生,最终影响了几乎所有现代语言1969—1970UNIX用汇编写成,移植困难1972DennisRitchie设计出C语言1978K&R经典教材出版,成为事实标准1989/1990ANSIC(C89)与ISOC90正式发布1999—2018C99、C11、C17陆续演进今天,C依然无处不在操作系统内核:Linux与Windows嵌入式与驱动:单片机、物联网设备基础软件:数据库、编译器、虚拟机语言实现:Python等解释器本身2.1C语言的历史和特点9C语言的特点2.1.2六个关键词理解C的取舍简洁高效仅32个关键字,生成代码效率接近汇编贴近硬件支持指针与位运算,可直接操作内存结构化以函数为模块,天然支持自顶向下设计运算符丰富34种运算符,表达能力强可移植性好标准库统一,源码稍作修改即可跨平台约束较宽松类型检查不严,自由的代价是需要程序员自律2.1C语言的历史和特点10C语言程序的基本构成2.2一个最小的C程序包含哪些部分#include<stdio.h>

/*主函数:程序唯一的入口*/intmain(void){inta=3,b=4;//变量定义intsum=a+b;//表达式运算

printf("%d\n",sum);//调用库函数return0;//返回状态码}预处理指令以#开头,编译前完成文本替换main函数有且仅有一个,程序从这里开始执行语句每条以分号结束,写在一对花括号内注释/**/或//,编译器忽略,但读者需要库函数通过头文件声明后才能调用2.2C语言的组成11开发环境的搭建2.3选择一款趁手的工具,教学建议统一环境Dev-C++/Code::Blocks轻量、免安装配置,教学与竞赛常用推荐入门VisualStudio功能完备,调试器强大,体积较大WindowsVSCode+GCC/MinGW跨平台、可扩展,需手动配置编译器进阶推荐Xcode/ClangmacOS原生工具链,终端直接gcc编译macOS提示:安装路径与工程目录请勿包含中文或空格,否则容易出现编译报错。2.3C语言开发环境的搭建12第一个程序与编译运行流程2.4—2.5从一行源码到一个可执行文件#include<stdio.h>intmain(void){printf("Hello,C!\n");return0;}运行结果Hello,C!程序正常结束,返回值01编辑hello.c写出源程序→2预处理/编译hello.o语法检查并译成目标代码→3链接hello.exe合并库函数与目标代码→4运行输出结果由操作系统装入内存执行2.4—2.5编写、编译与运行13入门阶段的高频错误看懂报错信息,比记住语法更重要语句末尾漏写分号✗printf("hi")✓printf("hi");使用了中文标点✗printf(”hi“);✓printf("hi");忘记包含头文件✗直接调用printf✓#include<stdio.h>main拼写或返回类型错误✗voidmian()✓intmain(void)花括号不配对✗{...缺少}✓成对书写并及时缩进常见错误与调试提示14本讲小结编程语言沿“机器语言→汇编→高级语言”不断提高抽象层次;任何语言都由数据、运算、控制、抽象封装四类要素构成;C语言兼具高级语言表达力与硬件控制力,属编译型;C程序以main为唯一入口,经编辑、编译、链接、运行。课后任务完成开发环境安装并截图独立编写并运行Hello程序修改程序输出个人学号姓名故意制造3处错误,记录报错预习第3章:数据类型下一讲第3章C语言基础:数据类型、运算符与输入输出第3章C语言基础数据类型·常量与变量·运算符与表达式·类型转换·输入输出讲授4学时·实验2学时·教材第3章(P20—P44)《C语言程序设计基础与实践》配套课件本讲学习目标1掌握基本数据类型的分类、字节长度与取值范围2掌握常量与变量的定义、命名规则与初始化方法3掌握各类运算符的功能、优先级与结合性4掌握格式化输入输出函数与常用格式控制符的使用第3章C语言基础2本讲导航一条主线:数据怎么存→怎么算→怎么进出程序3.1数据类型整型、实型、字符型的分类与长度3.2常量与变量两种数据载体的定义与使用3.3运算符和表达式赋值、算术、关系、逻辑、条件、sizeof3.4数据类型转换自动转换的规则与强制转换的写法3.5数据的输入与输出printf/scanf与格式控制符第3章C语言基础3数据类型全景3.1数据类型决定了“占多少内存”与“能做什么运算”基本类型整型char/short/int/long实型float/double枚举enum构造类型数组结构体struct共用体union指针类型存放地址,如int*p空类型void,表示“无类型”常用类型速查(32/64位平台)char1字节-128~127int4字节约±21亿longlong8字节约±9.2×10¹⁸float4字节7位有效数字double8字节15位有效数字用sizeof实测最可靠:printf("%d",sizeof(int));3.1数据类型4常量的五种形式3.2.1程序运行过程中其值不能改变的量整型常量10十进制0x1F十六进制(0x开头)017八进制(0开头)实型常量3.14小数形式1.5e3指数形式(=1500)默认按double处理字符常量'A'单引号,仅一个字符'\n''\t''\0'转义字符本质是它的ASCII码值字符串常量"Hello"双引号末尾自动添加'\0'"A"2字节,'A'1字节符号常量#definePI3.14159constdoublePI=3.14;见名知意,便于统一修改记住三点字符单引号,字符串双引号符号常量习惯全大写#define行末不加分号3.2.1常量5变量:先定义,后使用3.2.2变量名是内存单元的别名,类型决定单元的大小intage;//只定义intcount=0;//定义并初始化floatscore=95.5f;chargrade='A';intx=1,y=2,z;//同类型可一起定义

age=20;//赋值未初始化的局部变量,其值是内存中的随机“垃圾值”——务必先赋初值再参与运算。标识符命名规则✓只能由字母、数字、下划线组成✓不能以数字开头✓严格区分大小写:sum≠Sum✓不能使用32个关键字作变量名★见名知意:用score而非sint、if、for、return…均为关键字3.2.2变量6赋值运算符与算术运算符3.3.1—3.3.2最常用,也最容易踩坑算术运算符+-*/%整数相除结果取整:5/2=2要得到2.5需写5.0/2%求余,两侧必须是整数:7%3=1复合赋值运算符a+=3等价于a=a+3同理还有-=*=/=%=赋值号右结合:a=b=5先算b=5自增自减:i++与++i的区别inti=5,j;j=i++;//先取值后自增→j=5,i=6j=++i;//先自增后取值→j=7,i=7单独成句时i++与++i完全等价;一旦出现在表达式中,取值时机不同,结果就不同。切勿在一个表达式中多次改变同一变量,如i=i+++++i,其结果由编译器决定。3.3.1—3.3.2赋值与算术运算符7关系运算符与逻辑运算符3.3.3—3.3.4一切判断的基础:真为1,假为0关系运算符><>=<===!=运算结果只有两个值:成立得1,不成立得0。前四个优先级高于后两个。逻辑运算符&&逻辑与:两侧都真才为真||逻辑或:有一侧真即为真!逻辑非:单目,真假反转短路求值:结果已定,右侧不再计算if(n!=0&&100/n>2)//n为0时右侧不执行,避免除零if(found||search(a,n))//found为真时不再调用searchC语言中“非0即真”:if(x)等价于if(x!=0)。判断相等要用==,写成=就变成了赋值。3.3.3—3.3.4关系与逻辑运算符8条件运算符、sizeof与优先级3.3.5—3.3.6C语言唯一的三目运算符条件运算符?:表达式1?表达式2:表达式3max=(a>b)?a:b;条件为真取表达式2,否则取表达式3。求字节数运算符sizeofsizeof(int)→4sizeof(a)/sizeof(a[0])→数组元素个数它是运算符而非函数,在编译时就得出结果。优先级从高到低(同级看结合性)单目!++-->算术*/%+->关系><==!=>逻辑&&||>条件?:>赋值=+=拿不准时加括号——括号永远优先,且让代码更易读。3.3.5—3.3.6条件运算符与sizeof9数据类型转换3.4自动转换由编译器完成,强制转换由程序员负责自动(隐式)转换:向精度更高的类型看齐char/short→int→unsigned→long→double运算时低类型自动转为高类型,不丢失精度;但赋值给低类型时会截断。强制(显式)转换:(类型名)表达式inta=5,b=2;printf("%f",a/b);//2.000000先整除printf("%f",(float)a/b);//2.500000正确intn=(int)3.99;//n=3直接舍去小数强制转换只影响本次运算,不改变原变量(float)a/b与(float)(a/b)结果不同浮点转整型是直接截断,不是四舍五入3.4数据类型转换10格式化输出printf3.5格式控制符必须与变量类型一一对应printf("格式控制字符串",输出项1,输出项2,...);printf(“学号:%d成绩:%.1f\n",no,score);修饰符让输出更整齐%5d至少占5列,右对齐%-5d左对齐%.2f保留2位小数%8.2f共8列,保留2位小数常用格式控制符%dint十进制整数%ldlong长整型%ffloat/double小数%cchar单个字符%s字符串%x%o十六/八进制%%输出一个百分号3.5.1—3.5.2输出函数与格式控制符11格式化输入scanf3.5输入要的是“地址”,不是“值”intage;floatscore;scanf("%d",&age);//&不可省略scanf("%d%f",&age,&score);charname[20];scanf("%s",name);//数组名本身就是地址取地址符&普通变量前必须加&,数组名除外格式必须匹配double用%lf读入,float用%f不要写\n格式串中的\n会要求用户额外输入空白自动跳过空格、Tab、回车都可作分隔符%c例外%c会读入空白字符,需前加空格:"%c"字符的单独输入输出ch=getchar();逐个读入字符putchar(ch);输出一个字符3.5.1输入输出函数12案例:华氏温度转摄氏温度综合运用变量定义、输入输出、算术运算与类型转换#include<stdio.h>

intmain(void){floatf,c;

printf("请输入华氏温度:");scanf("%f",&f);c=5.0/9*(f-32);//注意5.0printf("摄氏温度为%.2f\n",c);return0;}运行结果请输入华氏温度:100摄氏温度为37.78①定义变量温度有小数,必须用float或double②输入数据scanf中变量前加&③核心运算写5/9结果为0,必须写5.0/9④输出结果%.2f控制小数位数,结果更规范案例学习13本章高频错误这些坑几乎每个初学者都会踩一次整数相除丢失小数✗c=5/9*(f-32);✓c=5.0/9*(f-32);scanf忘记取地址符✗scanf("%d",n);✓scanf("%d",&n);double用错格式符✗scanf("%f",&d);✓scanf("%lf",&d);判等误写成赋值✗if(a=3)✓if(a==3)字符与字符串混用✗charc="A";✓charc='A';常见错误与调试提示14本讲小结数据类型决定存储长度与取值范围,用sizeof可实测;常量的值不可改变,变量必须先定义、先赋值再使用;运算符优先级:单目>算术>关系>逻辑>条件>赋值;整数相除会取整,混合运算时注意自动与强制类型转换;printf/scanf的格式控制符必须与变量类型严格对应。课后任务用sizeof输出各类型字节数编写摄氏转华氏的程序输入三位整数,分离百十个位完成教材第3章课后习题预习第4章:程序控制结构下一讲第4章程序控制结构:顺序、选择与循环第4章程序控制结构顺序·选择·循环·跳转——结构化程序设计的全部积木讲授6学时·实验4学时·教材第4章(P45—P76)《C语言程序设计基础与实践》配套课件本讲学习目标1理解顺序、选择、循环三种基本结构与结构化程序设计思想2掌握if、if-else、elseif与switch语句的语法和适用场合3掌握for、while、do-while三种循环及其相互转换4掌握循环嵌套的执行规律与break、continue的作用范围第4章程序控制结构2本讲导航任何复杂程序,都可以由三种基本结构组合而成4.1C语言的语句五类语句与复合语句的书写规范4.2条件语句if三种形式、switch多分支4.3循环语句for、while、do-while与循环嵌套4.4跳转语句break、continue、goto的作用与取舍结构化程序设计三原则:自顶向下、逐步求精、单入口单出口。第4章程序控制结构3三种基本结构与语句分类4.11966年被证明:三种结构足以描述任何算法顺序结构A→B→C自上而下,逐条执行选择结构条件成立?A:B根据判断走不同分支循环结构条件成立→重复执行重复执行直到条件不成立C语言的五类语句表达式语句sum=a+b;函数调用语句printf("hi");控制语句if/for/while复合语句{...}视为一条空语句;什么也不做凡是语法上要求一条语句的地方,都可以用一对花括号括起的复合语句代替。4.1C语言的语句4if语句的三种形式4.2.1条件为非0即执行/*1.单分支*/if(score>=60)printf("及格\n");

/*2.双分支*/if(score>=60)printf("及格\n");elseprintf("不及格\n");

/*3.多分支elseif*/if(score>=90)grade='A';elseif(score>=80)grade='B';elseif(score>=60)grade='C';elsegrade='D';条件必须加括号if后的表达式一定用()括起非0即为真if(n)等价于if(n!=0)行末不加分号if(x>0);是空语句,等于没判断多条语句加花括号否则只有第一条属于ifelseif自上而下一旦某个条件成立,后面全部跳过4.2.1if语句实现分支结构5if的嵌套与else的配对4.2.1最容易看走眼的地方看似的意图if(a>0)if(b>0)printf("both\n");else//想配a>0printf("a<=0\n");实际的执行if(a>0){if(b>0)printf("both\n");else//实配b>0printf("a<=0\n");}配对规则else总是与它上面最近的、尚未配对的if结合,与缩进无关——编译器不看缩进,只看括号。两条实用建议无论几条语句,一律写花括号嵌套超过三层,改用elseif或拆成函数4.2.1if语句的嵌套6switch多分支语句4.2.2适合“等值判断”,不适合区间判断switch(表达式)//必须是整型或字符型{case常量1:语句组1;break;//跳出switchcase常量2:语句组2;break;default://可选,可放任意位置语句组3;}表达式类型受限只能是int或char,不能是浮点数case后必须是常量不能写casex>60这样的表达式各case值不得重复否则编译报错break决定是否穿透漏写break,会一直执行到下一个break刻意穿透很有用多个case共用一段代码时不写break4.2.2switch语句实现分支结构7案例:成绩等级判定4.2.3同一个问题的两种写法,体会if与switch的取舍写法一:elseif处理区间if(s>=90)g='A';elseif(s>=80)g='B';elseif(s>=70)g='C';elseif(s>=60)g='D';elseg='E';写法二:先把区间变成等值switch(s/10){//关键一步case10:case9:g='A';break;case8:g='B';break;case7:g='C';break;default:g='E';}判断顺序不能颠倒:若把s>=60写在最前,90分也会被判为D。case10后不写语句直接落到case9,这是“刻意穿透”的典型用法。4.2.3案例学习8for语句4.3.1循环次数已知时的首选for(表达式1;表达式2;表达式3)循环体语句;①表达式1初始化,只执行一次②表达式2循环条件,每轮开始前判断③表达式3增量,每轮循环体结束后执行执行顺序:①→②→循环体→③→②→循环体→③……直到②不成立示例:求1~100之和inti,sum=0;for(i=1;i<=100;i++)sum+=i;printf("%d",sum);//5050三个表达式均可省略,但两个分号不能少for(;;)是标准的无限循环写法循环变量在循环外仍可使用4.3.1for语句9while与do-while4.3.2一个先判断再执行,一个先执行再判断while:可能一次都不执行while(条件){循环体;}do-while:至少执行一次do{循环体;}while(条件);//分号不可少三种循环的选用建议for循环次数确定遍历数组、计数累加while次数不定,条件先判断读到文件末尾、迭代求根do-while至少要做一次菜单显示、输入合法性校验三者可以互相转换,选择的依据是“哪种写法最能表达你的意图”。4.3.2while与do-while语句10循环嵌套:九九乘法表4.3.3外层走一步,内层走一轮inti,j;for(i=1;i<=9;i++){//外层:控制行for(j=1;j<=i;j++)//内层:控制列printf("%d*%d=%-3d",j,i,i*j);printf("\n");//换行}运行结果(节选)1*1=11*2=22*2=41*3=32*3=63*3=9……执行总次数外层m次×内层n次内外层变量必须不同都用i会导致外层计数被破坏内层每次重新初始化外层每进一次,j从1开始j<=i是关键写成j<=9就成了完整矩形表4.3.3循环嵌套11案例:素数判断与水仙花数4.3.4循环+标志变量,最经典的两个训练判断n是否为素数inti,flag=1;//标志变量for(i=2;i<=n/i;i++)//只需试到√nif(n%i==0){flag=0;break;//已确定,提前退出}if(flag&&n>1)printf("%d是素数",n);输出全部水仙花数intn,a,b,c;for(n=100;n<=999;n++){a=n/100;//百位b=n/10%10;//十位c=n%10;//个位if(a*a*a+b*b*b+c*c*c==n)printf("%d",n);}解题套路:用标志变量记录“是否发生过某件事”,循环结束后再统一判断;用整除与求余分离数位,是C语言中最常用的数字处理技巧。4.3.4案例学习12跳转语句:break、continue、goto4.4改变循环的正常流程break结束整个循环只跳出它所在的那一层循环;在switch中用于跳出switch。continue结束本次循环跳过循环体的剩余部分,直接进入下一轮的条件判断。goto无条件跳转到标号会破坏程序结构,除多层循环快速退出外不建议使用。同一段代码,一字之差结果迥异for(i=1;i<=5;i++){if(i==3)break;//输出12printf("%d",i);}for(i=1;i<=5;i++){if(i==3)continue;//输出1245printf("%d",i);}4.4跳转语句13案例:成绩统计(跳转语句综合)4.4.4输入-1结束,负分跳过,统计有效成绩的平均分intn=0;doublex,sum=0;

while(1){//无限循环scanf("%lf",&x);if(x==-1)break;//出口:输入-1if(x<0||x>100){printf("无效,已忽略\n");continue;//跳过本次累加}sum+=x;n++;}if(n)printf("平均分%.2f\n",sum/n);①循环控制while(1)配break,适合次数未知②数据校验非法数据用continue跳过,不中断③除零保护if(n)防止一个有效数据都没有④可扩展再加两个变量即可统计最高最低分4.4.4案例学习14本章高频错误这几类错误编译器往往不报错,但结果全错if后误加分号✗if(a>0);✓if(a>0)判等写成赋值✗if(a=3)✓if(a==3)switch漏写break✗case1:x=1;✓case1:x=1;break;多条语句缺花括号✗while(i<5)sum+=i;i++;✓while(i<5){sum+=i;i++;}循环变量未更新✗while(i<5)sum+=i;✓循环体内必须改变i,否则死循环嵌套内外用同一变量✗for(i..)for(i..)✓for(i..)for(j..)常见错误与调试提示15本讲小结顺序、选择、循环三种结构足以描述任何算法;if处理区间判断,switch处理等值判断且勿忘break;else与最近的未配对if结合,写花括号可根治此类问题;for用于次数确定,while用于条件驱动,do-while至少执行一次;break结束整个循环,continue只结束本次循环。课后任务用三种循环分别实现1~100求和输出100以内全部素数打印倒三角形字符图案编写简易菜单(do-while)预习第5章:数组下一讲第5章数组:一维、二维与字符串第5章数组一维数组·二维数组·字符数组与字符串讲授4学时·实验4学时·教材第5章(P77—P106)《C语言程序设计基础与实践》配套课件本讲学习目标1掌握一维数组的定义、初始化、元素引用与内存存储方式2掌握二维数组的定义、初始化及按行存储的规律3理解字符数组与字符串的关系,以及结束标志\0的作用4掌握strlen、strcpy、strcat、strcmp等字符串函数的使用第5章数组2本讲导航为什么需要数组:100个学生成绩,总不能定义100个变量5.1一维数组定义与初始化、使用与存储、排序与查找5.2二维数组定义与初始化、按行存储、矩阵运算5.3字符数组与字符串\0结束标志、输入输出、字符串处理函数数组是一组类型相同、名字相同、用下标区分的变量的集合,在内存中连续存放。第5章数组3一维数组的定义与内存存储5.1.1—5.1.2下标从0开始,元素在内存中连续排列类型名数组名[常量表达式];inta[5];//5个int,共20字节长度必须是常量,不能写inta[n];下标范围是0~4,没有a[5]内存示意:inta[5]={10,20,30,40,50};10a[0]20a[1]30a[2]40a[3]50a[4]地址连续,每格4字节数组名代表首地址a等价于&a[0],是一个地址常量元素与普通变量同权a[2]=35;sum+=a[i];都合法C不检查下标越界a[5]、a[-1]能编译通过,但后果不可预知5.1.1—5.1.2一维数组的定义与存储4初始化的四种写法与遍历5.1.1没有初始化的数组,元素值是随机的inta[5]={1,2,3,4,5};//完全初始化intb[5]={1,2};//其余自动补0intc[]={1,2,3};//长度自动定为3intd[5]={0};//全部清零的惯用法

inte[5]={1,2,3,4,5,6};//错误:初值个数超长遍历:与for循环是天生一对for(i=0;i<5;i++)printf("%d",a[i]);循环条件写i<5而非i<=5,这是初学者最常见的越界来源。用sizeof自动求元素个数,避免硬编码intn=sizeof(a)/sizeof(a[0]);//数组长度变了也不用改循环数组长度一经定义不可改变,这是与后续动态内存分配的最大区别。5.1.1一维数组的定义与初始化5案例:求最大值与冒泡排序5.1.3数组最经典的两个应用求最大值及其下标intmax=a[0],k=0;for(i=1;i<n;i++)if(a[i]>max){max=a[i];k=i;}冒泡排序(升序)for(i=0;i<n-1;i++)//n-1趟for(j=0;j<n-1-i;j++)//每趟比较if(a[j]>a[j+1]){//相邻交换t=a[j];a[j]=a[j+1];a[j+1]=t;}擂台法先假设第一个是最大,再逐个挑战为什么是n-1趟n个数排好n-1个,最后一个自然到位为什么是n-1-i次每趟结束末尾已有i个数归位,无需再比三变量交换必须借助中间变量t,不能直接互赋5.1.3案例学习6案例:折半查找5.1.3前提是数组必须有序——用有序换效率intlow=0,high=n-1,mid,pos=-1;

while(low<=high){mid=(low+high)/2;if(a[mid]==x){pos=mid;break;}elseif(a[mid]>x)high=mid-1;//找左半elselow=mid+1;//找右半}if(pos==-1)printf("未找到");效率对比(100万个数)顺序查找最多1000000次折半查找最多20次每次比较排除一半数据low>high说明查找失败数组无序时结果必然错误用pos记录查找结果、用-1表示“没找到”,是C语言中极为常见的返回值约定。5.1.3案例学习7二维数组:本质是“数组的数组”5.2.1—5.2.2行下标在前,列下标在后,按行连续存储inta[3][4];//3行4列intb[2][3]={{1,2,3},{4,5,6}};//分行初始化,推荐intc[2][3]={1,2,3,4,5,6};//连续初始化intd[][3]={{1},{2}};//行数可省,列数不可a[2][3]的逻辑视图a[0][0]a[0][1]a[0][2]a[1][0]a[1][1]a[1][2]内存顺序:a[0][0]a[0][1]a[0][2]a[1][0]a[1][1]a[1][2]遍历必须用双重循环:外层走行,内层走列for(i=0;i<3;i++){for(j=0;j<4;j++)printf("%4d",a[i][j]);printf("\n");}写成a[i,j]是错的,必须a[i][j]定义时可省行数,列数任何时候都不能省5.2.1—5.2.2二维数组的定义与存储8案例:杨辉三角5.2.3二维数组+递推关系,一次写清inta[10][10]={0},i,j;

for(i=0;i<10;i++){a[i][0]=1;//每行首元素为1a[i][i]=1;//每行末元素为1for(j=1;j<i;j++)a[i][j]=a[i-1][j-1]+a[i-1][j];//递推}for(i=0;i<10;i++){//按三角形输出for(j=0;j<=i;j++)printf("%5d",a[i][j]);printf("\n");}运行结果(前5行)1111211331先定边界首末元素恒为1,是递推的起点再推内部每个数等于上一行的左上与正上之和注意下标i-1、j-1要保证不越界,故j从1开始5.2.3案例学习9字符数组与字符串5.3.1—5.3.2C语言没有字符串类型,用字符数组代替chars1[6]={'H','e','l','l','o','\0'};chars2[6]="Hello";//等价,更常用chars3[]="Hello";//长度自动为6chars4[5]="Hello";//危险:装不下\0"Hello"看起来是5个字符,实际占6个字节——末尾那个看不见的\0才是字符串的灵魂。内存示意:chars[6]="Hello";Hs[0]es[1]ls[2]ls[3]os[4]\0s[5]所有字符串函数都以\0为终点:少了它,函数会一直往后读,直到撞上内存中偶然出现的0。5.3.1—5.3.2字符数组与字符串的存储10字符串的输入与输出5.3.3一个不小心,就是缓冲区溢出scanf("%s",s)遇空格、Tab、回车即停止输入"TomLee"只得到Tomgets(s)可读入整行含空格不检查长度,C11已废弃,禁止使用fgets(s,n,stdin)可读入整行且限制长度安全替代方案,会保留换行符puts(s)/printf("%s")输出到\0为止puts自动换行,printf不换行注意:字符串输入输出时,数组名前不加&——数组名本身就是地址。5.3.3字符串的输入与输出11常用字符串处理函数5.3.4使用前必须#include<string.h>strlen(s)求实际长度不含\0,与sizeof结果不同strcpy(s1,s2)把s2复制给s1s1必须足够大,且不能用=赋值strcat(s1,s2)把s2接到s1之后s1要能容纳合并后的全部字符strcmp(s1,s2)按ASCII逐字符比较返回0相等、正数s1大、负数s1小两个绝不能犯的错误s1=s2;✗应写strcpy(s1,s2);if(s1==s2)✗应写if(strcmp(s1,s2)==0)5.3.4字符串处理函数12案例:字符统计与回文判断5.3.5遍历字符串的两种典型套路(isalpha等需#include<ctype.h>)统计字母、数字、空格与其他inti,le=0,di=0,sp=0,ot=0;for(i=0;s[i]!='\0';i++){if(isalpha(s[i]))le++;elseif(isdigit(s[i]))di++;elseif(s[i]=='')sp++;elseot++;}判断是否为回文串inti=0,j=strlen(s)-1,ok=1;while(i<j){//两端向中间靠if(s[i]!=s[j]){ok=0;break;}i++;j--;}循环条件用\0写s[i]!='\0'比先求strlen更高效双指针法一头一尾同时移动,是字符串处理的通用技巧5.3.5案例学习13本章高频错误数组越界不报错,但足以让程序莫名崩溃下标越界✗for(i=1;i<=n;i++)a[i]✓for(i=0;i<n;i++)a[i]用变量定义长度✗intn=5;inta[n];✓#defineN5→inta[N];字符串用=赋值✗chars[10];s="hi";✓strcpy(s,"hi");字符串用==比较✗if(s1==s2)✓if(strcmp(s1,s2)==0)忘记留\0的位置✗chars[5]="Hello";✓chars[6]="Hello";二维数组省了列数✗inta[][]={...};✓inta[][3]={...};常见错误与调试提示14本讲小结数组是同类型元素的有序集合,下标从0开始、内存连续;数组长度必须是常量,C语言不检查下标越界;二维数组按行存储,定义时行数可省、列数不可省;字符串以\0结尾,chars[6]才装得下"Hello";字符串的赋值与比较必须用strcpy和strcmp。课后任务输入10个成绩,求平均并排序实现折半查找并统计比较次数输出3×3矩阵的转置不用库函数实现strlen与strcpy预习第6章:函数下一讲第6章函数:模块化程序设计的基石第6章函数定义与声明·参数传递·嵌套与递归·作用域与生存期讲授4学时·实验4学时·教材第6章(P107—P128)《C语言程序设计基础与实践》配套课件本讲学习目标1理解函数的作用与自顶向下、逐步求精的模块化设计思想2掌握函数的定义、声明、调用方式与返回值的处理3掌握形参与实参的对应关系及值传递的实质4理解递归的执行过程,以及变量的作用域与生存期第6章函数2本讲导航从“能跑”到“好维护”,函数是第一道分水岭6.1—6.2函数的概述、定义与声明函数首部、函数体、声明的作用6.3—6.4返回语句与函数参数return、形参实参、数组作参数6.5函数的调用三种调用方式、嵌套调用、递归调用6.6—6.7作用域与生存期内部外部函数、局部与全局变量6.8—6.9函数应用与案例学习模块化设计的完整实践第6章函数3为什么需要函数6.1一个500行的main函数,没人愿意读,更没人敢改1避免重复同一段逻辑写一次,处处调用2分而治之大问题拆成若干小问题分别解决3便于维护改一处即可,不必满篇搜索4团队协作接口约定好,可并行开发函数的两大来源库函数由系统提供,如printf、strlen、sqrt;使用前需包含对应头文件。自定义函数由程序员自己编写,本章的主角;main也是一个特殊的自定义函数。6.1函数的概述4函数的定义与声明6.2定义是“造出来”,声明是“打个招呼”返回值类型函数名(形参表)//函数首部{声明部分;执行语句;//函数体return表达式;}intmax(inta,intb)//定义(有函数体){returna>b?a:b;}

intmax(inta,intb);//声明(分号结尾)无参函数写voidintmain(void)比main()更规范无返回值写voidvoidprint(void){...}形参必须逐个写类型不能写成intmax(inta,b)先定义后调用可免声明但把声明统一放在文件开头是好习惯声明只需首部+分号形参名可以省略:intmax(int,int);6.2函数的定义和声明5return语句与返回值6.3函数把结果交还给调用者的唯一出口intis_even(intn){if(n%2==0)return1;//提前返回return0;//兜底返回}一个函数可以有多个return,但只会执行一个return之后的语句永远不会执行void函数可写return;提前结束返回值类型不一致时会自动转换——这往往是bug的源头inthalf(intn){returnn/2.0;}//声明int,实际返回doubleprintf("%d",half(5));//输出2,小数被丢弃doublehalf(intn){returnn/2.0;}//正确写法函数值的类型以定义时声明的返回值类型为准,与return后表达式的类型无关。6.3返回语句6形参与实参:值传递的实质6.4.1传过去的是“复印件”,不是“原件”voidswap(inta,intb){intt=a;a=b;b=t;}intx=1,y=2;swap(x,y);printf("%d%d",x,y);//仍然是12调用瞬间的内存1x2y1a2bmain的x、y与swap的a、b是四块互不相干的内存单向传递实参把值复制给形参,形参怎么改都传不回来形参在调用时才分配内存函数一结束,形参立即消失实参可以是常量或表达式swap(3,x+1)合法;形参必须是变量要想改变实参,必须传地址这正是第7章指针要解决的问题6.4.1形式参数与实际参数7数组作为函数参数6.4.2—6.4.3数组是个例外:传的是首地址,能改回去doubleaverage(inta[],intn)//长度必须另传{inti,sum=0;for(i=0;i<n;i++)sum+=a[i];return(double)sum/n;}average(score,10);//调用时只写数组名形参写inta[]或int*a均可函数内sizeof(a)得不到数组长度在函数中修改a[i],会真正改变原数组main函数的参数:来自命令行intmain(intargc,char*argv[])//argc:参数个数argv:参数字符串数组运行progab时,argc为3,argv[0]是程序名本身。6.4.2—6.4.3数组作参数与main的参数8函数的调用方式与嵌套调用6.5.1—6.5.2函数可以调用函数,但不能定义在函数里三种调用方式语句调用printf("hi");不使用返回值表达式调用c=max(a,b)*2;返回值参与运算参数调用printf("%d",max(a,b));函数值作为另一函数的实参嵌套调用:main→f1→f2,逐层深入再逐层返回main→f1→f2←返回值逐层回传C语言不允许函数嵌套定义——所有函数一律平级。6.5.1—6.5.2函数的调用与嵌套调用9递归调用:函数自己调用自己6.5.3必须有出口,否则栈溢出longfact(intn){if(n<=1)return1;//递归出口returnn*fact(n-1);//递归公式}出口:n<=1时不再往下递公式:把问题化成规模更小的同类问题每层调用都占用独立的栈空间fact(4)的执行过程:先“递”下去,再“归”回来fact(4)=4×fact(3)返回24fact(3)=3×fact(2)返回6fact(2)=2×fact(1)返回2fact(1)=1←出口返回1递去4层,再归来4层,最终得到24。层数过深会耗尽栈空间。6.5.3递归调用10递归案例:斐波那契与汉诺塔6.5.3能用一句话描述的问题,往往三行就能写完斐波那契数列intfib(intn){if(n==1||n==2)return1;returnfib(n-1)+fib(n-2);}汉诺塔voidhanoi(intn,chara,charb,charc){//把n个盘从a经b移到cif(n==1){move(a,c);return;}hanoi(n-1,a,c,b);move(a,c);hanoi(n-1,b,a,c);}递归的优点代码极简,与数学定义一一对应,可读性强递归的代价重复计算多、栈开销大;fib(40)要算十亿次改写为迭代斐波那契用循环只需O(n),效率天差地别何时该用递归问题天然是分治结构,如汉诺塔、树的遍历6.5.3递归调用11局部变量、全局变量与作用域6.6—6.7变量在“哪里能用”和“活多久”是两件事intg=10;//全局变量

voidf(void){intg=20;//局部变量,屏蔽全局printf("%d",g);//输出20}局部变量定义在函数或复合语句内仅在本块内有效函数结束即释放全局变量定义在所有函数之外从定义处到文件末尾程序运行期间一直存在同名时局部优先,全局被临时“遮住”全局变量少用:任何函数都能改,出错难查static局部变量:函数结束仍保留上次的值static函数即内部函数,只能本文件调用6.6—6.7内部外部函数与变量作用域12案例:模块化的成绩统计6.8—6.9main只负责调度,每个函数只做一件事#include<stdio.h>#defineN10

voidinput(inta[],intn);//输入doubleaverage(inta[],intn);//求均分intfindMax(inta[],intn);//求最高voidsort(inta[],intn);//排序

intmain(void){ints[N];input(s,N);printf("均分%.2f\n",average(s,N));printf("最高%d\n",findMax(s,N));sort(s,N);return0;}①自顶向下先想清楚main要调用哪几个功能②一函数一职责函数名就是它做的事,无需注释③接口先行把声明集中写在文件开头④逐步求精再分别实现每个函数并单独测试6.8—6.9函数应用与案例学习13本章高频错误函数写错了,编译器常常只给一句含糊的警告调用前未声明✗main中直接调用后面定义的max✓文件开头写intmax(int,int);形参类型写省略✗intmax(inta,b)✓intmax(inta,intb)定义时误加分号✗intf(void);{...}✓intf(void){...}忘记return或类型不符✗intf(){printf("hi");}✓有返回值类型就必须return以为形参能改实参✗swap(x,y)后x、y不变✓需传地址:swap(&x,&y)递归没有出口✗returnn*fact(n);✓if(n<=1)return1;常见错误与调试提示14本讲小结函数是模块化设计的基本单位,一个函数只做一件事;调用前必须先声明,声明是首部加分号;参数是值传递,形参的改变传不回实参;数组名作参数传递的是首地址,函数内可修改原数组;递归必须有出口,局部变量优先于同名的全局变量。课后任务编写判断素数的函数并调用用函数实现数组排序与查找分别用递归和迭代求斐波那契完成模块化成绩统计程序预习第7章:指针下一讲第7章指针:C语言的灵魂第7章指针地址与指针·指针与数组·指针与函数·动态内存分配讲授6学时·实验4学时·教材第7章(P129—P152)《C语言程序设计基础与实践》配套课件本讲学习目标1理解地址与指针的概念,掌握&与*两个运算符2掌握用指针访问一维数组、二维数组和字符串的方法3掌握指针作函数参数实现“双向传值”,了解函数指针4掌握malloc、free等动态内存分配函数的正确使用第7章指针2本讲导航指针是C语言的灵魂,也是初学者最大的门槛7.1指针与指针变量声明与初始化、基本操作、指针的运算7.2指针与数组一维、二维数组与指针数组7.3指针与函数指针作参数、函数指针7.4二级指针指向指针的指针7.5动态内存分配malloc、free与内存回收第7章指针3地址与指针:从“住址”说起7.1内存的每个字节都有编号,这个编号就是地址inta10地址2000int*p2000地址3000p指向ap里存的不是数据,而是数据所在的位置直接访问:printf("%d",a);间接访问:printf("%d",*p);地址内存单元的编号,如同门牌号指针就是地址的另一种说法指针变量专门用来存放地址的变量7.1.1指针与指针变量4指针变量的定义与两个运算符7.1.1—7.1.2&取地址,*取内容,互为逆运算inta=10;int*p;//定义指针变量,*是标志p=&a;//让p指向aint*q=&a;//定义并初始化,推荐写法

printf("%d",*p);//输出10,间接访问*p=20;//等价于a=20*的两种身份定义时是“这是指针”,使用时是“取内容”类型必须匹配int*只能指向int,不能指向double空指针int*p=NULL;表示“暂时不指向任何地方”野指针最危险未初始化的指针指向随机地址,改写它等于埋雷三个等价关系,务必牢记a≡*p≡*(&a)&a≡p*&a≡a,&*p≡p7.1.1—7.1.2指针变量的声明与基本操作5指针的运算7.1.3p+1不是加1个字节,而是加一个“元素”10a[0]p20a[1]p+130a[2]p+240a[3]50a[4]int*p=a;每加1,地址实际前进sizeof(int)=4个字节p+n/p-n前后移动n个元素常用于遍历数组p++/p--指向下一个/上一个元素注意别越出数组边界p1-p2两指针之间相隔的元素个数仅在同一数组内有意义p1==p2/p1>p2比较两个地址的先后常用于判断是否到达末尾指针之间不能相加、相乘、相除——两个门牌号加起来没有意义。7.1.3指针的运算6指针与一维数组7.2.1数组名就是首元素的地址,四种写法完全等价a[i]≡*(a+i)≡p[i]≡*(p+i)inta[5]={1,2,3,4,5};int*p=a;//等价于p=&a[0]

for(i=0;i<5;i++)printf("%d",*(p+i));//或p[i]a是地址常量,不能写a++p是指针变量,可以写p++用*p++遍历时,先取值再移动正因为数组名是地址,数组作函数参数时传的才是首地址,函数内的修改才能带回来。7.2.1指针与一维数组7指针与二维数组7.2.2a是行指针,a[0]才是列指针——最容易绕晕的一页inta[3][4];a行指针,指向第0行整行a+1跳过一整行(4个int)a[0]或*a列指针,指向元素a[0][0]a[0]+1跳过一个元素*(*(a+i)+j)就是a[i][j]先定位行,再定位列访问a[1][2]的五种等价写法a[1][2]*(a[1]+2)*(*(a+1)+2)(*(a+1))[2]*(&a[0][0]+1*4+2)都指向同一个元素7.2.2指针与二维数组8指针数组与数组指针7.2.3一字之差,天壤之别——关键看括号int*p[5];指针数组本质是数组,有5个元素,每个元素都是int*指针。常用来管理一组字符串。int(*p)[5];数组指针(行指针)本质是指针,只有1个变量,它指向一个含5个int的数组。常用于指向二维数组的某一行。指针数组的典型应用:字符串表char*week[3]={"Mon","Tue","Wed"};printf("%s",week[1]);//输出Tue记忆口诀:先看紧挨着名字的符号——有括号先看括号。7.2.3指针数组9二级指针:指向指针的指针7.4地址也存在内存里,它自然也有地址inta102000int*p20003000int**q30004000q=&p;*q≡p**q≡*p≡ainta=10;int*p=&a;int**q=&p;//二级指针printf("%d",**q);//输出10几个*就要解引用几次指针数组名就是二级指针常用于在函数中修改指针本身7.4二级指针10指针作函数参数7.3.1第6章没能交换成功的swap,这一次可以了值传递:交换失败voidswap(inta,intb){intt=a;a=b;b=t;}

swap(x,y);//x、y原封不动地址传递:交换成功voidswap(int*a,int*b){intt=*a;*a=*b;*b=t;}

swap(&x,&y);//x、y真的交换了本质并没有变——依然是值传递,只不过这次复制过去的“值”是一个地址,顺着它就能找到原变量。一次返回多个结果函数只能return一个值,多个结果靠指针参数带出避免大对象复制传结构体地址比复制整个结构体高效得多只读参数加constvoidf(constint*p)表明函数不会修改它7.3.1指针变量作为函数参数11函数指针7.3.2函数也有入口地址,也可以被“指向”intmax(inta,intb){returna>b?a:b;}

int(*pf)(int,int);//定义函数指针pf=max;//函数名即入口地址printf("%d",pf(3,5));//调用,输出5printf("%d",(*pf)(3,5));//等价写法括号不能省:int*pf(int,int)是函数返回值与参数类型必须完全一致赋值时函数名后不加括号典型用途:把“要做什么”当参数传进去voidprocess(inta[],intn,int(*cmp)(int,int));//传入不

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论