C语言软件编程经验交流ppt课件

上传人:s9****2 文档编号:567623795 上传时间:2024-07-21 格式:PPT 页数:68 大小:2.14MB
返回 下载 相关 举报
C语言软件编程经验交流ppt课件_第1页
第1页 / 共68页
C语言软件编程经验交流ppt课件_第2页
第2页 / 共68页
C语言软件编程经验交流ppt课件_第3页
第3页 / 共68页
C语言软件编程经验交流ppt课件_第4页
第4页 / 共68页
C语言软件编程经验交流ppt课件_第5页
第5页 / 共68页
点击查看更多>>
资源描述

《C语言软件编程经验交流ppt课件》由会员分享,可在线阅读,更多相关《C语言软件编程经验交流ppt课件(68页珍藏版)》请在金锄头文库上搜索。

1、C语言软件编程之经验交流1这次报告比较局限于C语言,不会讲太多其他高级语言比如C+,JAVA,PYTHON等等,刚进实验室的学生我的建议是先学好C语言,掌握项目开发中软件的开发目的,开发流程,测试流程等。注意,做这个报告的目的是希望大家能够开发出高效的C程序,而不是让大家开发出复杂高难度高技巧的C程序。报告目的2提纲一、C语言基础二、内存管理三、常用技巧四、调试五、示例3开发软件工欲善其事,必先利其器-论语牢牢打好基础,紧紧抓住核心,真正实现目的-深入学习科学发展观编辑软件:VC+6.0,VS20XX编程辅助软件:msdn功能性辅助软件:vcassistant,numegaboundschec

2、ker,intelvtune,sourceinsight推荐的资料:高质量C/C+编程指南(林锐)、Windows核心编程、linux高级程序设计4一、C语言基础在C语言中使用的词汇分为六类:标识符,关键字,运算符,分隔符,常量,注释符。1.1.1C语言词汇5标识符只能是字母、数字、下划线组成的字符串,并且其第一个字符必须是字母或下划线。以下标识符是合法的:a,x,_3x,BOOK_1,sum5以下标识符是非法的:3s以数字开头;s*T出现非法字符*;-3x以减号开头;(1)标识符一、C语言基础6在使用标识符时注意以下几点:标准C不限制标识符的长度,但它受各种版本的C语言编译系统限制,同时也受

3、到具体机器的限制;在标识符中,大小写是有区别的。例如BOOK和book是两个不同的标识符;标识符虽然可由程序员随意定义,但标识符是用于标识某个量的符号。因此,命名应尽量有相应的意义,以便阅读理解,作到“顾名思义”。intImgWidth;(1)标识符一、C语言基础71、匈牙利命名法:开头字母用变量类型的缩写,其余部分用变量的英文或英文的缩写,要求单词第一个字母大写。intiMyAge;“i”是int类型的缩写;charcMyName10;“c”是char类型的缩写;floatfManHeight;“f”是float类型的缩写;2、驼峰规则:又叫小驼峰式命名法。第一个单词首字母小写,后面其他单词

4、首字母大写。intmyAge;charmyName10;floatmanHeight;3.帕斯卡命名法:又叫大驼峰式命名法。每个单词的第一个字母都大写。intMyAge;charMyName10;floatManHeight;一、C语言基础8关键字是由语言规定的具有特定意义的字符串,通常也称为保留字。用户定义的标识符不应与关键字相同。C语言的关键字分为以下几类:(2)关键字一、C语言基础类型说明符用于定义、说明变量、函数或其它数据结构的类型。如char,short,int,double等语句定义符用于表示一个语句的功能。如for,if,else,while,switch等。预处理命令字用于表示

5、一个预处理命令。如#define#pragma等。9C语言中运算符与变量,函数一起组成表达式,表示各种运算功能。运算符由一个或多个字符组成,如,=,&等。(3)运算符(4)分隔符在C语言中采用的分隔符有逗号和空格两种。一、C语言基础10(5)常量C语言中使用的常量可分为数字常量、字符常量、字符串常量、符号常量、转义字符等多种。比如char*p=“helloworld”;C语言中的常量是不接受程序修改的固定值。(6)注释符C语言的注释符是以“/*”开头并以“*/”结尾的串,C+中使用“/”注释所在行。一、C语言基础11什么是字节对齐,为什么要字节对齐?1.1.2字节对齐一、C语言基础12(1)什

