1.1= 与 ==
例1:
本例中循环语句的本意是跳过文件中的空格符、制表符、换行符
while(c=''||c=='/t'||c=='/n')
c=getc(f);
c= ''||c=='/t'||c=='/n'
死循环
例2:
if((filedesc==open(argv[i],0))<0)
error();
永远不会被调用
1.2 & 和 | 不同于&& 和||
1.3 C语言运算符
a---b <==> a-- -b
a - --b
y=x/*p 表示注释 -》y=x/(*p)
n-- 的含义是:n-- >0;
而不是:
n- - >0;
1.4 整型常量
a+++++b的含义是:
a++ + ++b
1.5 字符和字符串
注:用单引号括起来的一个字符代表一个整数
用双引号括起来的一个字符代表一个指针
2.1 函数
float *g() , (*h)();
*g() 《==》*(g()) g是一个函数 该函数的返回值类型为指向浮点数的指针。
h是一个函数指针 ,h所指向的函数的返回值为浮点类型
3.1 指针 数组
struct
{
int p[4];
double x;
}b[17];
声明了b是一个拥有17个元素数组,其中每个元素都是一个结构体
*a 就是数组a中下标为0的元素引用。
*a=84;
清空数组
int month;
for(month=0;month<12;month++)
{
int day;
for(day=0;day<31;day++)
{
calendar[month][day]=0;
}
}
3.1 非数组的指针
库函数strlen返回参数中字符串所包括的字符数目,
而作为结束标志的空字符并未在计算在内,因此,strlen(s)
的值是n,那么字符串的实际需要n+1个字符空间。
char *r,*malloc();
r=malloc(strlen(s)+strlen(t)+1);
if(!r)
{
complain();
exit(1);
}
strcpy(r,s);
strcat(r,t);
/* 一段时间以后*/
free(r);
3.3 作为参数的数组声明
函数的声明:
int strlen(char s[])
{
/*具体声明*/
}
《==》
int strlen(char *s)
{
/*具体声明*/
}
main(int argc,char *argv[])
{
/*具体内容*/
}
《==》
main(int argc,char **argv)
{
/*具体内容*/
}
3.5 空指针并非空字符串
当常数0被转换为指针使用时 这个指针绝对不能被解除应用,
当我们将0赋值给一个指针变量,绝对不能企图使用该指针所指向的内存
中的存储内容
if(p==(char *) 0)
......
3.6 边界计算与不对称边界
C语言 数组中实际不存在的“溢界”元素的地址位于数组所
占内存之后,这个地址可以用于进行赋值和比较
、、以用该元素 、、、就非法啦!
一次可以移动k个字符
void memcpy(char *dest,const char *source ,int k)
{
while(--k>=0)
*dest++=*source++;
}
memcpy
原型:extern void *memcpy(void *dest, void *src, unsigned int count);
用法:#include <string.h>
功能:由src所指内存区域复制count个字节到dest所指内存区域。
说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针。
举例:
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
char *s="Golden Global View";
char d[20];
clrscr();
memcpy(d,s,strlen(s));
d[strlen(s)]='/0';
printf("%s",d);
getchar();
return 0;
}
函数bufwite利用库函数memcpy来一次转移一批字符到
缓冲区、
void bufwrite(char *p,int n)
{
while(n > 0)
{
int k,rem;
if(bufptr==&buffer[N])
flushbuffer();
rem=N-(bufptr-buffer); /*缓冲区当前可用字符数*/
k = n > rem ? rem : n; /*确定移动的字节数*/
memcpy(bufptr,p,k);
bufptr += k;
p += k;
n -= k;
}
}
注:1、从缓冲区中第一个未占用字符开始,赋值k个字符到其中
2、将指针bufptr指向的地址前移k个字符,使其仍然
指向缓冲区中第一个未占用字符
3、输入字符串的指针p前移k个字节符
4、将n减去k
?????????????????????????????????????????????????????????????
#define BUFSIZE (NROWS *(NCOLS-1))
static int buffer[BUFSIZE];
void print(int n)
{
if(bufptr == &buffer[BUFSIZE])
{
static int row = 0;
int *p;
for(p=buffer+row;p<bufptr;p+=NROWS)
printnum(*p);
printnum(n);
printnl();
if(++row == NROWS)
{
printpage();
row = 0;
bufptr = buffer;
}
else
*bugptr++ =n;
}
}
void flush()
{
int row;
int k=bufptr - buffer;
if(k>NROWS)
{
k = NROWS;
}
if(k>0)
{
for(row=0;row<k;row++)
{
int *p;
for(p=buffer+row;p<bufptr;p+=NROWS)
printnum(*p);
printnl();
}
printpage();
}
}
??????????????????????????????????????????????????????????????
例题:我们编写一个程序,该程序按一定顺序生成一些整数,并将这些
整数按列输出
程序的输出可能包括若干页的整数,
#define BUFSIZE (NROWS*(NCOLS-1))
static int buffer[BUFSIZE];
static int *bufptr =buffer;
void print(int n)
{
if(bufptr==&buffer[BUFSIZE]) <==> (bufptr>=&buffer[BUFSIZE-1])
{
}else
{
*bufptr++=n;
}
}
********************************************************************************
void print(int n)
{
if(bufptr == &buffer[BUFSIZE])
{
static int row = 0;
int *p;
for(p=buffer+row;p<bufptr;p+=NROWS)
printnum(*p);
printnum(n);
printnl();
if(++row == NROWS)
{
printpage();
row = 0;
bufptr = buffer;
}
else
*bugptr++ =n;
}
}
void flush()
{
int row;
int k=bufptr - buffer;
if(k>NROWS)
{
k = NROWS;
}
if(k>0)
{
for(row=0;row<k;row++)
{
int *p;
for(p=buffer+row;p<bufptr;p+=NROWS)
printnum(*p);
printnl();
}
printpage();
}
}
********************************************************************************
3.7 求值顺序
除数问题:
if(count!=0 && sum/count < samllaverage)
printf("average < %g/n",smallaverage);
逗号运算符,首先对左侧操作数求值,然后该值被“丢弃”,在对右侧的
操作数求值,
for(i=0;i<n;i++)
y[i]=x[i];
3.8 运算符&& || !
3.9 整数溢出
3.10
为函数main提供返回值
练习:
编写一个函数,对一个已排序的整数表执行二分查找。
函数的输入 包括一个指向表头的指针,表中的元素个数,
以及待查找的数值。函数的输出时一个指向满足查找要求的
元素的指针,当未查找到满足要求的数值时,输出一个NULL指针。
4.1 连接
4.2 声明与定义
extern int a;
说明a是一个外部变量
static修饰符是一个能够减少命名冲突的有用的工具。
作用域:限定在一个源文件中,
static也可以用于函数
4.4 形参 实参 返回值
任何c函数都有一个形参类表,列表中的每个参数都是一个变量
函数调用过程中被初始化。
一个函数如果形参列表为空 ,在被调用时 实参列表为空
如果调用函数 和被调函数 在不同的文件中
在调用函数中必须对北调函数的声明:
4.5 检查外部类型
extern
4.6 头文件
每一外部对象只在一个地方声明,这个声明的地方一般
就在一个头文件中,需要用到该外部对象的所有模块都
应该包括这个头文件。
需要注意的是,定义该外部对象的模块也应该包括这个头文件。
5·1 返回整数的getchar函数
getchar 函数名: getchar
功 能: 从stdio流中读字符
用 法: int getchar(void);
注解:
getchar有一个int型的返回值.当程序调用getchar时.程序就等着用户按键.用户输入的字符被存放在键盘缓冲区中.直到用户按回车为止(回车字符也放在缓冲区中).当用户键入回车之后,getchar才开始从stdio流中每次读入一个字符.getchar函数的返回值是用户输入的第一个字符的ASCII码,如出错返回-1,且将用户输入的字符回显到屏幕.如用户在按回车之前输入了不止一个字符,其他字符会保留在键盘缓存区中,等待后续getchar调用读取.也就是说,后续的getchar调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完为后,才等待用户按键.
getch与getchar基本功能相同,差别是getch直接从键盘获取键值,不等待用户按回车,只要用户按一个键,getch就立刻返回, getch返回值是用户输入的ASCII码,出错返回-1.输入的字符不会回显在屏幕上.getch函数常用于程序调试中,在调试时,在关键位置显示有关的结果以待查看,然后用getch函数暂停程序运行,当按任意键后程序继续运行.
getch()是非缓冲输入函数,就是不能用getch()来接受缓冲区已存在的字符
#include<conio.h>
#include<stdio.h>
void main()
{
char c;
printf("Please enter char/n");
while((c=getchar())!='/n')
putchar(c);
putchar('/n');
printf("***********");
getch();
}
5.1更新顺序文件
fseek 函数名: fseek
功 能: 重定位流上的文件指针
用 法: int fseek(FILE *stream, long offset, int fromwhere);
描 述: 函数设置文件指针stream的位置。如果执行成功,stream将指向以fromwhere为基准,偏移offset个字节的位置。如果执行失败(比如offset超过文件自身大小),则不改变stream指向的位置。
返回值: 成功,返回0,否则返回其他值。
第一个参数stream为文件指针
第二个参数offset为偏移量,整数表示正向偏移,负数表示负向偏移
第三个参数origin设定从文件的哪里开始偏移,可能取值为:SEEK_CUR、 SEEK_END 或 SEEK_SET
SEEK_SET: 文件开头
SEEK_CUR: 当前位置
SEEK_END: 文件结尾
其中SEEK_SET,SEEK_CUR和SEEK_END和依次为0,1和2.
简言之:
fseek(fp,100L,0);把fp指针移动到离文件开头100字节处;
fseek(fp,100L,1);把fp指针移动到离文件当前位置100字节处;
fseek(fp,100L,2);把fp指针退回到离文件结尾100字节处。
一个记录需要重新写入文件
5.2更新顺序文件
FILE *fp;
struct record rec;
while(fread((char *)&rec,sizeof(rec),1,fp)==1)
/*对rec执行的某些操作*/
if(/*rec必须重新写入*/)
{
fseek(fp , -(long)sizeof(rec) , 1);
fwrite((char *)&rec,sizeof(rec),1,fp);
fseek(fp,0L,1);
}
5.3 缓冲输出与内存分配
setbuf函数
char buf[BUGSIZE];
setbuf(stdout,buf);
1.缓冲区数组buf的声明为
static char buf[BUFSIZE];
2.将buf声明为全局变量
动态分配缓冲区,在程序中并不主动释放分配的缓冲区
注:
char *malloc;
setbuf(stdout,malloc(BUFSIZE));
5.4 使用errno检测错误
5.5库函数 signal
头文件
#include<signal.h>
signal(signal type,headler function);
single type代表系统头文件signal.h中定义的某些常量,
这些常量用来标识single函数将要捕获的信号类型
handler function 是当指定的事件发生时,将要加以调用的
的事件处理函数。
longjmp
exit
退出程序:
trap 或者siganal 函数就可以让你在
某种不正常退出的情况下,再调用你指
定的函数,可以做些清理工作啊什么的。
预处理器
6.1 不能忽视宏定义中的空格
#define f (x) ((x)-1)
则定义f代表 (x) ((x)-1)
#define f(x) ((x)-1)
则定义f(x)代表 ((x)-1)
6.2 宏并不是函数
#define abs(x) (((x)>=0)?(x):-(x))
或者
#define max(a,b) ((a)>(b)?(a):(b))
括号不能省
例如 abs(a-b)
abs(a)+1
6.3 宏并不是语句
6.4 宏并不是类型定义
使多个不同变量的类型可在一个地方说明:
#define FOTYPE struct foo
FOTYPE a;
FOTYPE b;
typedef struct foo FOTYPE;
区别:
#define T1 struct foo*
typedef struct foo *T2;
T1 a,b; //声明wei:struct foo *a,b;
a声明为指向结构体的指针
b定义为结构体
T2 a,b; a,b都声明为指向结构体的指针
第7章 可移植性缺陷
7.4 字符是有符号整数还是无符号整数
7.5 移位运算符
mid = (low + high) >> 1;
与
mid = (low + high) / 2;
完全等效,而且前者的执行速度也要快的多啊!
7.6 内存为置0
#include<stdio.h>
void main()
{
int *p;
p=NULL;
printf("%d",*p);
}
禁止读取内存地址0的机器上,这个程序将会失败,
7.7 除法运算时发生的截断
7.8 随机数的大小
rand函数 返回1-2的15次幂-1
rand和srand的用法
首先我们要对rand&srand有个总体的看法:
srand初始化随机种子,rand产生随机数
表头文件: #include<stdlib.h>
定义函数 :int rand(void)
函数说明 :
因为rand的内部实现是用线性同余法做的,他不是真的随机数,只不过是因为其周期特别长,所以有一定的范围里可看成是随机的,rand()会返回一随机数值,范围在0至RAND_MAX 间。在调用此函数产生随机数前,必须先利用srand()设好随机数种子,如果未设随机数种子,rand()在调用时会自动设随机数种子为1。rand ()产生的是假随机数字,每次执行时是相同的。若要不同,以不同的值来初始化它.初始化的函数就是srand()。
返回值:
返回0至RAND_MAX之间的随机整数值,RAND_MAX的范围最少是在32767之间(int),即双字节(16位数)。若用unsigned int 双字节是65535,四字节是4294967295的整数范围。
0~RAND_MAX每个数字被选中的机率是相同的。
srand(设置随机数种子)
表头文件:#include<stdlib.h>
定义函数:void srand (unsigned int seed);
函数说明:
srand()用来设置rand()产生随机数时的随机数种子。参数seed必须是个整数,通常可以利用geypid()或time(0)的返回值来当做seed。如果每次seed都设相同值,rand()所产生的随机数值每次就会一样
除以上所说的之外,补充一点就是srand这个函数一定要放在循环外面或者是循环调用的外面,否则的话得到的是相同的数字
randomize()
原形是void randomize(),功能是用来始初rand() 的种子的初始值,而且该值是不确定的,它相当于srand((unsign)(time(NULL)) 不过应注意的是randomize()的功能要通过time来实现所以在调用它时头文件要包含time.h罢了
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
main()
{
int i,j;
time_t t;
srand((unsigned) time(&t));
//srand((int)time(0));
for(i=0;i<3;i++)
{
j=1+(int)(10.0*rand()/(RAND_MAX+1.0));
printf(" %d ",j);
}
}
7.9大小写字母转换
toupper towlower 函数
#define _toupper(c) ((c)+'A'-'a')
#define _tolower(c) ((c)+'a'-'A')
7.10 首先释放,然后重新分配
malloc realloc free
ptr是一个指针
如果ptr指向的是一块最近一次调用malloc,realloc
calloc 分配的内存,即使这块内存已释放,realloc函数仍然可以
工作。
因此,可以通过调节free、malloc和realloc的调用顺序,
充分利用malloc函数的搜索策略来压缩存储空间
固有:free(p);
p=realloc(p,newsize);
7.11 可移植性问题