资源描述
,Click to edit Master title style,Click to edit Master text styles,Second level,Third level,Fourth level,Fifth level,*,*,Click to edit Master title style,Click to edit Master text styles,Second level,Third level,Fourth level,Fifth level,*,*,Click to edit Master title style,Click to edit Master text styles,Second level,Third level,Fourth level,Fifth level,*,*,内容,命令行参数,可变长的实参列表,输入输出重定向,动态内存分配,c,预处理,gcc,编译参数,编程中的注意事项,编程举例:事务处理程序,内容,命令行参数,可变长的实参列表,输入输出重定向,动态内存分配,c,预处理,gcc,编译参数,编程中的注意事项,编程举例:事务处理程序,命令行参数,以命令行运行程序时所带的参数,int main(int argc,char*argv);,int main(int argc,char *argv);,几乎所有的实际应用程序都需要处理命令行参数,举例:,notepad.exe a.txt,7z,/*read and output characters*/,while(c=fgetc(inFilePtr)!=EOF),fputc(c,outFilePtr);,/*end while*/,/*end if*/,else /*output file could not be opened*/,printf(File%s could not be openedn,argv 2 );,/*end else*/,/*end if*/,else /*input file could not be opened*/,printf(File%s could not be openedn,argv 1 );,/*end else*/,/*end else*/,return 0;/*indicates successful termination*/,/*end main*/,内容,命令行参数,可变长的实参列表,输入输出重定向,动态内存分配,c,预处理,gcc,编译参数,编程中的注意事项,编程举例:事务处理程序,可变长的实参列表,函数接受的实参个数可以是不确定的,例:,int printf(const char*format,);,其中,表示这个函数可以接受可变数目的实参,省略号必须放在形参列表的末尾,include,stdarg.h,中的宏和定义,va_list:,为了访问可变长实参列表中的实参必须声明一个类型为,va_list,的对象,va_start:,在一个可变长实参列表中的实参被访问前,先要调用这个宏。其功能:,初始化,用,va_list,声明的对象,以便让宏,va_arg,和,va_end,来使用,va_arg:,宏,展开成一个表示可变长实参列表,中下一个实参,的值和类型的表达式。,va_end:,正常返回,/*Fig.14.2:fig14_02.c Using variable-length argument lists*/,#include,#include,double average(int i,.);/*prototype*/,int main(void),double w=37.5;,double x=22.5;,double y=1.7;,double z=10.2;,printf(%s%.1fn%s%.1fn%s%.1fn%s%.1fnn,w=,w,x=,x,y=,y,z=,z);,printf(%s%.3fn%s%.3fn%s%.3fn,The average of w and x is,average(2,w,x),The average of w,x,and y is,average(3,w,x,y),The average of w,x,y,and z is,average(4,w,x,y,z);,return 0;/*indicates successful termination*/,/*end main*/,/*calculate average*/,double average(int i,.),double total=0;/*initialize total*/,int j;/*counter for selecting arguments */,va_list ap;,/*stores information needed by va_start and va_end*/,va_start(ap,i);,/*initializes the va_list object*/,/*process variable length argument list*/,for(j=1;j :,输出重定向符,cmd data.out,:,输入重定向符,cmd,、,:,原文件会被删除,重新生成新的文件,它以,追加,的方式,将命令的输出写入文件的末尾,原文件内容会被保留,新的内容会添加到原文件内容的后面,输入,重定向,输入重定向使输入信息来自文件,小于号,是输入重定向操作符,在,之后的文件名或设备名是 重定向的输入源,如果一个程序需要输入较多数据,使用输入重定向可以提高效率。,如,more,、,sort,和,find,命令。其中,more,进行分屏显示;,find,查找符合条件的内容;,sort,(按行)排序,实例,more file,把,stdout,重定向到,file,文件中,cmd file,把,stdout,重定向到,file,文件中,(,追加,),cmd 1 file,把,stdout,重定向到,file,文件中,cmd 2 file,把,stderr,重定向到,file,文件中,cmd 2 file,把,stderr,重定向到,file,文件中,(,追加,),cmd file2 cmd,命令以,file,文件作为,stdin,,,以,file2,文件作为,stdout,prog.c,#include,int main(void),char c;,while(scanf(%c,&c)=1),printf(%c,c);,printf(%c,c);,return 0;,尝试一下命令,cmd,cmd outfile.txt,cmd outfile.txt,输出重定向的一个应用,如在批处理命令执行期间为了禁止命令或程序执行后输出信息而扰乱屏幕,可用,DOS,重定向功能把输出改向,NUL,设备,(NUL,不指向任何实际设备,),例如:,C:copy a.txt b.txt NUL,命令执行结束,不显示,1 file(s)copied,的信息。,输入重定向的一个应用,有的交互程序在执行时要求很多键盘输入,但有时输入是固定不变的,为加快运行速度,可预先建立一个输入文件,此文件的内容为程序的键盘输入项,每个输入项占一行,。,假如有一个程序,cx,其输入项全部包括在文件,in.dat,中,执行,C:cx NUL,程序就自动执行。,管道,进程从“管道”的一端发送另一端接收,也就是说将若干命令用输入输出“管道”串接在一起,这就是管道;管道在某种程度上是输入和输出重定向的结合,,前一个命 令的输出,作为下一个命令的输入,,而不需要经过任何中间文件。,竖线字符,”|”,是管道操作符,管道命令经常与一些过滤命令联合使用。,DOS,的管道功能是使一个程序或命令的标准输出用做另一个程序或命令的,标准输入,。,type aaa|DEBUG bbb,如把,DEBUG,的输入命令写入文件,aaa,用,type,命令通过管道功能将,aaa,的内容传输给,DEBUG,在,DEBUG,执行期间不再从控制台索取命令参数,从而提高了机器效率。,dir|more,使得当前目录列表在屏幕上逐屏 显示。,dir,的输出是整个目录列表,它不出现在屏幕上而是由于符号“,|”,的规定,成为下一个命令,more,的输入,,more,命令则将其输入,,more,命令则 将其输入一屏一屏地显示,成为命令行的输出。,dir|find”hello”file,其中,dir,的输出是当前目录列表,不出现在屏幕上而是成为,find,命令的输入。,find,命令在输入文件中寻找指定字符串,“hello”,并输出包含这个字符串的行,由于输出重定向符号,的规定,最后的输出已存入文件,file,,不出现在屏幕上。,dir|findfile,则是将当前目录项中的子目录项寻找出来并存入文件,file,中,。,内容,命令行参数,可变长的实参列表,输入输出重定向,动态内存分配,c,预处理,gcc,编译参数,编程中的注意事项,编程举例:事务处理程序,动态内存分配,静态内存分配,在编译时完成分配,自动释放,方便、效率高,栈空间,,大小有限制(默认情况下,,windows,系统,1M,,,Linux,下,8M,),动态内存分配,数据结构的存储空间不是在程序运行前事先分好,而是在程序运行中根据需要临时分配,程序员自己申请并指明大小,自己释放,灵活,堆空间,,空间大小几乎没有什么限制(只受到计算平台存储空间资源和操作系统对存储空间资源分配策略的限制),c/c+,程序内存分配,栈(,stack,),程序运行时由编译器自动分配,,存放函数的参数值,局部变量的值等。,其操作方式类似于数据结构中的栈。程序结束时由编译器自动释放。,堆(,heap,),在内存开辟另一块存储区域。一般由程序员分配释放,若程序员不释放,,程序结束时可能由,OS,回收,。注意它与数据结构中的堆是两回事。,全局区(静态区)(,static,),编译器编译时即分配内存。全局变量和静态变量的存储是放在一块的,初始化的 全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。,程序结束后由系统释放,文字常量区,程序代码区,堆栈实例代码比较,实例:,#include#include,int,a=0;/,全局初始化区,char*p1;/,全局未初始化区,void main(),int,b=1;/,栈,char s=,abc,;/,栈,char*p2;/,栈,char*p3=123456;/1234560,在常量区,,p3,在栈上。,static,int,c=0;/,全局(静态)初始化区,p1=(char*)malloc(10);,p2=(char*)malloc(20);/,分配得来得,10,和,20,字节的区域就在堆区。,strcpy(p1,“123456”);/1234560,放在常量区,编译器可能会将它与,p3/,所指向的,123456,优化成一个地方,system(pause,);,动态内存分配,malloc,函数和,free,函数,C,void,*,malloc(size_t size);,int*gradeArray=malloc(sizeof(int);,void free(void*ptr);,free(gradeArray);,new/,delete,C+,运算符,调用类的构造函数,(new),或者析构函数,(delete),int*gradeArray=new int 10;,delete gradeArray;,堆,/,栈的不同,堆和栈的主要区别由以下几点:,1,、管理方式不同;,2,、空间大小不同;,3,、能否产生碎片不同;,4,、生长方向不同;,5,、分配方式不同;,6,、分配效率不同;,堆栈的不同,管理方式不同;,管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;,对于堆来说,释放工作由程序员控制,容易产生,memory leak,。,空间大小不同;,空间大小:一般来讲在,32,位系统下,,堆内存可以达到,4G,的空间,,从这个角度来看堆内存几乎是没有什么限制的。但是,对于栈来讲,一般都是有一定的空间大小的,例如,在,VC6,下面,默认的栈空间大小是,1M,。当然,这个值可以修改。,堆栈的不同,能否产生碎片不同;,碎片问题:,对于堆来讲,频繁的,new/delete,势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出,,详细的可以参考数据结构。,堆栈的不同,生长方向不同;,生长方向:,对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。,分配方式不同;,分配方式:堆都是动态分配的,没有静态分配的堆。栈有,2,种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由,malloc,函数进行分配,但是栈的动态分配和堆是不同的,他的,动态分配是由编译器进行释放,无需我们手工实现,。,堆栈的不同,分配效率不同;,分配效率:,栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。,堆则是,C/C+,函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构,/,操作系统)在堆内存中搜索可用的足够大小的空间,如,果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,,这样就,有机会分到足够大小的内存,然后进行返回,。显然,,堆的效率比栈要低得多,。,函数调用的栈操作,寄存器,ebp,用做帧指针(,frame pointer,),esp,用作栈指针(,stack pointer,),函数调用操作包括从一块代码到另一块代码之间的双向数据传递和执行控制转移。,数据传递通过函数参数和返回值来进行。,在进入函数时为函数的局部变量分配存储空间,并且在退出函数时收回这部分空间,函数调用的栈操作,void swap(int*a,int*b)int c;c=*a;*a=*b;*b=c;int main()int a,b;a=16;b=32;swap(,内容,命令行参数,可变长的实参列表,输入输出重定向,动态内存分配,c,预处理,gcc,编译参数,编程中的注意事项,编程举例:事务处理程序,C,预处理,#include,预处理命令,文件包含,#define,预处理命令,符号常量和宏,条件编译,#error,和,#pragma,预处理命令,assert,#include,文件,#include“,文件名,“,或,#include,文件包含命令的功能是把指定的文件插入该命令行位置取代该命令行,从而把指定的文件和当前的源程序文件连成一个源文件。,尖括号与双引号 差别:目录查找次序不同,一个,include,包含一个文件,允许嵌套包含,条件编译,#define,符号常量和宏,#undef,条件编译的三种形式,条件编译,#ifdef,标识符 程序段,1#else,程序段,2#endif,#ifndef,标识符 程序段,1#else,程序段,2#endif,#if,常量表达式 程序段,1#else,程序段,2#endif,如果标识符已被,#define,命令定义过则对程序段,1,进行编译;否则对程序段,2,进行编译。,,如果标识符未被,#define,命令定义过则对程序段,1,进行编译,否则对程序段,2,进行编译。,如常量表达式的值为真,(,非,0),,则对程序段,1,进行编译,否则对程序段,2,进行编译。,条件编译,#ifdef/#else/#endif,#define NUM okmain()ps=(struct stu*)malloc(sizeof(struct stu);ps-num=102;ps-name=Zhang ping;ps-sex=M;ps-score=62.5;#ifdef NUMprintf(Number=%dnScore=%fn,ps-num,ps-score);#elseprintf(Name=%snSex=%cn,ps-name,ps-sex);#endiffree(ps);,struct stuint num;char*name;char sex;float score;*ps;,条件编译,#ifndef/#define/#endif,避免头文件的重定义,#ifndef _TEST_H,#define _TEST_H/,一般是文件名的大写,头文件结尾写上一行:,#endif,这样一个工程文件里同时包含两个,test.h,时,就不会出现重定义的错误了。,条件编译,#ifdef/#else/#endif,判断表达式真假的条件编译,#define R 1main()float c,r,s;printf(input a number:);scanf(%f,#endif,预处理命令,#error,主要的作用是在编译的时候输出编译错误信息,token-sequence,,从方便程序员检查程序中出现的错误。,该指令用于程序的调试,当编译中,遇到,#error,指令就停止编译,。,#define CONST_NAME1 CONST_NAME1printf(%sn,CONST_NAME1);#undef CONST_NAME1#ifndef CONST_NAME1#error No defined Constant Symbol CONST_NAME1#endif,预处理命令,#pragma,主要的作用是设定编译器的状态或者是,指示编译器完成一些特定的动作,。,其格式一般为,:,#pragma para,其中,para,为参数,,常用参数组合:,#pragma message :,编译信息输出窗口中输出相应的信息。,例如,#pragma message(“,消息文本,”),预处理命令,当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条指令在编译的时候就进行检查。假设我们希望判断自己有没有在源代码的什么地方定义了,_X86,这个宏可以用下面的方法,#,ifdef,_X86,#,Pragma,message(“_X86 macro activated!”),#,endif,当我们定义了,_X86,这个宏以后,应用程序在编译时就会在编译输出窗口里显示“,_X86 macro activated!”,。,预处理命令,#pragma code_seg,#pragma code_seg(section-name,section-class ),它能够设置程序中函数代码,存放的代码段,,当我们开发驱动程序的时候就会使用到它。,#pragma once(,比较常用),只要在头文件的最开始加入这条指令就能够保证,头文件被编译一次,。,预处理命令,其他,pragma,的参数,#pragma hdrstop,#pragma once,#pragma resource,#pragma warning,assert,宏 断言,void assert(int expression),assert,宏的原型定义在,中,其先计算表达式,expression,,如果其值为假(即为,0,),那么它先向,stderr,打印一条出错信息,,然后通过调用,abort,来终止程序运行。,其优势是利于调试,缺点是频繁的调用会极大的,影响程序的性能,,增加额外的开销。,调试结束后,可以通过在包含,#include,的语句之前插入,#define NDEBUG,来禁用,assert,调用。,#include#define NDEBUG#include,assert(),使用实例,#include#include#include,int main(void)FILE*fp;fp=fopen(“test.txt”,“w”);/,文件可创建,打开成功,assert(fp);/,所以这里不会出错,fclose(fp);fp=fopen(“noexitfile.txt”,“r”);/,文件不存在,打开失败,assert(fp);/,所以这里出错,fclose(fp);/,程序永远都执行不到这里来,return 0;,运行后,错误提示为:,badptr.c:14,:main:Assertion fp failed.,断言,assert,的用法,assert,用法,在函数开始处检验,传入参数,的合法性;,int resetBufferSize(int nNewSize),assert(nNewSize=0);assert(nNewSize=0,劣,assert(nOffset=0);assert(nOffset+nSize=m_nInfomationSize);,优,断言内,不可使用改变环境的语句,;,assert(i+100),;,劣,-,调试结束,取消断言后程序出错,断言定义文件,#include cvidef.h,#include cvirte.h,#ifndef _ASSERT_H_,#define _ASSERT_H_,#ifdef _cplusplus,extern C,#endif,#undef assert,#ifdef NDEBUG,#define assert(exp)(void)0),#else,void CVIANSI _assert(char*,char*,int);,#define assert(exp)(exp)?(void)0:_assert(#exp,_FILE_,_LINE_),#endif,#ifdef _cplusplus,#endif,#endif/*_ASSERT_H_*/,内容,命令行参数,可变长的实参列表,输入输出重定向,动态内存分配,c,预处理,gcc,编译器,编程中的注意事项,编程举例:事务处理程序,gcc,编译器,C,/C+,程序的编译运行,gcc/g+,是,GNC,的开源编译器,用来对,c/c+,程序进行编译、调试,后缀为,.c,的程序,,gcc,当成,c,程序,,g+,当成,c+,程序;而后缀为,.cpp,的程序两者都当成,c+,程序,/hello.c,#include,int main(),printf(hello worldn);,return 0;,gcc,编译过程,预处理,对源代码文件中的文件包含、预编译语句进行分析,gcc-o hello,.i,-E,hello.c,编译及优化,将预处理文件进行汇编,生成汇编语言程序,gcc-o hello,.s-S,hello.i,汇编,将汇编的代码进一步进行处理,生成相应的目标文件,以,.o,为扩展名,gcc-o hello.o,-c,hello,.s,链接,将生成的目标文件与其他目标文件(或库文件)连接成可执行的二进制代码文件,gcc-o hello hello.o,gcc,hello,.c o,hello,多个文件的编译链接,对于一个程序的多个源文件进行编译连接时,可以使用如下格式:,gcc o test first.c second.c third.c,该命令将同时编译,3,个源文件,将它们连接成一个可执行文件,名为,test,常用编译选项,(1),-c,仅把源程序编译为目标代码而不做链接,不生成最终的可执行程序,只生成一个与源程序文件名相同的以,.o,为后缀的目标文件。,-o,将编译结果写入文件,中,-v,Gcc,的版本信息,-x language,强制编译器指定的语言编译器,来编译某个源程序,例如,gcc-x c+,test,.c,-I,库依赖选项,指定库及头文件路径,l,在函数库,中查找需要链接的函数,-L,将目录,加入到搜索链接函数库的目录集合中,常用编译选项,(2),-w,禁止输出警告信息,-Wall,在标准输出上显示所有的警告信息,-O,或,-O,指定编译优化级别,,可以为,1,,,2,,,3,和,s,,,-O,等于,-O1,-,g,生成调试辅助信息,以便使用,GDB,等调试工具进行调试,-,pg,加入运行剖面生成代码,以便生成,可以被,gprof,解读,的程序运行剖面数据,gcc,实例,-,清单,main.c-#include,#include,int factorial(int n);int main(int argc,char*argv),int n;,if(argc 2),printf(“Usage:%s nn”,argv 0);,return-1;,else,n=atoi(argv1);,printf(“Factorial of%d is%d.n”,n,factorial(n);,return 0;,-,清单,factorial.c-int factorial(int n),if(n=sizeof(int)=sizeof(short)=sizeof(char),Sizeof(int)=2bytes,sizeof(int)=2bytes,sizeof(long)=4bytes,Limits.h,定义一些常数,表示各个数据类型的范围,包括,SCHAR_MIN,SCHAR_MAX,UCHAR_MAX,SHRT_MIN,SHRT_MAX,USHRT_MAX,INT_MIN,INT_MAX,UINT_MAX,LONG_MIN,LONG_MAX,ULONG_MAX,有符号和无符号数,有符号数和无符号数,对最高位的解释不通,如果是有符号,,0-,表示正,,1-,表示负,大的无符号数转换成有符号数,可能变成负数,一个负数转换成无符号数,变成一个整数,000 0 0,001 1 1,010 2 2,011 3 3,100 4 -4,101 5 -3,110 6 -2,111 7 -1,补码的计算,1,的二进制码为,001,取反为,110,加上末尾,1,为,111,-1,的补码为,111,有符号和无符号数,例子,int si;,unsigned ui;,si=-1;,ui=(unsigned)INT_MAX+1;,printf(“%#x=signed%d=unsigned%dn”,si,si,si);,printf(“%#x=signed%d=unsigned%dn”,ui,ui,ui);,0 xffffffff=signed-1=unsigned 4294967295,0 x80000000=signed-2147483648=unsigned 2147483648,参考前页,有符号和无符号数,运算,有符号,/,无符号,同时出现,隐含强制转换有符号到无符号,也就是“窄”变”宽”,Unsigned short ui=5;,Short si=-5;,Printf(“%dn”,uisi),输出,0,因为,-5,转换成无符号数,成为一个很大的数,有符号和无符号数,无符号数相减,Unsigned int x =57,y=663;,Printf(“xy:%d,yx:%d,x-y0:%d,y-x0:%dn”,xy,yx,x-y0,y-x0);,对于无符号数,,x-y0,总是成立的,0 1,1,1,有符号和无符号数,无符号数和有符号数使用原则,尽量使用有符号数,需要更大数值范围的处理时,使用更长位数的整数,无符号数和标志位,无符号数的使用,数据掩码,计算机网络的,IP,地址,比如,定义了不同的文件类型,#define _S_IFMT 0170000 /,文件类型,bit,#define _S_IFDIR 0040000 /,目录文件,判断办法,If(mode&_S_IFMT)=_S_IFDIR),整型的截断和扩展,整型的截断,Int n;short s;,N=0 x12345678;,S=n;,Printf(“n:%d(%#x),s:%d(%#x)n”,N,n,s,s);,N:305441741(ox12345678),s:-21555(ox5678),高位字节被丢弃,整型的截断和扩展,整型的扩展,无符号数,/,有符号数,扩展后不变,Short ps=12345,ns=-12345;,Unsigned short pus =(unsigned short)ps;,Unsigned short nus=(unsigned short)ns;,Int pi,ni;,Unsigned int pui,nui,ui;,Pi=ps;ni=ns;,Pui=pus;nui=nus;,Printf(“pi=%d(%#x),ni=%d(%#x)”,pi,pi,ni,ni);,Printf(“pui=%d(%#x),nui=%d(%#x)”,pui,pui,nui,nui);,整型的截断和扩展,整型的扩展,无符号数,/,有符号数,扩展后不变,Short ps=12345,ns=-12345;,Unsigned short pus =(unsigned short)ps;,Unsigned short nus=(unsigned short)ns;,Int pi,ni;,Unsigned int pui,nui,ui;,Pi=ps;ni=ns;,Pui=pus;nui=nus;,Printf(“pi=%d(%#x),ni=%d(%#x)”,pi,pi,ni,ni);,Printf(“pui=%d(%#x),nui=%d(%#x)”,pui,pui,nui,nui);,无符号扩,Ps-,pus -pui,-pi(,有符号),无符号扩,Ns-nus-nui,-ni(,有符号),Pi=12345(0 x3039),ni=-12345(0 xffffcfc7),Pui=12345(0 x3039),nui=53191(0 xcfc7),整型计算的溢出,溢出的情况,两个符号相同的数值,+,两个符号相异的数值,-,两个大数,原因:整型是由一定范围的,Int a=12,b=8388608,c=1024;,Printf(“a*c=%d,b*c=%dn”,a*c,b*c);,A*c=12288,b*c=0,整型计算的溢出,判断加法是否溢出,Int a,b,c;,C=a+b;,If(a=0)=(b=0),&(a=0)!=(c=0),/overflow),乘出来的数值符号不对了,,问:能否解决 正数,+,负数,负数,+,负数的判断,整型计算的溢出,判断乘法是否溢出,Int x,y,z;,Z=x*y,;,If,(,x!=z/y),/overflow,结果除以,y,不等于,x,了,整型计算的溢出,计算平均值,Int I,n,avg,sum,xMAX_NUM;,For(sum=i=0;i0?Sum/n:0;,问题:每个数值较大,中间结果溢出。,整型计算的溢出,计算平均值,解决办法,For(rem_sum=avg=i=0;i0),avg+=rem_sum/n;,整除的结果累加,余数先整合起来,最后除以,n,,再加到,avg,里面,避免误差,整除所引起的误差,均分窗口大小,For(i=1;in;i+),p_xi=,i/n,*win_w+win_x;,prinft(“%dt”,p_xi),Putchar(n);,0 0 0 0 0 0 0 0 0,因为:,i/n,一直为,0,整除所引起的误差,均分窗口大小,改进,W=win_w/n;,For(i=1;in;i+),p_xi=w*i,+win_x;,prinft(“%dt”,p_xi),Putchar(n);,当,win_w=100,n=10,10 20 30 40 50 60 70 80 90,当,win_w=99,n=10,9,18,27,36,45,54,63,72,81,81,与右边界,99,差,18,像素,不均衡,整除所引起的误差,均分窗口大小,再改进,For(i=1;in;i+),p_xi=win_w*i/n,+win_x;,prinft(“%dt”,p_xi),Putchar(n);,当,win_w=99,n=10,9,19,29,39,49,59,69,79,89,89,与右边界,99,差,10,像素,均分,OK,先,win_w*i,再除以,n,,保证精度,整型数据的字节序和尾端,大尾端,big endian,高位字节,-,低端地址,低位字节在高端地址,小尾端,little endian,正好相反,实例,32,位整数,ox12345678,从低地址到高地址,大尾端:,0 x12,0 x34,0 x56,0 x78,小尾端:,0 x78,0 x56,0 x34,0 x12,整型数据的字节序和尾端,考虑尾端的情况,不同系统之间进行网络数据传输,一个系统写入文件,另外一个系统读出文件,解决办法,Uint32_t htonl(uint32_t hostlong);,主机,-,网络,Uint32_t ntohl(uint32_t hostlong);,网络,-,主机,Uint16_t htons(uint16_t hostshort);,主机,-,网络,Uint16_t ntohs(uint16_t hostshort);,网络,-,主机,整型数据的字节序和尾端,实例,Union,Char byte4;Unsigned short usi2;Unsigned int u_int;data;,Int I;,Data.byte0=a;Data.byte1=b;Data.byte2=c;Data.byte3=d;,For(int i=0;i4;i+),Putchar(data.bytei);putchar();,Printf(“%#x:%d,%#x:%dn”,data.usi0,data.usi0,data.usi1,data.usi1);,Printf(“%#x:%d”,data.u_int,data.u_int);,整型数据的字节序和尾端,实例,Union,Char byte4;Unsigned short usi2;Unsigned int u_int;data;,Int I;,Data.byte0=a;Data.byte1=b;Data.byte2=c;Data.byte3=d;,For(int i=0;ib,且,c=0,则,a+cb+c,a*cb*c,浮点数的加法和乘法满足交换性,A+b=b+a,a*b=b*a,浮点数的加法不满足结合型,(a+b)+c=a+(b+c),(1.23+1e17)1e17=0,较大的误差导致,1.23,被忽略,1.23+(1e17-1e17)=1.23,浮点数,精度实例,T=1.234;x =t*2.01;,Y=t+t+t/100.0;,If(x=y),Printf(“x(%.10f)=Y(%.10f)n”,x,y);,Else,Printf(“x(%.10f)!=Y(%.10f)n”,x,y);,结果,x(2.4803400000)!=Y(2.4803400000),比较奇怪,因为这两个实际上是不相等的,放大,10,16,就能够看出差别来,X (24803399999999996.00)!=,y (24803400000000000.00),浮点数,浮点数的比较,下面的实例将死循环,Double i;,For(i=0.0;i!=1.0;i+=0.1),Printf(“%.2fn”,i);,由于误差的累计,10,个,0.1,相加不等于,1.00,避免使用浮点数做循环变量,浮点数,浮点数的比较,浮点数的相等,/,不相等,If(fabs(a-b)ESP),浮点数是否等于,0,If(x-ESP),float.h,定义一个最小单位,,1.0+x,不等于,1.0,的最小值,#define FLT_EPSILON 1.19209290e07F,#define DBL_EPSILON 2.220446
展开阅读全文