6、么是字节对齐?现代计算机中内存空间都是按照byte划分的,从理论上讲对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。一、C语言基础13(2)为什么要字节对齐?对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台的要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位)如果存

7、放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该int数据。一、C语言基础14(3)大小端(例程)在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。对于位数大于8位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中一、C语言基础15(3)大小端(例程)写一个

8、C函数,若处理器是Big_endian的,则返回0;若是Little_endian的,则返回1intcheckCPU()unionwinta;charb;c;c.a=1;return(c.b=1);一、C语言基础16(3)大小端(例程)采用Little-endian模式的CPU对操作数的存放方式是从低字节到高字节,而Big-endian模式对操作数的存放方式是从高字节到低字节序是所有成员都从低地址开始存放。联合体union的存放顺序是所有成员都从低地址开始存放。一、C语言基础17/作者版权版本说明,头文件声明,全局变量,函数声明,预处理块#include#include”global.h”vo

9、idoutput();/子函数声明intmain(intargc,char*argv)inti,j;unsignedchar*data;/定义局部变量/分配数据空间,分配在堆上data=(unsignedchar*)malloc(1000*sizeof(unsignedchar);for(i)/调用子函数output();/释放分配空间free(data);data=NULL;voidoutput()一、C语言基础18#ifndefGRAPHICS_H(作用:防止graphics.h被重复引用)#defineGRAPHICS_H#include.(作用:引用标准库的头文件)#include.(

10、作用:引用非标准库的头文件)voidFunction1(.);(作用:全局函数声明)classBox(作用:类结构声明);#endif1.2.1头文件一、C语言基础19在头文件中,用ifndef/define/endif结构产生预处理块,用#include格式来引用库的头文件。头文件一般由三部分内容组成:1.2.1头文件头文件开头处的版权和版本声明;预处理块;函数和类结构声明等。一、C语言基础20头文件的主要作用在于调用库功能,对各个被调用函数给出一个描述,其本身不包含程序的逻辑实现代码,它只起描述性作用,告诉应用程序通过相应途径寻找相应功能函数的真正逻辑实现代码。用户程序只需要按照头文件中的

11、接口声明来调用库功能,编译器会从库中提取相应的代码。1.2.1头文件一、C语言基础21注意:1)在.h文件中声明的函数,如果在其对应的.c文件中有定义,那么我们在声明这个函数时,不使用extern修饰符,如果反之,则必须显示使用extern修饰符;2)不要在.h文件中编写实现代码,不要#include“.c”文件。1.2.1头文件一、C语言基础22所有全局变量尽量以g_开头,并且尽可能声明成static类型;尽量杜绝跨文件访问全局变量.如果的确需要在多个文件内访问同一变量,应该由该变量定义所在文件内提供GET/PUT函数实现;全局变量必须要有一个初始值,全局变量尽量放在一个专门的函数内初始化;

12、如调用全局变量的函数少于三个,考虑改为局部变量实现。1.2.2谨慎使用全局变量一、C语言基础23在实际的软件项目中,每个人负责的可能只是一个模块,对全局变量的使用没有小程序那样简单,在使用全局变量的时候更要谨慎,跨模块调用的全局变量使用时都需要申请,而且定义必须明确。1.2.2谨慎使用全局变量一、C语言基础24voidmain(intargc,char*argv)1.2.3main函数一、C语言基础命令行界面的程序,通常都需要输入命令行参数帮助程序执行。假定有一个可执行程序名为test.exe。运行该程序的的命令行如下:test.exe带命令行参数是同一行中的附加项:test.execTEST

