第一讲C语言复习.ppt

上传人:本田雅阁 文档编号:3111543 上传时间:2019-07-10 格式:PPT 页数:105 大小:862.52KB
返回 下载 相关 举报
第一讲C语言复习.ppt_第1页
第1页 / 共105页
第一讲C语言复习.ppt_第2页
第2页 / 共105页
第一讲C语言复习.ppt_第3页
第3页 / 共105页
第一讲C语言复习.ppt_第4页
第4页 / 共105页
第一讲C语言复习.ppt_第5页
第5页 / 共105页
点击查看更多>>
资源描述

《第一讲C语言复习.ppt》由会员分享,可在线阅读,更多相关《第一讲C语言复习.ppt(105页珍藏版)》请在三一文库上搜索。

1、第一讲 C语言复习,C+语言程序设计,杨万扣 导航与控制研究所 东南大学自动化学院 ,1.考试说明 2.推荐教材 3.C语言简述 4.VC编译器 5.C程序事例 6.注意事项,提纲,考试说明,考核方式 平时过程化考核40%,一般5个个人项目 项目(团队项目)30%,通常为1个团队项目 期末考试30% 通常为5题上机题目。前5题选4题,注重基本算法和基础能力;最后2题选1题,注重考查学生的综合运用能力,多方案选择能力。,推荐教材,新标准C+程序设计教程 C+编程思想, C+Primer 深度探索C+对象模型 Effective C+,More effective C+ 编程规范文档(高质量C+编

2、程) 数据结构 + 算法设计 典型案例 大数据与机器学习 http:/www.coursera.org/,C是面向过程的语言 它真正提供的只有宏、指针、结构、数组和函数 结构化语言 重点在于算法和数据结构 首要考虑,是如何通过一个过程, 对输入(或环境条件)进行运算处理得到输出 (或实现过程(事务)控制),C语言概述,C提供了大量的库函数: 输入输出函数:printf(), scanf(), 动态内存分配函数:malloc(), free(), 内存管理:memset(), memcpy(), .,C语言概述,C语言知识巩固和补充,输入输出 位运算 函数 指针和动态内存分配 命令行参数 C语言

3、标准库函数,VC编译器,VC 6.0,VS2010,VS2015,VS2015使用的是新C标准 C11,,#include int main() int i; printf (“Hello!n“); return 0; ,C语言程序,由函数和变量组成 函数包含一些语句,指定要执行的计算操作 变量存储计算过程中使用的值,1. 编译 2. 链接 3. 生成可执行文件 .exe,C语言概述-例子,1. main 函数,通常函数的命名没有限制,但main是一个特殊的函数名-每个程序都从main函数开始执行,即每个程序都必须有且仅有一个main函数,2. #include 用于告诉编译器在本程序中包含标

4、准输入输出库的信息,#include void main() float len, pi; float lower, upper, step, cur; pi = 3.1415; lower = 1.0; upper = 5.0; step=1.0; cur = lower; while ( lower = upper ) len = 2*pi*cur; printf( “r=%3.0f, len=%6.0fn”, cur, len); cur = cur+step; ,while控制语句,常量定义改成宏定义,C语言例子,#include #define PI 3.1415 void main

5、() float len; float lower, upper, step, cur; lower = 1.0; upper = 5.0; step=1.0; cur = lower; while ( lower = upper ) len = 2*PI*cur; printf( “r=%3.0f, len=%6.0fn”, cur, len); lower = lower+step; ,C预处理器,三个常用的预处理器指令是: #include #include #include “文件名” 这两种形式查找路径方法不一样,(2) #define #define 名字 替换文本,(3) 条件包

6、含 #if #endif,不带参数 #define forever for(;) /*无限循环*/ (2) 不带参数的宏定义通常用于为程序中的常量取一个名字,称为符号常量。格式: #define 标识符 替换文本 如: #define PI 3.14159,C预处理器-宏定义,含义清楚,提高了程序的可读性。 在需要改变一个常量时能做到“一改全改”,用define定义宏是C语言的习惯,在C+中有更好的解决方案.,用#define定义符号常量的问题 所定义的符号常量无法进行类型检查 #define的处理只是简单的字符串的替换,可能会引起一些意想不到的错误 C+建议用const定义符号常量 cons

