版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
上章回顾宏定义特点和注意细节条件编译特点和主要用处文件包含的路径查询规则C语言扩展宏定义的用法C语言编程实践
第二章预习检查异或的运算符是什么位段指针特性C语言关键字本章结构指针特性C语言编程实践C语言常犯错误C语言关键词C语言编程调试C语言编程要点位段位运算课程目标了解位运算的实际应用。了解C语言几个重要关键词的特性和他们之间区别熟悉C语言编程要点熟悉C语言常见的语法错误以及解决方法了解如何去定位错误以及解决错误2C语言编程实践
位运算指针特性C语言关键词C语言几个以混淆的概念C语言编程易犯毛病集合2.1位运算
按位与运算按位或运算按位异或运算求反运算左移运算右移运算2.1位运算
位运算符的含义位运算是指进行二进制位的运算。功能:c语言提供对内存单元的二进制位的操作,使得c语言能够编写系统软件.位运算符&:按位与|:按位或^:按位异或~
:取反<<:左移>>:右移2.1位运算
要点:位运算除~以外,均为二目运算;
运算对象只能为整型或字符型数据.
各个位运算符号的使用:2.1.1按位与运算
按位与──&
格式:x&y
主要用途:取(或保留)1个数的某(些)位,其余各位置0规则:对应位均为1时才为1,否则为0:3&9=1。例如,3&9=1:0011&1001 ──── 0001=1
2.1.2按位或运算
按位或──|
格式:x|y
主要用途:参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就为1规则::对应位均为0时才为0,否则为1:3|9=11。 例如,3|9=11:0011 |1001 ──── 1011=11
2.1.2按位异或运算
按位异或──^
格式:x^y规则:对应位相同时为0,不同时为1:3^9=10。主要用途:使1个数的某(些)位翻转(即原来为1的位变为0,为0的变为1),其余各位不变例子:
00001001^0000010100001100(十进制为12)2.1.3求反运算
求反──~
格式:~y规则:各位翻转,即原来为1的位变成0,原来为0的位变成1:在IBM-PC机中,~0=0xffff,~9=0xfff6。主要用途:间接地构造一个数,以增强程序的可移植性
2.1.4左移运算
按位左移──<<
格式:x<<位数规则:使操作数的各位左移,低位补0,高位溢出:5<<2=20。
2.1.5右移运算
按位右移──>>
格式:x>>位数规则:使操作数的各位右移,移出的低位舍弃;高位:对无符号数和有符号中的正数,补0;有符号数中的负数,取决于所使用的系统:补0的称为“逻辑右移”,补1的称为“算术右移”。例如,20>>2=5说明x、y和“位数”等操作数,都只能是整型或字符型数据。除按位取反为单目运算符外,其余均为双目运算符。参与运算时,操作数x和y,都必须首先转换成二进制形式,然后再执行相应的按位运算。例如,5<<2=20:0101→10100,20>>2=5:10100→00101。2.1.6位运算例子例2
题目:从键盘上输入1个正整数给int变量num,输出由8~11位构成的数(从低位、0号开始编号)基本思路:(1)使变量num右移8位,将8~11位移到低4位上。(2)构造1个低4位为1、其余各位为0的整数。(3)与num进行按位与运算。
/*程序功能:输出一个整数中由8~11位构成的数*/main(){intnum,mask;printf("Inputaintegernumber:");scanf("%d",&num);num>>=8; /*右移8位,将8~11位移到低4位上*/mask=~(~0<<4); /*间接构造1个低4位为1、其余各位为0的整数*/printf("result=0x%x\n",num&mask);}程序运行情况:Inputaintegernumber:1000←┘result=0x3程序说明:~(~0<<4)按位取0的反,为全1;左移4位后,其低4位为0,其余各位为1;再按位取反,则其低4位为1,其余各位为0。这个整数正是我们所需要的。2.1.6位运算例子例1
题目:从键盘上输入1个正整数给int变量num,按二进制位输出该数。
#include"stdio.h"main(){intnum,mask,i;printf("Inputaintegernumber:");scanf("%d",&num);mask=1<<15;/*构造1个最高位为1、其余各位为0的整数(屏蔽字)*/printf("%d=",num);for(i=1;i<=16;i++){ putchar(num&mask?’1’:‘0’); /*输出最高位的值(1/0)*/ num<<=1; /*将次高位移到最高位上*/ if(i%4==0)putchar(‘,’); /*四位一组,用逗号分开*/}printf("\bB\n");}
程序运行情况:
Inputaintegernumber:10001000=0000,0011,1110,1000B阶段小节位运算通常可以做哪些操作位域的含义是什么位域的使用要点有哪些2.3指针特性数据指针数组与动态申请2.3.1数据指针实例:
unsignedchar*p=(unsignedchar*)0xF000FF00;*p=11;数据指针的运算指针自增自减操作的结果取决于指针指向的数据类别int*p=(int*)0xF000FF00;p++(或++p)p=p+sizeof(int),p--(或--p)->p=p-sizeof(int)。2.4C语言关键词consttypedef与definedefine与enumstatic2.4.1constconst--只读说说以下的区别constinta;intconsta;constint*a;int*consta;intconst*aconst;Const的优势关键字const的作用是为给读你代码的人传达非常有用的信息通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码防止便利被无意的代码修改2.4.2typedef与define#define预处理指令在编译预处理时进行简单的替换,不作正确性检查
不需要再在内存中分配变量空间调试程序无法检查用#define说明的常量用#under指令取消typedef声明一个新的类型名代替已有的类型名在编译时处理的不实际分配内存空间2.4.2typedef与define#define实例#defineyour_intint*
your_inta,b;结果相当于int*a,b;只是简单的宏替换即int*a;intb;typedef例子typedefint*your_int;
your_inta,b
结果/a,b都为指向int的指针即int*a;int*b;2.4.3define与enum#enum特点用enum关键字说明的常量由编译程序自动生成,程序员不需要用手工对常量一一赋值。用enum关键字说明常量使程序更清晰易读,因为在定义enum常量的同时也定义了一个枚举类型标识符。在调试程序时通常可以检查枚举常量。需要分配内存来存储常量
2.4.3define与enum#enum例子
enumError_Code{OUT_OF_MEMORY,
INSUFFICIENT_DISK_SPACE,
LOGIC_ERROR,
FILE_NOT_FOUND};
2.4.3define与enum#enum相对#define的优势使程序更容易维护使程序更易读使程序调试起来更方便2.4.4staticstatic的特点本地的全局变量设置变量的链接属性设置变量的存储域static的作用在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用2.5C语言编程要点
C语言存储空间布局
Heap与stack
2.5.1
C程序存储空间布局C语言的组成正文段
初始化数据段(数据段)非初始化数据段(bss段)栈堆2.5.1
C程序存储空间布局C语言存储布局栈|\|//|\|堆未初始化初始化正文段2.5.2Heap与stackHeap与stackStack的空间由操作系统自动分配/释放,Heap上的空间手动分配/释放。Stack空间有限,Heap是很大的自由存储区内存分配域malloc函数分配的内存空间即在堆上程序在编译期对变量和函数分配内存都在栈上进行程序运行过程中函数调用时参数的传递也在栈上进行内存分配的方式从静态存储区域分配:(1)内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。动态存储区:(1)在栈上创建。函数内局部变量的存储单元都可以在栈上创建效率很高,但是分配的内存容量有限。(2)从堆上分配,亦称动态内存分配。动态内存的使用非常灵活,但问题也最多。内存分配的方式静态存储区只读数据区(RO)已初始化读写数据区(RW)低地址高地址未初始化读写数据区(BSS)堆内存的分配方式栈内存的分配方式堆内存栈内存2.5.3动态分配内存——栈与堆
(1)栈内存从高地址向地址分配(不同处理器,不同编译系统,会有所不同),堆内存从低地址到高地址分配(2)在实现机制上:堆使用链表在实现,而栈使用线性存储方式(3)在内存管理上,栈内存是由编译器管理的,而堆内存是由程序调用具体的库函数管理的2.5.3动态分配内存——栈与堆出栈,入栈,修改寄存器的值,满栈、空栈(由处理器的硬件决定)栈内存的使用,参数使用栈空间,自动变量使用栈空间,返回值使用栈空间内层函数可以使用外层函数的栈空间,但外层函数不能使用内层函数的栈空间2.5.3动态分配内存——栈与堆堆内存的分配和释放是程序通过调用C语言的库函数完成的堆内存分配过程中,每次分配将返回一个当前分配内存指针,即堆内存有多个入口点,可单独释放,释放时只需指定内存的指针即可2.5.3动态分配内存——栈与堆指针1指针2指针3指针1指针4指针3指针1指针3指针42.5.3动态内存分配和释放void*malloc(size_tsize);允许从空闲内存池中分配连续内存;size参数是一个所需字节数的整数;返回一个指向void类型的指针,在使用时要根据需要做强制类型转换.voidfree(void*pointer);若*pointer所指的内存已经被释放,或未知的内存地址,则调用free可能产生未知结果.
若*pointer是NULL,则free()不会起任何作用
malloc(例)#include<stdio.h>#include<malloc.h>voidmain(){ int*p,n,i,j,temp; printf("\nEnternumberofelementsinthearray:"); scanf("%d",&n); p=(int*)malloc(n*sizeof(int)); for(i=0;i<n;++i){ printf("\nEnterelementno.%d:",i+1); scanf("%d",p+i); } for(i=0;i<n-1;++i) for(j=i+1;j<n;++j) if(*(p+i)>*(p+j)){ temp=*(p+i); *(p+i)=*(p+j); *(p+j)=temp; } for(i=0;i<n;++i) printf("%d\n",*(p+i));}free()(例)#include<stdio.h>#include<stdlib.h>voidmain(){intnumber,i;int*ptr;printf("Howmanyints?");scanf("%d",&number);ptr=(int*)malloc(number*sizeof(int));if(ptr!=NULL){for(i=0;i<number;i++){ *(ptr+i)=i;}for(i=number;i>0;i--){printf("%d\n",*(ptr+(i-1)));}free(ptr);}else{printf("\nMemoryallocationfailed.\n");}}阶段小节常见的位运算符有哪些什么是数据指针如何定义一个函数指针const有那些特点,主要应用在哪些方面内存堆的操作C强制数据类型转化要注意哪些方面2.6C语言编程易犯毛病集合书写标识符时,忽略了大小写字母的区别忽略了变量的类型,进行了不合法的运算将字符常量与字符串常量混淆忽略了“=”与“==”的区别忘记加分号多加分号输入字符的格式与要求不一致switch语句中漏写break语句忽视了while和do-while语句在细节上的区别定义数组时误用变量2.6.1书写标识符时,忽略了大小写字母的区别分析注意:C认为大写字母和小写字母是两个不同的字符main()
{
inta=5;
printf("%d",A);}2.6.2忽略了变量的类型,进行了不合法的运算分析注意:整型变量a和b可以进行求余运算,而实型变量则不允许进行“求余”运算main()
{
floata,b;
printf("%d",a%b);}2.6.3将字符常量与字符串常量混淆分析charc;
c="a";注意:字符常量是由一对单引号括起来的单个字符字符串常量是一对双引号括起来的字符序列以“\”作字符串结束标志2.6.3将字符常量与字符串常量混淆分析charc;
c="a";注意:字符常量是由一对单引号括起来的单个字符字符串常量是一对双引号括起来的字符序列以“\”作字符串结束标志2.6.4忽略了“=”与“==”的区别分析if(a==3)a=b;
if(a=3)a=b;注意:“=”是赋值运算符“==”是关系运算符2.6.5忘记加分号分析
{a=1
b=2z=x+y;
t=z/100;
printf("%f",t);}2.6.6多加分号分析注意:复合语句的花括号后不应再加分号for(I=0;I<5;I++);会出现什么问题???if(a%3==0);{z=x+y;
t=z/100;
printf("%f",t);};2.6.7switch语句中漏写break语句分析注意:case与break的配对switch(grade){case'A':printf("85~100\n");
case'B':printf("70~84\n");
case'C':printf("60~69\n");
case'D':printf("<60\n");
default:printf("error\n");}2.6.8忽视了while和do-while语句在细节上的区别While语句分析do-while语句分析注意while循环是先判断后执行,而do-while循环是先执行后判断
do-while至少执行一次main(){inta=0,i;
scanf("%d",&i);
while(i<=10)
{a=a+i;
i++;
}
printf("%d",a);}main(){inta=0,i;
scanf("%d",&i);
do{a=a+i;
i++;
}while(i<=10);
printf("%d",a);}2.6.9定义数组时误用变量语句分析intn;
scanf("%d",&n);
inta[n];注意数组名后用方括号括起来的是常量表达式,可以包括常量和符号常量。C不允许对数组的大小作动态定义
2.6.10数组最大下标值语句分析main()
{ staticinta[10]={1,2,3,4,5,6,7,8,9,10};
printf("%d",a[10]);
}注意数组其下标值由0开始
a数组有N个元素,最大下标是N-12.6.11初始化数组时,未使用静态存储语句分析inta[3]={0,1,2};
???与
staticinta[3]={0,1,2};
注意静态存储(static)数组和外部存储(exterm)数组才能初始化
2.6.12同时定义了形参和函数中的局部变量语句分析
语句改正
intmax(x,y)intx,y,z;{ z=x>y?x:y;
return(z);}
intmax(x,y)intx,y;{
intz; z=x>y?x:y;
return(z);}
注意 形参应该在函数体外定义 局部变量应该在函数体内定义2.6.13误认为形参值的改变会影响实参的值语句分析语句改正main(){intx=3,y=4;swap(x,y);printf("%d,%d",x,y);}intswap(intx,inty){intz;z=x;x=y;y=z;}main(){intx=3,y=4;int*p1,*p2;p1=&xp2=&y;swap(p1,p2);printf("%d,%d",x,y);}intswap(int*p1,int*p2){intz;z=*p1;*p1=*p2;*p2=z;}注意 实参和形参之间单向传递2.6.14函数的实参和形参类型不一致语句分析错误分析C要求实参与形参的类型一致
P1---指针参数P1---整形参数main(){intx=3,y=4;int*P1,*p2;P1=&x,p2=&y;swap(P1,p2);printf("%d,%d",x,y);}intswap(intp1,intp2){intz;z=p1;p1=p2;p2=z;}2.7
C语言的调试如果我运行的程序挂起了,应该怎么办如何检测内存漏洞(leak)调试程序的最好方法是什么怎样调试TSR程序能报告条件失败的程序2.7.1如果我运行的程序挂起了,应该怎么办程序挂起的四大原因程序中有死循环;程序运行的时间比所期望的长;程序在等待某些输入信息,并且直到输入正确后才会继续运行;程序设计的目的就是为了延迟一段时间,或者暂停执行。2.7.1.1死循环什么死循环有几张情况可以造成死循环分析例子:解决方式增加对应的调试debug信息/*initializeadoubledimensionarray*/for(a=0;a<10;++a){for(b=0;b<10;++a){array[a][b]==0;}}2.7.1.2运行时间比期望的时间长什么时候回出现这种情况该如何消除分析例子:/*AsubroutinetocalculateFibonaccinumbers*/intfib(inti){if(i<3)return1;elsereturnfib(i-1)+fib(i-2);}
解决方式熟悉基本的语法或者算法运算信息2.7.1.3等待正确的输入原因是:等待正确的输入信息分析例子:#include<stdio.h>main(){FILE*in=fopen("numbers.dat","r");inttotal=0,n;while(fscanf(in,"%d",&n)!=EOF){total+=n;}printf("Thetotalis%d\n",total);fclose(in);}2.7.2如何检测内存漏洞(leak)什么是内存漏洞动态分配的内存单元不再使用却没有被释放什么情况会容易出现这样的问题忘记释放分配给临时缓冲区的内存空间内存漏洞特点最难检测最危险2.7.2如何检测内存漏洞(leak)例子分析voidSayHi(char*name){char*UpName;inta;UpName=malloc(strlen(name)+1);/*Allocatespaceforthename*/for(a=0;a<strlen(name);++a) UpName[a]=toupper(name[a]);UpName[a]='\0‘;printf("Hello,%si\n",UpName);}intmain(){
SayHi("Dave");return(0);}2.7.2如何检测内存漏洞(leak)解决方案小心谨慎地编写程序,充分考虑到内存漏洞的可能性malloc和free要配对使用相应的软件包利用语言的扩展功能2.7.3调试程序的最好方法是什么调试过程的三个要素应该用什么工具调试一个程序?用什么办法才能找出程序中的错误?怎样才能从一开始就避免错误?2.7.3.1应该用什么工具调试一个程序调试工具功能观察程序的运行情况设置断点设置监视2.7.3.2用什么办法才能找出程序中的错误先调试程序中较小的组成部分,然后调试较大的组成部分彻底调试好程序的一个组成部分后,再调试下一个组成部分连续地观察程序流
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 《泵车操作培训A》课件
- 《财务工作手册》课件
- 《清华成本高峰会》课件
- 《建筑设计防火规范》课件
- 畸胎瘤病因介绍
- 《数据恢复软》课件
- 《肛痈肛瘘脱肛》课件
- 养老照护机构老年人在院期间教育服务流程图1-1-1
- 流行性脑脊髓膜炎病因介绍
- 沙门菌属食物中毒病因介绍
- 直燃机机组维护保养规程
- 【标准格式】有限空间告知牌(罐区储罐)
- 中国,全图及各省,地图透明,模版
- “双减”背景下提升初中数学课堂教学效益的策略 论文
- 防止电力生产事故的-二十五项重点要求2023版
- 2023吉首大学EDA试题
- 对账单标准模板
- 尊重知识产权 教学设计
- 课程设计液溴储罐的设计
- 年度先进个人、先进生产工作者申报表
- 三年级上册英语教案-Module 8 Unit 2 Wheres the cat 外研三起
评论
0/150
提交评论