13、其中c和TEST就是命令行参数。C程序通过使用main()的参数来读取这些附加参数。25main(intargc,char*argv)这个函数中两个参数的意义:argc记录的是命令行中输入参数的数目;argv是一个拥有argc个元素的字符串数组,每个元素保存一个命令行中输入的参数。1.2.3main函数一、C语言基础26#includeintmain(intargc,char*argv)inti;for(i=0;iargc;i+)printf(Argument%dis%s.n,i,argvi);return0;1.2.3main函数一、C语言基础下面的程序演示argc和argv的使用:27Ar

14、gument0ishello.exe.Argument1isa.Argument2isb.Argument3isc.Argument4isd.Argument5ise.1.2.3main函数一、C语言基础运行结果:假如上述代码编译为hello.exe,那么运行:hello.exe a b c d e 281.2.3main函数一、C语言基础在这个例子中,argc的值为6,命令行一共输入了六个参数:“hello.exe”、“a”、“b”、“c”、“d”、“e”对应程序输入为:argv0:repeat.exe,argv1:a,argv2:b,argv3:c,argv4:dargv5:en需要注意的

15、是若输入参数作为数值使用时,使用atoiatof进行字符转换看例程29一、C语言基础1.3代码编写规范从书写清晰,便于阅读,理解,维护的角度出发,在书写程序时应遵循以下规则:一个说明或一个语句占一行。if,for,while,do占一行,执行语句放后面并且使用大括号,多用对齐。用括起来的部分,通常表示了程序的某一层次结构。一般与该结构语句的第一个字母对齐,并单独占一行。低一层次的语句或说明可比高一层次的语句或说明缩进若干格后书写。以便看起来更加清晰,增加程序的可读性。在编程时应力求遵循这些规则,以养成良好的编程风格。多写注释,合理的使用注释可以让你的程序可读性更高。30一、C语言基础另外一些编

16、程风格说明:程序块要采用缩进风格编写,缩进少使用空格键;对齐多使用TAB键,少使用空格键;逗号、分号只在后面加空格。inta,b,c;比较操作符,赋值操作符“=”,“+=”,算术操作符“+”,“%”,逻辑操作符“&”,“&”,位域操作符“”,“.”前后不加空格。p-id=pid;/“-”指针前后不加空格if、for、while、switch等与后面的括号间应加空格,使if等关键字更为突出、明显。if(a=b&cd)32一、C语言基础33一、C语言基础1.4命名规则使用匈牙利命名法,标识符应直观意思明确尽量使用缩写,如intiImgWidth;不要使用大小写来区分变量,如intx,X;局部变量不

17、要与全局变量同名;常量使用大写字母,合理使用前缀,静态变量加前缀s_,全局变量加前缀g_。34一、C语言基础1.5表达式n注意优先级的的高低以及结合顺序,多使用括号确定优先级35一、C语言基础1.5表达式注意if常用的条件判断情况:布尔变量if(flag)if(!flag)整型变量if(flag=0)if(flag!=0)浮点变量if(abs(x-0)1e-5)指针变量if(p=NULL)if(p!=NULL)if语句36一、C语言基础1.5表达式注意以下几点:多重循环中,尽量将循环少的放在外层循环for(i=0;iN;i+),循环执行N次,最大执行到i=N-1,i最后执行完等于Nswitch

18、的每个case都加上break,最后加上default尽量少用goto循环语句37从静态存储区域分配,在程序编译的时候就已经分配好,整个运行期都存在。如全局变量和static变量。从栈上创建,从函数创建开始存在,函数结束就释放,效率高,但是分配大小有限。如函数内部变量。从堆上分配,也称动态内存分配。使用malloc分配,需要手动free释放。使用灵活,容易出问题。C语言中内存分配区域:二、内存管理38二、内存管理2.1常见内存错误没有分配直接使用或者分配未成功却使用了它;没有初始化或者归零就直接使用(分配内存后系统默认值不一定是0);使用时内存访问越界,使用完忘记释放内存,造成内存泄漏;对已分

