C陷阱&缺陷-笔记

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 可移植性问题

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wbandzlhgod

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值