7、t = ; 如: const double PI = 3.1415926;,C预处理器-宏定义,(3) 带参数 #define max(A, B) (A)(B)?(A):(B),使用宏max 看起来象函数调用,但宏调用直接将文本替换文本插入到代码中,但也存在问题: max( i+, j+ ); /* 错*/,好处是:避免函数调用的开销,#undef 指令取消名字的宏定义,可以避免后续的宏调用,C预处理器-条件包含,使用条件语句对预处理本身进行控制,这种条件语句的值是在预处理的执行过程中进行计算 利用计算得到的条件值选择性地包含不同的代码,#if SYSTEM = SYSV #define HD

8、R “sysv.h” #elif SYSTEM = BSD #define HDR “bsd.h” #else #define HDR “default.h” #endif #include HDR,#ifndef HDR #define HDR #endif,一般预编译器常量都是大写,#include using namespace std; #define DEBUG void main() #ifdef DEBUG couta; #ifdef DEBUG cout“input int: “aendl; #endif ,(1)如果没有定义DEBUG宏 实际被编译的程序代码如下:,#incl

9、ude using namespace std; void main() int a; cina; ,(2)如果定义DEBUG宏 实际被编译的程序代码如下:,#include using namespace std; #define DEBUG void main() couta; cout“input int: “aendl; ,编译C+程序时,编译器自定义了一个预处理器名字, _cplusplus #ifdef _cplusplus #endif (2) 编译C程序时,编译器自定义名字_STDC_,(3) _cplusplus 和 _STDC_ 不会同时定义,#include using

10、namespace std; void main() #ifdef _cplusplus couta; #ifdef _cplusplus cout“input int: “aendl; #endif ,注释,有两种方式 /*我爱我家 */ / 我爱我家 (C风格) 注释是写给人看的,而不是写给计算机的。,注释 可以概括程序算法,标识变量意义,讲解难懂的代码。添加注释是一种好的编程习惯,注释 不会增加程序的可执行代码的长度。 在代码生成以前,编译器会将注释从程序中剔除掉,输入/输出,C语言输入输出函数:printf(), scanf(), (2) 必须包含相关的系统头文件 ,(3) C+ 采用

11、的是 cin, cout (4) 必须包含相关的系统头文件 ,(5) C语言文本输入输出函数:fprintf(), fscanf(), (6) C+文本输入输出, ofstream outfile( “name-of-file” ); ifstream infile( “name-of-file” ); 需要包含头文件 #include,变量,变量:为我们提供了一个有名字的内存存储区,可以通过程序对其进行读、写和处理。C+中每个符号都与一个特定的数据类型相关联,这个类型决定了相关内存的大小、布局、能够存储在该内存中的值得范围以及可以应用其上的操作集。 数据值:(对象的右值,被读取的值) 地址:

12、(在内存中的地址,又称为左值),C语言的输入输出语句(教材P282) #include scanf( ) 将输入读入变量 printf( ) 将变量内容输出,scanf( ) 语句(函数),int scanf( const char * , .); 参数可变的函数 第一个参数是格式字符串,后面的参数是变量的地址,函数作用是按照第一个参数指定的格式,将数据读入后面的变量 参数可变的函数的参考阅读(不要求掌握) http:/ 返回值 0 成功读入的数据项个数; 0 没有项被赋值; EOF 第一个尝试输入的字符是EOF(结束) (对某些题,返回值为EOF可以用来判断输入数据已经全部读完),print

13、f( ) 语句(函数),int printf( const char * , .); 参数可变的函数 第一个参数是格式字符串,后面的参数是待输出的变量,函数作用是按照第一个参数指定的格式,将后面的变量在屏幕上输出,返回值: 成功打印的字符数; 返回负值为出错,%d 读入或输出int变量 %c 读入或输出char变量 %f 读入或输出float变量 %s 读入或输出char * 变量 %lf 读入或输出double 变量 %e 以科学计数法格式输出数值 %x 以十六进制读入或输出 int 变量 %I64d 读入或输出 _int64 变量(64位整数) %p 输出指针地址值 %.5lf 输出浮点数