19、配内存的指针进行赋值操作,原来分配内存区域丢失,内存泄漏;释放了内存却继续使用,指针在释放后并不是变为NULL,仍然指向原来地址,成为“野指针”。39二、内存管理2.2指针与数组数组在栈上和静态存储区域创建,其地址与容量分配后不可改变,但内容可以改变;指针的特征是“可变”,用于分配动态内存区域;不能直接对数组名进行复制和比较,使用strcpy和strcmp;指针存储的是动态内存区域的地址,可以直接传递地址,当对两块动态内存区域复制或比较时使用memcpy和memcmp;数组的大小,需要加上最后面的0,可以使用sizeof获得;指针使用sizeof获得的是指针变量的字节数;需要注意的是当数组作为

20、函数参数传递时,自动退化为该类型的指针。40二、内存管理2.2指针与数组例子:41二、内存管理2.3指针指针的本质是地址,指针变量本身作为普通寄存器变量被存储,特别是该寄存器地址内存储的是另一个寄存器地址,该寄存器地址内存储的数据是指针指向的数据。栈mainint i=200;char *p;0x123456假设已给p分配空间0x12 3456p=0x123456i=2000x1234560x123452100*p=1000x2012120x201216&p=0x201216&i=0x201220200栈42二、内存管理2.3指针malloc在堆上分配动态内存区域,需要指定分配区域的大小,以字

