《C Primer Plus》学习笔记——C预处理器和C库
1、在Unix系统中,尖括号告诉预处理器在一个或多个标准系统目录中寻找文件。双引号告诉预处理器先在当前目录(或文件名中指定的其他目录)中寻找文件,然后在标准位置寻找文件。
2、#undef指令:取消定义一个给定的#define
#define LIMIT 400 #undef LIMIT
3、条件编译
#ifdef、#else和#endif指令
#ifdef 宏名 //语句段1 #else //语句段2 #endif
作用:当标识符已经被定义过(一般是用#define命令定义),则对语句段1进行编译,否则编译语句段2。
其中#else部分可以没有
#ifdef 宏名 //语句段1 #endif
#ifndef指令
#ifndef 宏名 //语句段1 #else //语句段2 #endif
作用:若标识符未被定义则编译语句段1,否则编译语句段2。
#else可以用于#ifdef和#ifndef中,但#elif不可以
#if和#elif指令
#if 表达式 // 语句段1 [#else // 语句段2] #endif
#if 表达式1 // 语句段1 #elif 表达式2 // 语句段2 #else // 语句段3 #endif
#error
指令将使编译器显示一条错误信息,然后停止编译
#line
指令可以重置由__LINE__和__FILE__宏报告的行号和文件名
#line 1000 //把当前行号重置为1000 #line 10 “cool.c” //把行号重置为10,文件名重置为cool.c
#pragma
指令没有正式的定义。编译器可以自定义其用途。典型的用法是禁止或允许某些烦人的警告信息
实际的例子
#include <stdio.h> #define LETTER 1 int main( int argc, char * argv[] ) { char str[20]="C Language",c; int i; i=0; while( (c=str[i]) != '\0' ) { i++; #if LETTER if( c>='a' && c<='z' ) c=c-32; #else if( c>='A' && c<='Z' ) c=c+32; #endif printf( "%c",c ); } return 0; }
运行的结果:C LANGUAGE
用条件编译命令的好处:采用条件编译,可以减少被编译的语句,从而减少目标的长度。当条件编译段比较多时,目标程序长度可以大大减少
4、qsort函数
原型:
void qsort (void *base,size_t num,size_t width,int ( *compar)(const void *,const void*))
其中base是排序的一个集合数组,num是这个数组元素的个数,width是一个元素的大小,comp是一个比较函数
例子:对一个长为1000的数组进行排序时,int a[1000]; 那么base应为a,num应为 1000,width应为 sizeof(int),comp函数随自己的命名
qsort(a,1000,sizeof(int),compar);
由小到大排序:
int compar(const void*a,const void*b) { return *(int*)a-*(int*)b; }
5、string.h库中的memcpy()和memmove()
memcpy
原型:
void *memcpy(void *dest, const void *src, size_t n);
从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
memmove()
原型:
void *memmove( void* dest, const void* src, size_t n );
从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
6、可变参数步骤:
(1)在函数原型中使用省略号
(2)在函数定义中创建一个va_list类型的变量
(3)用宏将该变量初始化为一个参数列表
(4)用宏访问这个参数列表
(5)用宏完成清理工作
例子
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <stdarg.h> 3 double sum(int, ...); 4 5 int main(void) 6 { 7 double s,t; 8 9 s = sum(3, 1.1, 2.5, 13.3); 10 t = sum(6, 1.1, 2.1, 13.1, 4.1, 5.1, 6.1); 11 printf("return value for " 12 "sum(3, 1.1, 2.5, 13.3): %g\n", s); 13 printf("return value for " 14 "sum(6, 1.1, 2.1, 13.1, 4.1, 5.1, 6.1): %g\n", t); 15 16 return 0; 17 } 18 19 double sum(int lim,...) 20 { 21 va_list ap; // declare object to hold arguments 22 double tot = 0; 23 int i; 24 25 va_start(ap, lim); // initialize ap to argument list 26 for (i = 0; i < lim; i++) 27 tot += va_arg(ap, double); // access each item in argument list 28 va_end(ap); // clean up 29 30 return tot; 31 }
习题
1、两个数的调和平均数可用如下方法得到:首先对两数的倒数取平均值,最后再取倒数。使用#define指令定义一个宏“函数”执行这个运算。编写一个简单的程序测试该宏。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 3 #define FUN(X, Y) (1/(1/X+1/Y)) 4 5 int main(void) 6 { 7 double m, n; 8 scanf("%lf%lf",&m, &n); 9 printf("FUN of %g and %g : %g\n",m, n, FUN(m, n)); 10 return 0; 11 }
2、ANSI库这样描述clock()函数:
#include<time.h>
clock_t clock (void);
clock_t是在time.h中定义的类型。clock()函数返回处理器时间,其单位依赖于实现(如果无法得到或无法表示处理器时钟,该函数返回值-1)。而同样在time.h中定义的CLOCKS_PER_SEC是每秒的处理器时间单位个数。因此,求出两次调用函数clock()的返回值的差,再用CLOCKS_PER_SEC去除这个差值,结果就是以秒为单位的两次调用之间的时间间隔。在做除法之前,将值的类型指派为double类型,可以将时间精确到小数点以后。编写一个函数,接受一个时间延迟数作为参数,然后运行一个循环,直至这段时间过完。编写一个简单的程序测试该函数。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <time.h> 3 4 void delay(double time); 5 6 int main(void) 7 { 8 double time; 9 printf("input a time(in seconds) to delay(q to quit):"); 10 while( scanf("%lf",&time) == 1 ) 11 { 12 delay(time); 13 printf("time is out!\n"); 14 printf("input a time(in seconds) to delay(q to quit):"); 15 } 16 } 17 18 void delay(double time) 19 { 20 double origin; 21 origin = clock() / CLOCKS_PER_SEC ; 22 while(clock() / CLOCKS_PER_SEC < origin + time); 23 }
3、编写一个函数。该函数接受下列参数:一个int数组的名称,数组大小和一个代表选取次数的值。然后函数从数组中随机选择指定数量的元素并打印它们。每个元素最多选择一次(模拟抽奖或挑选陪审成员)。另外,如果您的实现支持time()(在第12章中介绍)或其他类似函数,可在srand()中使用这个函数的输出来初始化随机数生成器rand()。编写一个简单的程序测试该函数。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <time.h> 3 #include <stdlib.h> 4 5 #define M 20 6 7 void random_pick(int *p, int size, int number); 8 9 int main(void) 10 { 11 int i, member[M], number; 12 srand(time(0)); 13 printf("the M members are:\n"); 14 for(i=0; i<M; i++) 15 { 16 member[i] = rand()%100; 17 printf("%d\t",member[i]); 18 } 19 printf("\ninput the size you want to pick (q to quit):"); 20 while( scanf("%d", &number) == 1 ) 21 { 22 random_pick(member, M, number); 23 printf("input the size you want to pick (q to quit):"); 24 } 25 } 26 27 void random_pick(int *p, int size, int number) 28 { 29 int i,j,count,pick[M],temp,repeat; //pick数组用于存放已选取成员的下标 30 for(i=0, count=0; i<number; ) 31 { 32 temp = rand() % size; 33 for(j=0, repeat=0; j<count; j++) //去除重复数 34 if ( temp == pick[j] ) 35 { 36 repeat = 1; 37 break; 38 } 39 if ( repeat == 0 ) 40 { 41 pick[count++] = temp ; 42 i++; 43 } 44 } 45 46 printf("the picks are:\n"); 47 for(j=0; j<count; j++) 48 printf("%d\t",p[pick[j]]); 49 printf("\n"); 50 }