14、,精确到小数点后5位,格式字符串里的格式控制符号:,#include int main() int a; char b; char c20; double d = 0; float e = 0; int n = scanf(“%d%c%s%lf%f“, ,int n = scanf(“%d%c%s%lf%f“, input: 123a teststring 8.9 9.2 output: 123 a teststring 8.900000 9.200000e+000 9.200000 5 input: 123ateststring 8.9 9.2 output: input: 123 a te

15、ststring 8.9 9.2 output:,123 a teststring 8.900000 9.200000e+000 9.200000 5,123 a 0.000000 0.000000e+000 0.000000 3,#include int main() int a,b; char c; char s20; long long n = 9876543210001111LL; scanf(“%d %c,%s%x%I64d“, input: -28 K,test ffee 1234567890123456 output: -28 ffffffe4 4294967268 test 0

16、012FF60 ffee 65518 1234567890123456,#include int main() char * s; scanf(“%s“,s); return 0; 错在何处?,常见错误:,错在 s 不知道指向何处,往其指向的地方写入数据,不安全,char * gets(char * s); 从标准输入读取一行到字符串s 如果成功,返回值就是 s 地址 如果失败,返回值是 NULL 可以根据返回值是 NULL判定输入数据已经读完 调用时要确保 s 指向的缓冲区足够大,否则可能发生内存访问错误,读取一行:,C+11标准剔除了gets, 替换的是gets_s(),#include

17、int main() char s200; char * p = gets(s); / gets_s(s,200); printf(“%s:%s“,s,p); return 0; input: Welcome to Beijing !,读取一行:,output: Welcome to Beijing !:Welcome to Beijing !,int sscanf(const char * buffer, const char * format, address, .); 和scanf的区别在于,它是从buffer里读取数据 int sprintf(char *buffer, const c

18、har *format, argument, .); 和printf的区别在于,它是往buffer里输出数据,sscanf 函数和 sprintf函数,#include int main() int a,b; char c; char s20; char szSrc = “-28 K,test ffee 1234567890123456“; char szDest200; _int64 n = 9876543210001111; sscanf(szSrc, “%d %c,%s%x%I64d“, output: -28 ffffffe4 4294967268 test 0012FF60 ffee

19、 65518 1234567890123456,位运算 (教材P28),有时我们需要对某个整数类型变量中的某一位(bit)进行操作,比如,判断某一位是否为1,或只改变其中某一位,而保持其他位都不变。C/C+语言提供了“位运算”的操作,能够做到类似的操作。 C/C+语言提供了六种位运算符来进行位运算操作: & 按位与 | 按位或 按位异或 取反 右移,按位与,按位与运算符“&”是双目运算符。其功能是将参与运算的两操作数各对应的二进制位进行与操作,只有对应的两个二进位均为1时,结果的对应二进制位才为1,否则为0。,例如:表达式“21 & 18 ”的计算结果是16(即二进制数10000),因为: 2

20、1 用二进制表示就是: 0000 0000 0000 0000 0000 0000 0001 0101 18 用二进制表示就是: 0000 0000 0000 0000 0000 0000 0001 0010 二者按位与所得结果是: 0000 0000 0000 0000 0000 0000 0001 0000,按位与,按位与运算通常用来将某变量中的某些位清0或保留某些位不变。例如,如果需要将int型变量n的低8位全置成0,而其余位不变,则可以执行: n = n 如何判断一个int型变量n的第7位(从右往左,从0开始数)是否是1 ?,只需看表达式 “n & 0x80”的值是否等于0x80即可。

21、,按位与,按位或运算符“|“是双目运算符。其功能是将参与运算的两操作数各对应的二进制位进行或操作,只有对应的两个二进位都为0时,结果的对应二进制位才是0,否则为1。 例如:表达式“21 | 18 ”的值是23 21: 0000 0000 0000 0000 0000 0000 0001 0101 18: 0000 0000 0000 0000 0000 0000 0001 0010 21|18: 0000 0000 0000 0000 0000 0000 0001 0111 按位或运算通常用来将某变量中的某些位置1或保留某些位不变。 例如,如果需要将int型变量n的低8位全置成1,而其余位不变