21、节作为单位。p=(char*)malloc(1*sizeof(char);/分配到0x123456,存储在栈地址0x201216的内存地址中*p=100;/修改0x123456中数值为100/free将分配的动态内存区域释放free(p);/虽然0x123456该地址被标志为已释放,但是p内存储的仍然是0x123456,p成为野指针p=NULL;/将0x201216内数据改为0x00,该地址不可访问malloc与free:43二、内存管理当子函数中使用指针时,子函数执行结束指针没有free掉,此时指针变量释放了,不代表它所指向的内存自动释放了。当内存被释放时,不代表指针不存在了或者指针成为NU

22、LL指针。需要查找程序内存泄漏。2.3指针需要注意的几点:44三、常用技巧3.1宏的使用#defineceil_div(x,y)(x+y-1)/y宏执行的是简单的替换作用,需要注意由操作符优先级引起的问题,多加括号。那么a=ceil_div(b&c,sizeof(int);将被转化为:a=(b&c+sizeof(int)-1)/sizeof(int);由于+/-的优先级高于&的优先级,那么上面式子等同于:a=(b&(c+sizeof(int)-1)/sizeof(int);为了避免这种情况发生,应当多写几个括号:#defineceil_div(x,y)(x)+(y)-1)/(y)45三、常用技

23、巧3.1宏的使用函数变宏每行代码最后都加行连接符“”,即使是空行也要加“”,最后一行代码后面不需要加“”,每行“”最后不能有多余字符或者空格,返回的是最后一条语句的执行结果。可以在宏函数内定义变量,可以使用if等语句,可以在宏内调用其他宏,可以使用指针。函数变宏可以加快程序运行速度。看例子46三、常用技巧3.2运行时间测量程序运行过程中,我们经常需要统计程序运行时间。下面给出示例:#includemain()clock_tbegin,end;begin=clock();end=clock();doubleduration;duration=(double)(end-begin)/CLOCKS_

24、PER_SEC;printf(“Timeis%2.1fsecondsn,duration);/#defineCLOCKS_PER_SEC1000/事实上endbegin获得的是毫秒计数47三、常用技巧3.2运行时间测量Time()函数是获得当前系统时间用的,一般不用于计时。当程序运行时间太短时,可以使用多次执行的办法来获得。可以使用更精确的运行时间计数函数:“QueryPerformanceCounter()”“QueryPerformanceFrequency()”48三、常用技巧随机数生成:#include#include#includevoidmain(void)inti;/*Seedt

25、herandom-numbergeneratorwithcurrenttimesothat*thenumberswillbedifferenteverytimewerun.*/srand(unsigned)time(NULL);/*Display10numbers.*/for(i=0;i10;i+)printf(%6dn,rand();Srand是产生伪随机序列的种子,种子一样产生的伪随机序列一样。RAND_MAX0x7fffffffj=(int)(*rand()/(RAND_MAX+1.0)产生一个0到之间的随机数49三、常用技巧3.3文件操作文件的打开与关闭文件在进行读写操作之前要先打开,

26、使用完毕要关闭。打开文件实际上是建立文件的各种有关信息,并使文件指针指向该文件,以便进行其它操作。关闭文件则断开指针与文件之间的联系,也就禁止再对该文进行操作。在语言中,文件操作都是由库函数来完成的。fp=fopen(“filename”,“r”);50三、常用技巧对于文件使用方式有以下几点说明:文件使用方式由r,w,a,b,t,+六个字符拼成,各字符的含义是:r(read):读w(write):写a(append):追加b(binary):二进制文件+:读和写凡用“r”打开一个文件时,该文件必须已经存在,且只能从该文件读出。用“w”打开的文件只能向该文件写入。若打开的文件不存在,则以指定的文

27、件名建立该文件,若打开的文件已经存在,则将该文件删去,重建一个新文件。51三、常用技巧if(fp=fopen(“readme.txt,rb)=NULL)printf(nerroronopenc:hzk16file!);exit(1);若要向一个已存在的文件追加新的信息,只能用“a”方式打开文件。但此时该文件必须是存在的,否则将会出错。在打开一个文件时,如果出错,fopen将返回一个空指针值NULL。在程序中可以用这一信息来判别是否完成打开文件的工作,并作相应的处理。52三、常用技巧文件的读写对文件的读和写是最常用的文件操作。在语言中提供了多种文件读写的函数:字符读写函数:fgetc和fputc

28、字符串读写函数:fgets和fputs数据块读写函数:fread和fwrite格式化读写函数:fscanf和fprinf行操作。53三、常用技巧文件的读写在文件内部有一个位置指针,用来指向文件的当前读写字节。在文件打开时,该指针总是指向文件的第一个字节。使用fgetc函数后,该位置指针将向后移动一个字节。应注意文件指针和文件内部的位置指针不是一回事。文件指针是指向整个文件的,文件内部的位置指针用以指示文件内部的当前读写位置,每读写一次,该指针系统自动向后移动。54三、常用技巧计算文件长度的程序示例longfilesize(FILE*stream)longcurpos,length;curpos

29、=ftell(stream);fseek(stream,0L,SEEK_END);length=ftell(stream);fseek(stream,curpos,SEEK_SET);returnlength;进行二进制文件读写时,打开方式后面加“b”55四、调试编程出现error时,从第一个error处开始解决错误,可能是很小的书写错误引起的。warning也需要关注,有时候会导致程序运行错误发生。程序出现BUG时,单步跟踪,查看变量,查看内存,查看栈调用,可以边编辑边跟踪。加入合适的断点,使用条件断点。程序调试结束后需要查找内存泄露,规范代码书写。使用assert,只有条件满足才继续向下执

30、行,在release下不会编译该语句。程序编写完成不一定是完全正确的,需要进行测试并进行跟踪调试。56四、调试4.1条件断点我们在调试的时候希望程序在某个断点处只有在满足一定的条件下中断,在不满足条件的时候正常运行,可以为程序调试带来极大的便利。示例57四、调试4.2内存泄漏查找养成好的代码写作规范,掌握内存管理概念,减少不规范代码内存泄漏可能性。是否内存泄露:运行可执行文件,使用任务管理器查看内存占用情况是否一直增加。比较简单但是显示不一定精确。使用NumegaBounderChecker软件查找,程序中加入exit(0)强制中断,Debug至该代码行程序异常中断时查看内存泄露报告。示例58

31、四、调试4.3watch跟踪调试时多使用watch窗口,在watch窗口内可以进行有限运算,注意watch运算带来的影响。示例59四、调试4.4C程序优化首先要确定优化目标,然后寻找优化方法。查找程序运行瓶颈,使用IntelVtune查看各部分运行时间,一步步进行优化。现在CPU,GPU发展方向都是多核,并行计算越来越方便,为优化提供了更多解决方案。任务级并行,使用多线程发挥多核优势。指令级并行,使用MMX,SSE,SSE2等指令集。参看Vtune使用指南60五、示例5.1软件设计算法思想,思路清楚,注意细节质量控制,代码高效,风格良好测试调试,测试全面,调试认真软件设计过程关键部分:在编写软

32、件程序之前,首先要明确你要解决的问题,软件只是思想的实现,不能通过编程来获得思想。所以在编写之前就需要对问题有透彻的理解,对解决问题的方法有清晰的思路,要考虑到可能遇到的所有问题,同时要考虑到软件的可靠性稳定性等。61五、示例5.1软件设计在编写软件程序之前,首先要明确你要解决的问题,软件只是思想的实现,不能通过编程来获得思想。所以在编写之前就需要对问题有透彻的理解,对解决问题的方法有清晰的思路,要考虑到可能遇到的所有问题,同时要考虑到软件的可靠性稳定性等。在代码编写的时候,注意代码编写规范,编写风格良好的代码,多用注释让代码的可读性变高。实际上一个项目中代码编写的时间可能是最短的。前期算法的

33、测试和后期测试工作占得时间更多。代码编译通过不代表软件完成,代码编写完成后需要进行大量的测试来确保程序的正确性,这也要求代码编写的适合大规模测试。在遇到问题的时候首先思考下算法设计是否合理,重新考虑下软件编写思路是否还有没有考虑到的情况,然后对代码进行跟踪调试。62五、示例5.2VC6+的使用创建程序添加程序文件编写代码编译运行设置参数调试程序63五、示例5.3例子一(看示例)蒙塔卡罗算法计算圆周率以概率和统计理论方法为基础的一种计算方法。将所求解的问题同一定的概率模型相联系,用计算机实现统计模拟或抽样,以获得问题的近似解。利用求圆的的面积来求得Pi。在正方形中随机投入很多点,使所投的点落在正

34、方形中每一个位置的机会相等看其中有多少个点落在圆内。将落在圆内的点数m与所投点的总数n的比m/n作为理论值的近似值。问题描述思路软件设计过程,先产生随机数据,判断该数据是否落在圆内,统计落在圆内的点数。最后计算圆周率。64五、示例5.3例子二(看示例)动态链接的好处扩展了应用程序的特性,可以用许多种编程语言来编写;简化了软件项目的管理;有助于节省内存,有助于资源共享;有助于应用程序的本地化,有助于解决平台差异;可以用于一些特殊的目的。windows使得某些特性只能为DLL所用。保护了代码版权。VC+6.0中使用动态链接库封装程序,在vs2005中,在项目属性中配置输出为动态链接库。(参看我的教

35、程)65五、示例5.3例子三(看示例)多线程编程首先要明确线程的概念(参考windows核心编程),windows中多线程并不是物理上的并行(单核CPU),而是通过CPU的时分复用来实现多线程的并行计算。多线程中的调试是非常麻烦的,因此在设计的时候就先要考虑清楚设计思路。多线程中经常发生资源共享冲突,为了保证多个进程互斥地对共享资源进行访问,一般使用互斥体(mutex)、临界量(critical_section)、事件(event)和信号量(semaphore)来解决。互斥体和临界量每次只准许一个线程对共享资源进行访问,不允许其他线程同时访问。信号量每次允许有限个线程对共享资源进行访问,超过限制的则进行等待。事件可以手动控制线程进行访问。66五、示例5.3例子三(看示例)多线程编程比如ATM机。如果只有一台ATM机,我们可以使用互斥体和临界量来协调使用,获得互斥体访问权的或者临界量优先权的先使用ATM,使用完后给其他人使用。信号量则对应的是多台ATM机的情形,假设共有三台ATM机,则每次最多可以有三个线程进行访问,其余的只能等待。67谢谢大家!欢迎交流:68

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 学术论文 > 其它学术论文

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号