还剩48页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
语言基础教学课件C目录与课程结构入门与环境配置语法基础与核心概念语言简介、计算机基础知识、开发环境搭建、第一个程序编写数据类型、变量、常量、运算符、输入输出函数等基础语法学习C C与运行实操与应用调试与错误总结流程控制、函数、数组、指针、结构体等核心概念的实际应用语言简介C历史与影响•年由贝尔实验室的丹尼斯里奇()开发1972·Dennis Ritchie•最初用于开发操作系统UNIX•被誉为现代编程语言之父•影响了众多后续语言、、等C++Java C#应用领域•操作系统与系统软件开发•嵌入式系统与单片机编程语言创始人丹尼斯里奇•高性能计算与底层驱动程序C·计算机基础与信息表示程序与进程程序是静态的指令集合,进程是程序的执行实例语言程序在运行时会被分配C内存空间,包括代码段、数据段、堆栈等区域二进制与信息编码计算机中所有数据都以二进制形式存储一个字节由位组成,可表byte8bit示的值码是常用的字符编码标准,将字符映射为数值0-255ASCII语言特性C是编译型语言,需要先将源代码转换为机器代码才能执行它是结构化编程语C言,程序由函数组成,具有高效、灵活的特点开发环境搭建推荐开发工具•轻量级编辑器,配合插件可支持语言开发Visual StudioCode C•开源、跨平台的集成开发环境Code::Blocks C/C++•适合初学者的简单Dev-C++IDE•功能强大的商业,学生可免费使用CLion IDE编译器选择•编译器集合,跨平台支持GCC GNU•项目的前端编译器Clang LLVM•微软编译器MSVC VisualC++选择应根据个人需求和操作系统环境进行初学者推荐使用集成度高IDE的,如,可以简化环境配置过程IDE Code::Blocks第一个语言程序示例C#include int main{printfHello,World!\n;return0;}代码结构解析•包含标准输入输出库#include•主函数,程序执行入口编译与运行流程int main•输出函数,显示文本printf创建源文件(文件)
1..c•返回值,表示程序正常结束return0使用编译器将源代码转换为可执行文件
2.运行生成的可执行文件
3.这个简单的程序是学习语言的第一步,展示了程序的基本Hello WorldC C结构编译原理基础预处理阶段处理所有以开头的预处理指令,如展开宏定义、包含头文件内容、条件编译等#输出扩展后的源代码编译阶段将预处理后的代码转换为汇编代码这一阶段会进行语法分析、语义分析和代码优化汇编阶段将汇编代码转换为机器指令,生成目标文件(或文件).o.obj链接阶段将多个目标文件和库文件链接成最终的可执行文件解决外部符号引用,确定函数和变量的最终内存地址语言标准概览C1()C89/C90ANSI C第一个广泛接受的语言标准,奠定了语言的基础大多数现代编译器C C仍然支持这一标准2C99引入了许多新特性变长数组、单行注释、内联函数、新的整数类型//(如)、复数支持、可变参数宏等long long3C11添加了多线程支持、原子操作、通用选择表达式、匿名结构体_Generic和联合体等功能4C17/C18主要是的修订版,修复了一些已知问题,没有添加新的语言特性C11建议初学者使用或更高版本,以便利用更现代的语言特性,同时保持良好的兼容C99性代码风格与命名规范缩进与格式化命名规范•使用一致的缩进通常为个空格或个制表符•标识符只能包含字母、数字和下划线,且不能以数字开头41•大括号风格风格(左括号放在行尾)或风格(左括号•变量名应使用小写字母,多个单词用下划线连接()KR Allmansnake_case独占一行)•常量和宏定义通常使用全大写字母•每行代码控制在个字符以内80-120•函数名通常使用小驼峰式命名法()camelCase•运算符两侧加空格提高可读性•命名要有描述性,避免过于简短或过于冗长良好的代码风格不仅提高了代码的可读性,也减少了错误发生的可能性在团队开发中,遵循一致的代码规范尤为重要注释与代码可读性注释类型//单行注释描述简短的代码行/**多行注释用于较长的解释说明*通常用于函数说明、算法描述等*//***文档注释类似多行注释*但通常用于生成API文档*/典型应用场景•函数头部描述功能、参数、返回值•复杂算法的解释•非显而易见的实现细节•临时解决方案(通常标记为或)注释原则TODO FIXME•注释应说明为什么,而不仅仅是做了什么•避免过度注释明显的代码•更新代码时同步更新相关注释•使用清晰、简洁的语言关键字与保留字数据类型关键字int,char,float,double,void,long,short,signed,unsigned,const,volatile,enum,struct,union,typedef控制流关键字if,else,switch,case,default,for,do,while,break,continue,return,goto存储类关键字auto,register,static,extern其他关键字sizeof,typedef,volatile,inline C99,restrict C99,_Bool C99,_ComplexC99,_Imaginary C99语言有个关键字(标准)和一些在后续标准中添加的关键字这些关键字是语言保留的,C32C89不能用作标识符(如变量名、函数名)理解这些关键字的作用是掌握语言的基础C数据类型综述类型void表示无类型,主要用于函数返回值和通用指针1基本类型2整型、浮点型、逻辑型int,char,short,long float,double_Bool构造类型3数组、结构体、联合体、枚举struct unionenum指针类型4存储内存地址的数据类型,可指向任何其他类型的数据语言提供了丰富的数据类型,可以满足各种数据存储和操作需求选择合适的数据类型有助于提高程序效率和可靠性不同数据类型占用的内存空间C不同,具有不同的值范围常量与变量常量定义方式变量声明与初始化//使用#define宏定义常量#define PI
3.14159//使用const关键字定义常量const doublepi=//声明变量int count;//声明并初始化int age=25;float height=
175.5;//多个变量同时声明
3.14159;//字面常量123//整型常量
1.23//浮点常量A//字符常量ABC//字符串int a,b,c;int x=1,y=2,z=3;常量变量的作用域与生命周期局部变量全局变量静态变量在函数或代码块内部声明的变量,作用域仅在所有函数外部声明的变量,可被程序中的使用关键字声明的变量,保持其值在static限于声明它的函数或代码块内生命周期从任何函数访问生命周期贯穿整个程序执行函数调用之间不变局部静态变量具有局部声明点开始,到所在代码块执行结束时终期间存储在静态数据区作用域但全局生命周期止存储在栈内存中int global_var=100;//全局变void counter{static intvoid func{int local_var=量voidfunc{global_var=count=0;//静态局部变量10;//局部变量//...}//200;//修改全局变量}count++;printf%d\n,local_var在此处被销毁count;}运算符基础算术运算符赋值运算符加减乘除取模基本赋值复合赋值+,-,*,/,%=,+=,-=,*=,/=,%=int a=10,b=3;int sum=a+b;//13int diff=a-b;int x=5;x+=3;//等同于x=x+3,结果为8x*=2;//等同于//7int product=a*b;//30int quotient=a/b;//3整数x=x*2,结果为16除法int remainder=a%b;//1比较运算符逻辑运算符等于不等于大于小于大于等于小于等于逻辑与逻辑或逻辑非==,!=,,,=,=,||,!int p=5,q=10;int result=p==q;//0假result=p intm=5,n=0;int result=mn;//0假result=m q;//1真||n;//1真result=!n;//1真算术表达式与类型转换隐式类型转换当不同类型的数据进行运算时,编译器会自动进行类型转换转换规则遵循较小的类型向较大的类型转换的原则int i=10;float f=
3.5;double d=
2.7;//i会被隐式转换为float,然后进行加法运算floatresult1=i+f;//
13.5//i和f都会被隐式转换为doubledouble result2=i+f+d;//
16.2显式类型转换(类型强制转换)类型提升与数据丢失风险float pi=
3.14159;//强制转换为int,小数部分被截断int int_pi=intpi;//3double x=
1.9;int y=intx+2;//3,而不是
3.9•整型提升小整型在运算时会提升为int•算术转换混合类型运算时向高精度类型转换•从浮点型转换为整型会丢失小数部分•较大的数值类型转换为较小的类型可能导致溢出输入输出函数函数printf用于格式化输出到标准输出设备(通常是屏幕)printfHello,World!\n;//简单字符串输出int age=25;printfAge:%d years\n,age;//带格式说明符的输出float height=
175.5;printfHeight:%.1f cm\n,height;//控制小数位数char grade=A;printfGrade:%c\n,grade;//输出字符函数scanf用于从标准输入设备(通常是键盘)读取格式化输入int num;printfEnter anumber:;scanf%d,num;//注意使用取地址符char name
[50];printfEnter yourname:;scanf%s,name;//字符数组不需要float x,y;printfEnter twonumbers:;scanf%f%f,x,y;//读取多个值常用格式说明符•%d-整型•%f-浮点型(float)•%lf-双精度浮点型(double)•%c-字符•%s-字符串•%x-十六进制•%%-输出百分号%输入输出注意事项输入缓冲区问题使用函数时,输入会先存储在缓冲区中,直到遇到回车才会被读取这可能导致一些常见问题scanf//示例读取整数后读取字符int num;char ch;printf输入一个数字:;scanf%d,num;printf输入一个字符:;scanf%c,ch;//注意%c前有一个空格,用于跳过空白字符常见错误与优化scanf•忘记使用运算符(字符数组例外)•格式说明符与变量类型不匹配•未检查scanf的返回值(表示成功读取的项目数)•缓冲区溢出风险(读取字符串时)//更安全的输入方式char name
[50];printf输入姓名:;scanf%49s,name;//限制最多读取49个字符,留一个给\0//检查返回值int result=scanf%d,num;if如果不加空格,第二个会读取到第一个输入后的回车符scanfresult!=1{printf输入错误!\n;}流程控制条件语句基本语句多分支结构if if-else if-elseint score=85;if score=60if score=90{printf优秀\n;}{printf通过考试!\n;}else if score=80{printf良好\n;}else ifscore=60{printf及格\n;}else{printf不及格\n;}语句if-elseif score=60{printf通过考试!\n;}else{printf未通过考嵌套语句试!\n;}ifif score=60{printf通过考试!\n;ifscore=90{printf并且表现优秀!\n;}}条件语句允许程序根据不同条件执行不同的代码块,是实现程序逻辑的基础条件表达式的结果为非零值时被视为真,为零时被视为假流程控制语句switch基本语法与用法int day=3;switch day{case1:printf星期一\n;break;case2:printf星期二\n;break;case3:printf星期三\n;break;case4:printf星期四\n;break;case5:printf星期五\n;break;case6:printf星期六\n;break;case7:printf星期日\n;break;default:printf无效的日期\n;break;}注意事项流程控制循环结构循环while当条件为真时重复执行代码块适用于事先不知道循环次数的情况int i=1;while i=5{printf%d,i;i++;}//输出:12345循环do-while先执行一次代码块,然后再检查条件确保代码块至少执行一次int j=1;do{printf%d,j;j++;}while j=5;//输出:12345循环for结构更紧凑,适合已知循环次数的情况包含初始化、条件和更新三部分for intk=1;k=5;k++{printf%d,k;}//输出:12345循环结构是程序中重复执行特定任务的基本机制选择适当的循环结构可以使代码更简洁、高效注意避免无限循环,确保循环条件最终会变为假循环嵌套与循环变量循环嵌套示例打印乘法表//打印9x9乘法表for int i=1;i=9;i++{for int j=1;j=i;j++{printf%d×%d=%-3d,j,i,i*j;}printf\n;}与break continue//break示例找到第一个能被7整除的数for int i=1;i=100;i++{if i%7==0{printf找到了%d\n,i;break;//立即退出循环}}//continue示例打印不能被3整除的数for int i=1;i=10;i++{if i%3==0{continue;//跳过本次循环剩余部分}printf%d,i;}//输出:12457810循环变量使用建议•使用有意义的变量名,如count、index等•尽量使用局部变量,减少副作用•避免在循环体内修改循环控制变量•注意变量初始值和边界条件•嵌套循环中使用不同的变量名循环嵌套是指在一个循环内部包含另一个循环,常用于处理二维数据或复杂的迭代逻辑语句用于提前退出整个循环,而语句用于跳过当前迭代的剩余部分,直接进入下一次迭代break continue数组基础数组定义与初始化数组元素访问数组遍历与常见操作//定义数组int scores
[5];//定义一个//访问数组元素(索引从0开始)int first//使用循环遍历数组for int i=0;i可存储5个整数的数组//初始化数组int=numbers
[0];//获取第一个元素,值为5;i++{printf%d,numbers
[5]={10,20,30,40,50};//10int last=numbers
[4];//获取最后numbers[i];}//计算数组元素和int sum部分初始化,未指定的元素默认为0int一个元素,值为50//修改数组元素=0;for int i=0;i5;i++partial
[5]={1,2,3};//等同于{1,numbers
[2]=35;//将第三个元素修改为{sum+=numbers[i];}//查找数组中2,3,0,0}//让编译器根据初始化值确定35的最大值int max=numbers
[0];for int数组大小int auto_size[]={5,10,15,i=1;i5;i++{if numbers[i]20};//大小为4的数组max{max=numbers[i];}}数组是存储同类型数据的连续内存空间在语言中,数组大小必须在定义时确定,且不会进行边界检查,超出范围的访问可能导致程序崩溃或不可预期的行为C多维数组二维数组定义与初始化二维数组访问与遍历//定义3行4列的二维数组int matrix
[3]
[4];//初始化二维数组int grid
[3]
[3]={{1,2,3},{4,5,6},//访问二维数组元素int element=grid
[1]
[2];//获取第2行第3列的元素,值为6//修改二维数组元素grid
[0]
[0]={7,8,9}};//部分初始化int partial
[3]
[3]={{1,2},{4}};//未指定的元素默认为010;//将第1行第1列的元素修改为10//使用嵌套循环遍历二维数组for inti=0;i3;i++{for intj=0;j3;j++{printf%d,grid[i][j];}printf\n;}多维数组的存储多维数组在内存中是按行优先顺序存储的连续空间例如,上面的数组在内存中实际排列为grid1,2,3,4,5,6,7,8,9字符与字符串字符类型与码ASCII//字符变量定义与初始化char ch=A;//字符与ASCII码转换int code=ch;//获取字符A的ASCII码,值为65char character=65;//等同于A//字符运算char next=ch+1;//B,ASCII码为66字符串函数语言提供了头文件,包含许多处理字符串的函数C•strlen-计算字符串长度(不包括结尾的\0)•strcpy-复制字符串•strcat-连接字符串字符串基础•strcmp-比较字符串•strstr-查找子字符串//字符串是以\0空字符结尾的字符数组char greeting
[6]=Hello;//实际占用6个字符H,e,l,l,o,\0//也可以显式包含空字符char greeting2
[6]={H,e,l,l,o,\0};//自#include char str
[20]=Hello;int length=strlenstr;动计算大小包括空字符char auto_size[]=C语言;//5strcatstr,World;//str变为Hello World字符串常见操作字符串复制字符串连接#include char source[]=Hello;char destination
[10];//使用strcpy复制字符串char str1
[20]=Hello;char str2[]=World;//连接两个字符串strcatstr1,str2;strcpydestination,source;//更安全的字符串复制C11标准strncpydestination,//str1变为Hello World//限制连接长度的安全版本strncatstr1,!!!,3;//str1变source,sizeofdestination-1;destination[sizeofdestination-1]=\0;//为Hello World!!!确保以空字符结尾字符串比较格式化字符串chars1[]=apple;chars2[]=banana;int result=strcmps1,s2;//result0char buffer
[50];int age=25;float height=
175.5;//格式化字符串并存储到buffer中表示s1在字典序中排在s2前面//result=0表示s1和s2相等//result0表示s1在字典序中排sprintfbuffer,Age:%d,Height:%.1f,age,height;//buffer现在包含Age:25,在s2后面//比较前n个字符int n_result=strncmps1,s2,3;Height:
175.5//从字符串中提取格式化数据char info[]=Age:30,Height:
180.0;sscanfinfo,Age:%d,Height:%f,age,height;//现在age=30,height=
180.0指针概念指针基础定义指针与数组指针是一种特殊的变量,用于存储内存地址通过数组名实际上是指向数组第一个元素的指针常量指针,可以间接访问和修改其他变量的值//指针声明int*ptr;//声明一个指向int numbers
[5]={10,20,30,40,整型的指针//获取变量的地址int number=50};int*p=numbers;//p指向数组的10;ptr=number;//ptr现在存储第一个元素//通过指针访问数组元素number的内存地址//通过指针访问变量的值printf%d\n,*p;//解引用int value=*ptr;//value=10printf%d\n,*p+1;//10//通过指针修改变量的值*ptr=20;20printf%d\n,*p+2;//30//指//现在number=20针运算p++;//p现在指向第二个元素printf%d\n,*p;//20指针是语言中最强大也最容易出错的特性之一它提供了对内存的直接操作能力,是实现高效算法和复杂C数据结构的基础但不当使用可能导致内存泄漏、程序崩溃等问题指针实用技巧字符串指针与字符数组//字符数组可修改char str1
[10]=Hello;str1
[0]=h;//合法操作//字符串指针指向常量字符串char*str2=World;//str2
[0]=w;//非法操作,可能导致程序崩溃//动态分配字符串可修改char*str3=char*malloc10;strcpystr3,Dynamic;str3
[0]=d;//合法操作freestr3;//不要忘记释放内存指针运算常见指针陷阱int arr
[5]={10,20,30,40,50};int*p=arr;//指针加法printf%d\n,*p+2;//30//指针减法•未初始化指针使用前必须指向有效内存printf%d\n,*p+4-2;//30//指针比较if pp+3{printfp指向的位置在p+3之前\n;}•内存泄漏忘记释放动态分配的内存•悬空指针指向已释放的内存•越界访问超出分配范围的内存访问•NULL指针解引用尝试访问NULL指针指向的内容//避免NULL指针解引用int*ptr=NULL;if ptr!=NULL{*ptr=10;//安全检查}指针与函数通过指针修改外部变量返回多个值函数指针//交换两个整数的值void swapint*a,//计算矩形的面积和周长void//定义一个函数类型int addint a,intint*b{int temp=*a;*a=calculateint length,int width,int b{return a+b;}int*b;*b=temp;}int x=5,y=*area,int*perimeter{*area=subtractint a,int b{return a10;swapx,y;//调用后,x=10,y=5length*width;*perimeter=2*-b;}//声明并使用函数指针intlength+width;}int area,*operationint,int;operation=perimeter;calculate5,3,area,add;int result1=operation5,3;perimeter;//调用后,area=15,//调用add,结果为8operation=perimeter=16subtract;int result2=operation5,3;//调用subtract,结果为2指针作为函数参数可以实现语言中的引用传递,允许函数修改调用者的变量函数指针允许在运行时选择要调用的函数,是实现回调机制和动态行为的基础C函数基础函数声明与定义//函数声明原型int addinta,int b;//函数定义int addinta,int b{return a+b;}//调用函数int result=add5,3;//result=8参数传递机制//值传递函数内对参数的修改不影响原变量void incrementintx{x++;//只修改局部副本}int num=10;incrementnum;//num仍然为10//指针传递函数可以修改原变量void incrementByPointerint*x{*x++;//修改指针指向的值}incrementByPointernum;//num变为11返回值与函数void//带返回值的函数int squareintx{return x*x;}//void函数不返回值void printMessagechar*msg{printf%s\n,msg;//无需return语句}//提前返回int findMaxintarr[],int size{if size=0{return-1;//错误情况提前返回}int max=arr
[0];for inti=1;isize;i++{if arr[i]max{max=arr[i];}}return max;}递归函数递归基本结构递归函数是调用自身的函数一个良好的递归函数应包含
1.基本情况(终止条件)不再递归调用的情况
2.递归情况将问题分解为更小的子问题//递归计算阶乘int factorialint n{//基本情况if n=1{return1;}//递归情况return n*factorialn-1;}斐波那契数列//递归计算斐波那契数列int fibonacciint n{if n=0{return0;}if n==1{return1;}return fibonaccin-1+fibonaccin-2;}递归与循环的对比•递归优点代码更简洁清晰,特别适合处理树形结构•递归缺点占用更多内存,可能导致栈溢出,效率通常低于循环•许多递归算法可以通过动态规划优化,避免重复计算//循环实现斐波那契数列更高效int fibIterativeint n{if n=0return0;if n==1return1;inta=0,b=1,c;for inti=2;i=n;i++{c=a+b;a=b;b=c;}return b;}宏与预处理指令常量与宏函数条件编译#define//定义常量宏#define PI
3.14159#define MAX_SIZE100//定义宏函数#define SQUARExx*x#define MAXa,b ab//条件编译#define DEBUG#ifdef DEBUGprintfDebug模式x=%d\n,x;#else printfRelease模式运行\n;#endif//避免重复包a:b//使用宏double area=PI*SQUAREradius;int max_value=MAX10,20;含#ifndef MY_HEADER_H#define MY_HEADER_H//头文件内容#endif//其他预处理指令#if definedWIN32//Windows特定代码#elifdefinedLINUX//Linux特定代码#else//其他平台代码#endif注意宏函数中的参数应用括号括起来,避免优先级问题文件包含#include//包含标准库头文件#include#include//包含自定义头文件#include myheader.h结构体结构体定义与声明//定义结构体类型struct Student{char name
[50];int id;float gpa;};//声明结构体变量struct Students1;//定义并初始化struct Students2={张三,10001,
3.8};访问结构体成员//点运算符访问成员s
1.id=10002;strcpys
1.name,李四;s
1.gpa=
3.5;//结构体指针访问成员struct Student*ptr=s1;ptr-id=10003;//等价于*ptr.id=10003printf学生姓名:%s\n,ptr-name;结构体数组与嵌套//结构体数组struct Studentclass
[30];class
[0].id=10001;class
[1].id=10002;//嵌套结构体struct Date{int year,month,day;};struct Employee{char name
[50];int id;struct Datebirthdate;struct Datehiredate;};struct Employeee1;e
1.birthdate.year=1995;e
1.hiredate.year=2020;枚举类型枚举定义与使用//定义枚举类型enum Weekday{Monday,//默认值为0Tuesday,//1Wednesday,//2Thursday,//3Friday,//4Saturday,//5Sunday//6};//声明枚举变量enum Weekdaytoday=Wednesday;//比较枚举值if today==Wednesday{printf今天是星期三\n;}//显式指定枚举值enum Month{January=1,//从1开始February,//2March,//3//...December=12};枚举的应用场景•表示一组相关的常量值,提高代码可读性•定义状态机的状态•表示选项或标志•替代#define定义多个相关常量//状态机示例enum State{IDLE,RUNNING,PAUSED,STOPPED,ERROR};enum Statecurrent_state=IDLE;//状态转换switch current_state{case IDLE:current_state=RUNNING;break;case RUNNING:current_state=PAUSED;break;//...}联合与共用体联合体定义与使用联合体特点•所有成员共享同一块内存空间//定义联合体union Data{inti;float f;char str
[20];};//声明联合体变量union Datadata;//使用联合体data.i=•一次只能使用一个成员10;printf整数值%d\n,data.i;data.f=
3.14;printf浮点值%f\n,data.f;//注意此时data.i的值已经被覆盖strcpydata.str,C语言;printf字符串%s\n,data.str;//同样,之前的值都被覆盖•联合体大小等于最大成员的大小•用于节省内存空间典型应用场景//节省内存的数据结构struct Variant{enum{INT,FLOAT,STRING}type;union{inti;float f;char*s;}value;};struct Variantv;v.type=INT;v.value.i=42;类型别名typedef基本用法简化复杂类型声明提高代码可读性和可移植性//为基本类型定义别名typedef//数组类型别名typedef int//平台相关类型typedef unsignedunsignedlong ulong;ulong count=IntArray
[10];IntArray numbers;char BYTE;typedef unsignedshort1000000;//为结构体定义别名typedef//等同于int numbers
[10];//函数WORD;typedef unsignedlongstruct{char name
[50];int指针类型别名typedef intDWORD;//数据结构相关类型typedefage;}Person;//使用别名创建变量*MathFuncint,int;int addint struct Node{int data;Person p1={张三,25};a,int b{return a+b;}intstructNode*next;}Node;//创建链subtractint a,int b{return a表节点Node*head=Node-b;}MathFunc operation=*mallocsizeofNode;add;int result=operation5,3;//result=8是语言中用于创建类型别名的关键字,可以使代码更简洁、更易读,特别是对于复杂的数据类型声明它不创建新类型,只是为现有类型提供新的名称typedef C动态内存分配基本内存函数#include//malloc-分配指定大小的内存块int*p1=int*malloc5*sizeofint;//分配5个整数大小的内存,返回指向第一个字节的指针//calloc-分配并清零内存int*p2=int*calloc5,sizeofint;//分配5个整数大小的内存,并初始化为0//realloc-调整已分配内存的大小p1=int*reallocp1,10*sizeofint;//将p1指向的内存扩展为10个整数大小//free-释放内存freep1;freep2;//释放不再使用的内存常见错误动态内存使用示例•内存泄漏忘记调用free释放内存•悬空指针使用已释放的内存//动态创建整数数组int size;printf输入数组大小:;scanf%d,size;int*arr=int*mallocsize•缓冲区溢出访问超出分配范围的内存*sizeofint;if arr==NULL{printf内存分配失败\n;return1;}//使用数组for inti=•重复释放对同一内存区域多次调用free0;isize;i++{arr[i]=i*2;}//释放内存freearr;arr=NULL;//避免悬空指针文件操作文件打开与关闭文本文件读写二进制文件读写#include//打开文件FILE*fp;fp=//字符读写int ch;while ch=fgetcfp!=//写入结构体struct Person{charfopendata.txt,r;//只读模式if fp==EOF{putcharch;}//行读写char name
[50];int age;};struct Personp={NULL{printf无法打开文件\n;line
[100];while fgetsline,sizeofline,李四,30};FILE*fp=fopenperson.dat,return1;}//文件处理...//关闭文件fclosefp;fp!=NULL{printf%s,line;}//格式wb;fwritep,sizeofstruct Person,1,化读写int id;char name
[50];float score;FILE fp;fclosefp;//读取结构体struct Person*outfp=fopenstudents.txt,p2;fp=fopenperson.dat,rb;freadp2,w;fprintfoutfp,%d%s%.2f\n,1001,sizeofstruct Person,1,fp;fclosefp;张三,
85.5;fcloseoutfp;FILE*infp=fopenstudents.txt,r;fscanfinfp,%d%s%f,id,name,score;fcloseinfp;常用文件模式•r-只读•w-写入(创建新文件或覆盖)追加•a-•r+-读写•b-二进制模式(如rb、wb)错误处理与断言与错误处理errno#include#include#include#include FILE*fp=fopennonexistent.txt,r;if fp==NULL{//获取错误代码int err=errno;//打印错误信息printf错误码:%d\n,err;printf错误信息:%s\n,strerrorerr;//或者直接使用perror perror文件打开失败;exitEXIT_FAILURE;}断言常见错误码#include voidprocess_dataint*data,int size{//验证参数有效性assertdata!=NULL;assertsize•ENOENT-文件或目录不存在0;//处理数据...}//可以在发布版本中禁用断言#define NDEBUG//放在include assert.h之前#include//现在所有•EACCES-权限被拒绝assert语句都被忽略•ENOMEM-内存不足•EINVAL-无效参数返回值判错策略//标准函数错误检查FILE*fp=fopendata.txt,r;if fp==NULL{//处理错误}//自定义函数错误处理int result=some_function;if result0{//处理错误}语言项目结构C多文件项目组织头文件与源文件关系模块化设计实践典型的C项目包含以下文件类型头文件module.h示例•单一职责原则每个模块负责一个功能领域•头文件.h包含函数原型、结构体定义、常量等•信息隐藏实现细节封装在源文件中•源文件.c包含函数实现#ifndef MODULE_H#define MODULE_H//结构体定义struct Point•接口设计头文件提供清晰的API{double x,y;};//函数原型double distancestruct Point•主程序文件包含main函数的源文件•避免循环依赖合理组织模块间关系p1,struct Pointp2;void print_pointstruct Point•构建文件Makefile或其他构建脚本p;#endif/*MODULE_H*/•使用头文件保护(include guards)避免重复包含项目目录结构示例project/├──include/#头文件目录│├──module
1.h│└──module
2.h├──src/#源文件目录│├──module
1.c│├──module
2.c│└──main.c├──lib/#库文件目录├──build/#构建输出目录└──Makefile#构建脚本源文件示例module.c#include#include#include module.h//函数实现doubledistancestruct Pointp1,structPointp2{returnsqrtpowp
2.x-p
1.x,2+powp
2.y-p
1.y,2;}voidprint_pointstruct Pointp{printf%f,%f\n,p.x,p.y;}经典算法案例排序1冒泡排序插入排序void bubble_sortint arr[],int n{for inti=0;in-1;i++{for intj=0;jn-i-1;j++void insertion_sortint arr[],intn{for inti=1;in;i++{int key=arr[i];intj=i-{if arr[j]arr[j+1]{//交换元素int temp=arr[j];1;while j=0arr[j]key{arr[j+1]=arr[j];j--;}arr[j]=arr[j+1];arr[j+1]=temp;}}}}arr[j+1]=key;}}时间复杂度On²时间复杂度On²,但在接近有序的数据上表现较好选择排序void selection_sortint arr[],intn{for inti=0;in-1;i++{int min_idx=i;for intj=i+1;jn;j++{if arr[j]arr[min_idx]{min_idx=j;}}//交换元素int temp=arr[i];arr[i]=arr[min_idx];arr[min_idx]=temp;}}时间复杂度On²经典算法案例查找2顺序查找int linear_searchint arr[],intn,int target{for inti=0;in;i++{if arr[i]==target{return i;//返回目标元素的索引}}return-1;//未找到目标元素}时间复杂度On适用场景适用于未排序的数组,或数据量较小的情况二分查找int binary_searchint arr[],int left,int right,int target{while left=right{int mid=left+right-left/2;//找到目标元素if arr[mid]==target{return mid;}//在左半部分继续查找if arr[mid]target{right=mid-1;}//在右半部分继续查找else{left=mid+1;}}return-1;//未找到目标元素}时间复杂度Olog n语言常用标准库C标准输入输出标准实用函数stdio.h-stdlib.h-•printf,scanf-格式化输入输出•malloc,calloc,realloc,free-内存管理文件操作随机数生成•fopen,fclose-•rand,srand-•fread,fwrite-二进制文件读写•atoi,atof-字符串转数值•fprintf,fscanf-文件格式化读写•qsort-快速排序•fgets,fputs-行读写•abs,labs-绝对值•fgetc,fputc-字符读写•exit-程序终止字符串处理数学函数string.h-math.h-•strlen-计算字符串长度•sin,cos,tan-三角函数•strcpy,strncpy-字符串复制•sqrt-平方根•strcat,strncat-字符串连接•pow-幂运算•strcmp,strncmp-字符串比较•exp,log,log10-指数和对数•strstr-查找子字符串•floor,ceil-向下和向上取整•memcpy,memmove-内存复制•fabs-浮点数绝对值其他常用标准库•time.h-时间和日期函数•ctype.h-字符类型判断和转换•limits.h-数据类型限制断言功能•assert.h-调试与常见错误总结编译错误与警告编译错误程序无法编译成可执行文件•语法错误缺少分号、括号不匹配等•未声明的标识符使用前未声明变量或函数•类型不匹配如将字符串赋值给整型变量编译警告可能导致问题的代码•未使用的变量•隐式类型转换可能导致精度丢失•使用了废弃的函数运行时错误•段错误(Segmentation Fault)访问无效内存•除零错误被零除•内存泄漏申请的内存未释放•堆栈溢出递归过深或局部变量过多•数组越界访问超出数组范围的元素•空指针解引用尝试通过NULL指针访问内存使用调试器调试器(如)的基本功能GDB•设置断点在特定行停止程序执行•单步执行逐行运行程序•查看变量检查变量的当前值•查看调用栈了解函数调用关系•条件断点满足特定条件时停止•核心转储分析程序崩溃后分析错误调试是编程过程中不可或缺的环节良好的调试习惯包括添加调试输出、使用断言检查假设、分阶段测试代码,以及系统地排除可能的错误原因编程规范与工程实践代码组织原则大型项目管理•单一职责每个函数只做一件事大型C项目的路径设置•低耦合高内聚减少模块间依赖•DRY原则不要重复自己project/├──include/#公共头文件├──src/#源代码│├──module1/│├──module2/│└──main/├──lib/#第三方库├──test/#测试代码├──doc/#文档├──build/#构建产物└──•KISS原则保持简单scripts/#构建脚本•分层设计将系统分为多个抽象层模块化和代码复用模块化设计步骤
1.确定模块边界和职责
2.设计清晰的API(函数原型)
3.实现模块功能
4.编写文档和测试代码复用策略宏管理技巧•创建通用函数库•使用前缀避免命名冲突•使用回调函数实现通用算法•避免在头文件中使用#define•参数化设计,提高灵活性•使用枚举代替宏定义常量•合理使用条件编译语言与其他语言对比C语言C C++•过程式编程语言•C的超集,支持面向对象编程•直接操作内存•提供类、继承、多态等特性•编译为机器代码,执行效率高•有标准模板库STL•无垃圾回收,需手动管理内存•保留了C的内存控制能力•低级语言,接近硬件•语法更复杂,学习曲线较陡•适用于系统编程、嵌入式系统•适用于大型应用、游戏开发Java Python•纯面向对象语言•解释型、高级脚本语言•自动内存管理垃圾回收•动态类型,简洁的语法•跨平台一次编写,到处运行•强大的标准库和第三方包•运行在Java虚拟机JVM上•支持多种编程范式•丰富的标准库和框架•执行速度较慢但开发效率高•适用于企业级应用、Android开发•适用于数据分析、Web开发、人工智能了解不同编程语言的特点和适用场景,有助于根据项目需求选择合适的工具语言虽然诞生已久,但因其效率和对硬件的控制能力,在特定领域仍然不可替代C典型习题精选及解析1变量与运算表达式//问题计算圆的面积和周长//输入圆的半径r//输出面积和周长#include#define PI
3.14159int main{float radius,area,circumference;printf请输入圆的半径:;scanf%f,radius;area=PI*radius*radius;circumference=2*PI*radius;printf圆的面积为:%.2f\n,area;printf圆的周长为:%.2f\n,circumference;return0;}条件与循环结构//问题打印九九乘法表#include intmain{for inti=1;i=9;i++{for intj=1;j=i;j++{printf%d×%d=%-3d,j,i,i*j;}printf\n;}return0;}知识点变量声明、常量定义、算术表达式、格式化输出知识点嵌套循环、格式化输出、算术运算//问题判断是否为闰年//规则能被4整除但不能被100整除,//或者能被400整除的年份是闰年boolisLeapYearint year{return year%4==0year%100!=0||year%400==0;}典型习题精选及解析2字符串与数组操作函数与指针综合应用//问题反转字符串#include#include voidreverse_stringchar*str{int length=strlenstr;inti,j;char temp;//问题使用指针交换两个数组#include#include voidswap_arraysint*arr1,int*arr2,int size{for inti=0;isize;for i=0,j=length-1;ij;i++,j--{temp=str[i];str[i]=str[j];str[j]=temp;}}inti++{int temp=arr1[i];arr1[i]=arr2[i];arr2[i]=temp;}}intmain{int size=5;intmain{char text
[100];printf请输入一个字符串:;getstext;//注意实际应用中应使用fgets更安全array1[]={1,2,3,4,5};int array2[]={10,20,30,40,50};printf交换前:\n;printf数组1:;forreverse_stringtext;printf反转后的字符串:%s\n,text;return0;}inti=0;isize;i++printf%d,array1[i];printf\n数组2:;for inti=0;isize;i++printf%d,array2[i];swap_arraysarray1,array2,size;printf\n交换后:\n;printf数组1:;forint i=0;isize;i++printf%d,array1[i];printf\n数组2:;for inti=0;isize;i++printf%d,array2[i];return0;}知识点字符数组、指针、字符串函数、循环常用测试与评测工具在线编程平台这些平台提供了编程练习环境,可以直接在浏览器中编写、编译和运行代码C•LeetCode提供算法和数据结构题目,有详细解析•CodeForces竞技编程平台,有大量比赛和练习题•HackerRank各种难度的编程题,从基础到高级•牛客网国内平台,有大量面试题和编程练习•PAT ProgrammingAbility Test浙江大学开发的编程能力测试系统代码质量工具这些工具帮助分析代码质量、发现潜在问题•Valgrind内存错误检测工具,可发现内存泄漏•Cppcheck静态代码分析工具,查找不使用编译器检查的错误•Splint详细的静态检查工具•GCC警告选项使用-Wall-Wextra等选项开启更多警告•AddressSanitizer检测内存错误的运行时工具单元测试框架这些框架帮助创建和运行自动化测试•UnityC语言的轻量级单元测试框架•CheckC语言的单元测试框架•CUnit功能齐全的C测试框架•GoogleTest虽然主要用于C++,但也可用于C善用这些工具可以帮助提高编程能力和代码质量对于初学者,在线判题系统是练习的好去处;对于更专业的开发,静态分析和单元测试工具是保证代码质量的关键课程小结与学习建议核心知识点回顾•C语言基础数据类型、运算符、流程控制•复杂数据结构数组、指针、结构体•内存管理动态分配、指针操作•模块化编程函数、头文件、项目结构•文件操作与错误处理进阶学习建议推荐书籍•《C程序设计语言》(KR)-经典著作•《C和指针》-深入理解指针•《C陷阱与缺陷》-避免常见错误•《数据结构与算法分析》-算法实现学习平台•Coursera、edX上的C语言课程•GitHub上的开源项目•Stack Overflow解决具体问题实战与面试准备项目实践•实现简单数据结构(链表、栈、队列)•编写小型工具程序(文件处理、简单游戏)•参与开源项目贡献面试准备•掌握常见算法和数据结构•理解内存管理机制•熟悉常见C语言问题和解决方案•练习编码和调试技能语言学习是一个循序渐进的过程,打好基础后再挑战高级主题实践是最好的学习方法,多写代码、多调试、多思考祝愿所有学习者在编程的道路上取得成功!C。
个人认证
优秀文档
获得点赞 0