22、,则可以执行:,按位或,n |= 0xff;,按位异或运算符“是双目运算符。其功能是将参与运算的两操作数各对应的二进制位进行异或操作,即只有对应的两个二进位不相同时,结果的对应二进制位才是1,否则为0。 例如:表达式“21 18 ”的值是7(即二进制数111)。 21: 0000 0000 0000 0000 0000 0000 0001 0101 18: 0000 0000 0000 0000 0000 0000 0001 0010 2118: 0000 0000 0000 0000 0000 0000 0000 0111,按位异或,异或运算的特点是:如果 ab=c,那么就有 cb = a以

23、及ca=b。此规律可以用来进行最简单的加密和解密。,按位非运算符“”是单目运算符。其功能是将操作数中的二进制位0变成1,1变成0。 例如,表达式“21”的值是无符号整型数 0xffffffea 21: 0000 0000 0000 0000 0000 0000 0001 0101 21: 1111 1111 1111 1111 1111 1111 1110 1010 而下面的语句: printf(“%d,%u,%x“,21,21,21); 输出结果就是: -22,4294967274,ffffffea,按位非,左移运算符“”是双目运算符。其计算结果是将左操作数的各二进位全部左移若干位后得到的值

24、,右操作数指明了要左移的位数。 左移时,高位丢弃,低位补0。 左移运算符不会改变左操作数的值。,左移运算符,例如,常数9有32位,其二进制表示是: 0000 0000 0000 0000 0000 0000 0000 1001 因此,表达式“94”的值,就是将上面的二进制数左移4位,得: 0000 0000 0000 0000 0000 0000 1001 0000 即为十进制的144。 实际上,左移1位,就等于是乘以2,左移n位,就等于是乘以2n。而左移操作比乘法操作快得多。,左移运算符,#include main() int n1 = 15; short n2 = 15; unsigned

25、 short n3 = 15; unsigned char c = 15; n1 = 15; n2 = 15; n3 = 15; c = 6; printf( “n1=%x,n2=%d,n3=%d,c=%x,c4=%d“, n1,n2,n3,c,c 4); 上面程序的输出结果是: n1=78000,n2=-32768,n3=32768,c=c0,c4=3072,n1: 0000 0000 0000 0000 0000 0000 0000 1111 n2: 0000 0000 0000 1111 n3: 0000 0000 0000 1111 c: 0000 1111 n1 = 15: (变成7

26、8000) 0000 0000 0000 0111 1000 0000 0000 0000 n2 = 15: ,(变成-32768) 1000 0000 0000 0000 n3 = 15: (变成 32768) 1000 0000 0000 0000 c = 6; (变成 c0) 1100 0000 c 4 这个表达式是先将 c 转换成整型 0000 0000 0000 0000 0000 0000 1100 0000 然后再左移。 c4=3072,右移运算符“”是双目运算符。其计算结果是把“ ”的左操作数的各二进位全部右移若干位后得到的值,要移动的位数就是“”的右操作数。移出最右边的位就被

27、丢弃。 对于有符号数,如long,int,short,char类型变量,在右移时,符号位(即最高位)将一起移动,并且大多数C/C+编译器规定,如果原符号位为1,则右移时高位就补充1,原符号位为0,则右移时高位就补充0。,右移运算符,对于无符号数,如unsigned long,unsigned int, unsigned short, unsigned char类型的变量,则右移时,高位总是补0。 右移运算符不会改变左操作数的值。 实际上,右移n位,就相当于左操作数除以2n,并且将结果往小里取整。 -25 4 = -2 -2 4 = -1 18 4 = 1,右移运算符,#include int

28、main() int n1 = 15; short n2 = -15; unsigned short n3 = 0xffe0; unsigned char c = 15; n1 = n12; n2 = 3; n3 = 4; c = 3; printf( “n1=%d,n2=%d,n3=%x,c=%x“,n1,n2,n3,c); 上面的程序输出结果是: n1=3,n2=-2,n3=ffe,c=1,n1: 0000 0000 0000 0000 0000 0000 0000 1111 n2: 1111 1111 1111 0001 n3: 1111 1111 1110 0000 c: 0000 1

29、111 n1 = 2: 变成3 0000 0000 0000 0000 0000 0000 0000 0011 n2 = 3: 变成-2 1111 1111 1111 1110 n3 = 4: 变成 ffe 0000 1111 1111 1110 c = 3; 变成1 0000 0001,思考题: 有两个int型的变量a和n(0 = n = 31), 要求写一个表达式,使该表达式的值和a的第n位相同。,答案: ( a n ) & 1 或: (a & (1 n,函数,为什么要用函数 函数声明,定义和调用 函数参数的默认值 函数参数的传递方式 内联函数 函数重载 库函数和头文件 小结,函数,大的任

30、务分成若干小的任务(函数) 函数可以把不需要了解的细节隐藏起来 一般一个函数不要超过50行代码 函数先声明,再调用。定义可以看做声明 一般定义函数放在.cpp中,声明放在.h中,(7) 对于每个程序,都要定义一个main()函数,它是C/C+程序 开始执行时调用的第一个函数. main()在调用其他的函数来完成程序的任务 (8) 程序中函数通信 通过 参数、返回值、全局对象来完成,(6) 函数声明 由返回类型、函数名和参数组成,重点要掌握: 1. 参数列表的作用(编译器会把参数列表和函数名混合在一起,形成新的名字),正因为最后的函数命不同,函数重载才能实现.(C语言不允许函数同名) 2. 参数

31、传递的过程与实质 3. 返回值的实际过程,函数,函数,函数声明(一般写在.h头文件中) 返回值类型 函数名(参数1类型 参数1名称, 参数2类型 参数名称, ); int YwkMax( int a, int int b); 函数定义(一般写在.cpp文件中) int YwkMax( int a, int b ) int c; if ( ab ) c = a; else c = b; return c; ,函数-默认参数,对于某些函数,程序往往会用一些固定的值去调用它.例如对于以某种数制输出整型数的函数print: void print(int value, int base); 在大多数情况

32、下都是以十进制输出,因此base的值总是为10。 C+在定义或声明函数时可以为函数的某个参数指定默认值。当调用函数时没有为它指定实际参数时,系统自动将默认值赋给形式参数。例如,可以将print函数声明为 void print(int value, int base=10); 调用print(20) 等价于 print(20, 10),注意事项 缺省参数无论有几个,都必须放在参数序列的最后, 例如: int SaveName (char *first, char second = “”,char *third = “”, char *fouth = “”); 在函数调用时,若某个参数省略,则其后

33、的参数皆应省略而取其缺省值,函数-默认参数,对参数默认值的指定只有在函数声明处有意义。因为函数的默认值是提供给调用者使用的。,函数-参数默认值,函数参数的默认值,int Function( int a=2 );,int Max( int a, int b ); int a, b; void Function2( int x, int y=Max(a,b), int z=a*b ) ,Function2( 4 ); Function2( 4, 9 ); Function2( 4, 2, 3 ); Function2( 4, , 3 );,等价于Function2(4, Max(a,b), a*b

34、),/ 错误,在函数声明时,指定参数的默认值 默认值的顺序,从右往左的顺序定义 调用时,默认值的顺序?,函数-参数默认值,为什么要默认值?,所有的函数都使用程序运行栈中分配的存储区。该存储区一直保持与该函数相关联,直到函数结束为止。那时,存储区将自动释放以便重新使用。该函数的整个存储区称为活动记录. 系统在函数的活动记录中为函数的每个参数都提供了存储区。参数的存储区长度由它的类型来决定。参数传递是指用函数调用的实参值初始化函数参数存储区的过程。 C+中参数传递的缺省初始化方法是把实参的值拷贝到参数的存储区中。这种称为按值传递(pass-by-value),函数-参数传递,函数-参数传递,三种形

35、式 传值调用 传地址(本质也是传值) 引用传递,函数-变量生命周期/作用域,int Max( int a, int b ) int c; if ( ab ) c = a; else c = b; return c; ,void test( ) int a, b, c; c = Max(a, b); ,参数传递方式?变量生命周期?,不适合按值传递的情况包括: 当大型的类对象必须作为参数传递时。对实际的应用程序而言,分配对象并拷贝到栈中的时间和空间开销往往过大。 当实参的值必须被修改时。例如:交换 void swap1( int a, int b ) int tmp = b; b = a; a =

36、 tmp; ,函数-参数传递,void main( ) int x=1, y=2; swap1( x, y); ,Swap1( a(x), b(y) );,void swap( int a, int b ) int c; c=a; a= b; b=c; void main( ) int x, y; x=3; y=4; swap( x, y); ,3,4,x y,a b c,3,4,3,4,x y,a b c,4,3,3,进入swap 从swap出,考虑函数返回值的实际过程,考虑函数引用类型参数传递的实际过程,void swap2( int *a, int *b ) int tmp = *b;

37、*b = *a; *a = tmp; ,Swap2( a(,void main( ) int x=1, y=2; swap2( ,比较函数swap1 和 swap2的参数传递过程,函数-参数传递,传地址方式,分析参数生命周期,void swap(int *a, int *b) int c; c=*a; *a= *b; *b=c; ,交换x和y的值,可以调用swap(&x, &y),用指针作为参数可以在函数中修改主调程序的变量值,即实现变量传递。必须小心使用!,函数-参数传递,函数-参数传递,引用,引用定义的方式如下: 类型名 ,引用是变量的另一个别名(参照绰号),定义引用时,一定要初始化,#i

38、nclude using namespace std; int main() int n = 4; int ,/ r引用了n,从此r和n是一回事,/修改r就是修改n,/输出4,/输出4,/修改n就是修改r,/ 输出 5,/r2和r引用同一个变量,就是n,/输出 5,函数-参数传递,引用作为函数的返回值【例4.5.2】,参数传引用【例4.5.4.1】,何种变量才能作为函数返回值时的引用 注意变量的生命周期,常引用,内联函数,(3) 带参数 #define max(A, B) (A)(B)?(A):(B),在调用内联函数时,编译器直接用内联函数的代码替换函数调用,于是省去了函数调用的开销。,缺点:

39、产生函数代码的多个副本并分别插入到程序中每一格调用该函数的位置上,使程序更大。,#include using namespace std; inline float cube(float s) return s*s*s; int main() float side; cin side; cout cube(side) endl; return 0; ,内联函数-例子,内联以代码复制(膨胀)为代价,省去了函数调用的开销,提高函数的执行效率。如果相比于执行函数体内代码的时间,函数调用的开销可以忽略不计,那么效率的收获会很小。 以下情况不宜用内联: 如果函数体内的代码比较长,使用内联将导致内存消耗代

40、价较高。 如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。,内联函数-慎用,函数重载,函数名相同,参数不一样。【例4.7.1】 注意函数调用过程,或者函数编译后的样子,函数指针 (教材P107),程序运行期间,每个函数都会占用一段连续的内存空间。而函数名就是该函数所占内存区域的起始地址(也称“入口地址”)。我们可以将函数的入口地址赋给一个指针变量,使该指针变量指向该函数。然后通过指针变量就可以调用这个函数。这种指向函数的指针变量称为“函数指针”。,函数指针,函数指针定义的一般形式为: 类型名 (* 指针变量名)(参数类型1, 参数类型2,); 其中“类型名”表示被指函数的

41、返回值的类型。“(参数类型1, 参数类型2,)”中则依次列出了被指函数的所有参数的类型。例如: int (*pf)(int ,char); 表示pf是一个函数指针,它所指向的函数,返回值类型应是int,该函数应有两个参数,第一个是int 类型,第二个是char类型。,函数指针,可以用一个原型匹配的函数的名字给一个函数指针赋值。要通过函数指针调用它所指向的函数,写法为: 函数指针名(实参表); 下面的程序说明了函数指针的用法,#include void PrintMin(int a,int b) if( ab ) printf(“%d“,a); else printf(“%d“,b); int

42、main() void (* pf)(int ,int); int x = 4, y = 5; pf = PrintMin; pf(x,y); return 0; 上面的程序输出结果是: 4,函数指针应用:快速排序库函数qsort,void qsort(void *base, int nelem, unsigned int width, int ( * pfCompare)( const void *, const void *); base是待排序数组的起始地址, nelem是待排序数组的元素个数, width是待排序数组的每个元素的大小(以字节为单位) pfCompare是一个函数指针,它

43、指向一个“比较函数”。该比较函数应是返回值为int,有两个参数为const void * 的函数 int 函数名(const void * elem1, const void * elem2);,快速排序库函数qsort,排序就是一个不断比较并交换位置的过程。 qsort函数在执行期间,会通过pfCompare指针调用 “比较函数”,调用时将要比较的两个元素的地址传给“比较函数”,然后根据“比较函数”返回值判断两个元素哪个更应该排在前面。 这个“比较函数”不是C/C+的库函数,而是由使用qsort的程序员编写的。在调用qsort时,将“比较函数”的名字作为实参传递给pfCompare。程序员当

44、然清楚该按什么规则决定哪个元素应该在前,哪个元素应该在后,这个规则就体现在“比较函数”中。,qsort函数的用法规定,“比较函数”的原型应是: int 函数名(const void * elem1, const void * elem2); 该函数的两个参数,elem1和elem2,指向待比较的两个元素。也就是说, * elem1和 * elem2就是待比较的两个元素。该函数必须具有以下行为: 1) 如果 * elem1应该排在 * elem2前面,则函数返回值是负整数(任何负整数都行)。 2) 如果 * elem1和* elem2哪个排在前面都行,那么函数返回0 3) 如果 * elem1应

45、该排在 * elem2后面,则函数返回值是正整数(任何正整数都行)。,快速排序库函数qsort,#include #include int MyCompare( const void * elem1, const void * elem2 ) unsigned int * p1, * p2; p1 = (unsigned int *) elem1; p2 = (unsigned int *) elem2; return (* p1 % 10) - (* p2 % 10 ); ,下面的程序,功能是调用qsort库函数,将一个unsigned int数组按照个位数从小到大进行排序。比如 8,23,

46、15三个数,按个位数从小到大排序,就应该是 23,15,8,#define NUM 5 int main() unsigned int anNUM = 8,123,11,10,4 ; qsort( an,NUM,sizeof(unsigned int), MyCompare); for( int i = 0;i NUM; i + ) printf(“%d “,ani); return 0; 上面程序的输出结果是: 10 11 123 4 8,思考题: 如果要将an数组从大到小排序, 那么MyCompare函数该如何编写?,解决方案之一:设置“符号位”,即用最左边的那一位 (也称最高位)作为“符

47、号位”来表示整数的正负,符号位为0说明该整数是非负的,为1则说明该整数是负的。 除符号位外的其余位,对于非负整数来说即等于其绝对值,对于负整数来说,等于其绝对值取反再加1(取反就是把0变成1,把1变成0)。,负整数的表示方式(教材P6),为简单起见,下表以16位的计算机为例,列出了几个整数及其在计算机中的表示形式:,以 -1 为例来说明负数的表示方法。-1的符号位为1,绝对值的二进制表示形式为 : 000 0000 0000 0001 取反后得到: 111 1111 1111 1110,加1后变成 111 1111 1111 1111,再补上最高位的符号位,最终得到其二进制表示形式为: 111

48、1 1111 1111 1111。 由负整数的二进制表示形式算出其绝对值的方法,就是将所有位取反,然后再加1。,命令行参数(教材P157),将用户在CMD窗口输入可执行文件名的方式启动程序时,跟在可执行文件名后面的那些字符串,称为“命令行参数”。命令行参数可以有多个,以空格分隔。比如,在CMD窗口敲: copy file1.txt file2.txt “copy”, “file1.txt”, “file2.txt” 就是命令行参数 如何在程序中获得命令行参数呢?,命令行参数,int main(int argc, char * argv) 参数argc就代表启动程序时,命令行参数的个数。C/C+语言规定,可执行程序程序本身的文件名,也算一个命令行参数,因此,argc的值至少是1。 argv是一个数组,其中的每个元素都是一个char* 类型的指针,该指针指向一个字符串,这个字符串里就存放着命令行参数。例如,argv0指向的字符串就是第一个命令行参数,即可执行程序的文件名,argv1指向第二个命令行参数,argv2指向第三个命令行参数。请看例子程

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1