一、C语言的指针
1.指针说明
指针是包含另一变量的地址变量。
(1)int *p
p是一个指针,指向一个整形数。
(2)int *p()
p是一个函数,该函数返回一个指向整数的指针。
(3)int (*p)()
p是一个指针,该指针指向一个函数,这个函数返回一个整数。
(4)int *p[]
p是一个数组,该数组的每一个元素是指向整数的指针。
(5)int (*p)[]
p是一个指针,该指针指向一个数组,这个数组的每一个元素是一个整数。
(6)int *(*p)()
p是一个指针,该指针指向一个函数,这个函数返回一个指向整数的指针。
2.指针的初始化(赋地址)
(1)通过符号&取变量(包括结构变量、数组第一个元素)的地址赋给指针;
(2)把数组名赋给指针;
(3)把函数名赋给指向函数的指针;
(4)动态分配内存
例:struct c{double r,i;};
struct c *p;
p=(struct c *)malloc(sizeof(struct c));
3.指针与数组、函数的关系
(1)对于一维数组 int a[i] 或指针 int *a
a+i 指向 a[i]
(2)对于字符串 char s[i] 或指针 char *s
s+i 指向第 i个字符 s[i]
(3)对于二维数组int a[i][j]
*a+j 指向 a[0][j]
*(a+i) 指向 a[i][0]
*(a+i)+j 指向 a[i][j]
例:对于 a[2][3]={1,2,3,4,5,6,}; 有 *(*(a+1)+1)=5;
(4)对于字符串数组char p[i][j] 或字符型指针数组char *p[i]
*p+j 指向第 0个字符串的第 j个字符
*(p+i) 指向第 i个字符串的第 0个字符
*(p+i)+j 指向第 i个字符串的第 j个字符
例:对于 *p[]={"ABC","DEF"}; 有 *(*(p+1)+1)='E';
例:对于 char p[][3]={"ABC","DEF"}; 有 *(*(p+1)+1)='E';
(5)对于指针数组int *a[i]
a[i] 指向 变量i
即 *a[i]=变量i 或 a[i]=&变量i
(6)对于结构struct XY
{int x;int *y}*p;
p是指向结构XY的指针
(*p).x 或 p->x 是表示 x 的内容
(*p).y 或 p->y 是表示指针 y 的值(地址)
*(*p).y 或 *p->y 是表示 y 所指的内容
&(*p).x 或 &p->x 是表示 x 的地址
(7)指向函数的指针
对于 void func(char *str)
{…}; //定义了一个函数
void (*p)(char*);//定义了一个函数指针
p=func; //让指针指向函数
则(*p)("…"); //用指针p可以调用函数func
(8)指向多个不同函数的指针数组
对于void function_1() {…};
…
void function_4() {…}; //定义了四个函数
typedef void(*menu_fcn)();//定义了指向函数的指针
menu_fcn command[4]; //定义了指针数组
command[0]=function_1;
…
command[3]=function_4; //让指针数组指向四个函数
则command[0](); //用指针数组中的一个元素调用一个函数
4.指针的分类
(1)近指针(near):
近指针为16位指针,它只含有地址的偏移量部分。近指针用于不超过64K 字节的单个数据段或代码段。在微、小和中编译模式下产生的数据指针是近指针(缺省状态);在微、小和中编译模式下产生的码指针(指向函数的指针)是近指针(缺省状态)。
(2)远指针(far)
远指针为32位指针,指针的段地址和偏移量都在指针内。可用于任意编译模式。每次使用远指针时都要重装段寄存器。远指针可寻址的目标不能超过64K ,因为远指针增减运算时,段地址不参与运算。在紧凑、大和巨模式下编译产生的数据指针是远指针(缺省状态)。
(3)巨指针(huge)
巨指针为32位指针,指针的段地址和偏移量都在指针内。可用于任意编译模式。远指针寻址的目标可以超过64K 。巨指针是规则化的指针。
5.指针的转换
(1)远指针转换成巨指针
使用以下函数
void normalize(void far * * p)
{
*p=(void far *)(((long)*p&0xffff000f)+(((long)*p&0x0000fff00<<12));
}
6.指针的使用
(1)将浮点数转换成二进制数
float ff=16.5;
unsigned char *cc;
(float*)cc=&ff;
//此时cc的内容为"00008441"
//即cc第一个字节=0;第二个字节=0;第三个字节=0x84;第四个字节=0x41;
(2)将二进制数转换成浮点数
float ff;
unsigned char *cc;
cc=(unsigned char*)malloc(4);
cc=(unsigned char*)&ff;
*(cc+0)=0;
*(cc+1)=0;
*(cc+2)=0x84;
*(cc+3)=0x41;
//此时ff=16.5
free(cc);
二、C 语言的函数
1.用户自定义函数格式
类型 函数名(形式参数表)
参数说明
{
……
}
2.函数的调用方式
(1)传值方式
①传给被调用函数的是整型、长整型、浮点型或双精度型变量。被调用的函数得定义相应的变量为形参。
②传给被调用函数的是结构变量。被调用函数得定义结构变量为形参。
③传给被调用函数的是结构变量的成员。被调用函数得定义与该成员同类的变量为形参。
(2)传址方式
①传给被调用函数的是变量的地址。被调用函数得定义指针变量为形参。
②传给被调用函数的是数组的地址即数组名。被调用的函数得定义数组或指针变量为形参。
③传给被调用函数的是函数的地址即函数名称。被调用函数得定义指向函数的指针变量为形参。
④传给被调用函数的是结构的地址。被调用函数得定义结构指针为形参。
3.函数调用(传值方式)结果的返回
(1)返回的是数值
要求被调用的函数类型与接收返回值的变量类型相同。
(2)返回的是指针
要求被调用的函数是指针函数,其指向的类型与接收的指针变量指向类型相同。
(3)不返回任何值
被调用的函数是void型。
三、C 语言的信息压缩法
1.使用位运算符
要把 5个数据的值压缩到一个字(16位)中,假定其中三个(f1、f2、f3)是标记(真或伪)各占一位;第四个是叫type的整数,其取值范围为 1到12,需要 4位的存储器;最后一个叫作index 的整数,其取值范围为从 0到 500,需占 9位。为此定义一个整型变量:unsigned int packed_data,可包含此 5个值。下图是位域分配。
type index
f1f2f3┌──┐┌───────┐
┌┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┐
└┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┘
把 n的 4个低位的值置入packed_data 的type域中,用下面的语句:
packed_data=(packed_data & ~(0xf<<9))|((n&0xf)<<9);
其中位或符号|左边是将type域置 0,右边是取 n的低 4位后左移9 位到type域中。
从packed_data 的type域中提取数值并把它赋予 n的语句是:
n=(packed_data>>9) & 0xf;
2.使用位域结构
(1)定义一个叫做 packed_struct的结构,含有 5个成员
struct packed_struct
{
unsigned int f1:1
unsigned int f2:1;
unsigned int f3:1;
unsigned int type:4;
unsigned int index:9;
};
(注:在结构中还可以放入普通数据类型,如char c;等)
(2)定义一个变量
struct packed_struct packed_data;
(3)把packed_data 的type 域置于n的低位,用语句
packed_data.type=n;
(4)从packed_data 中提取type域(按要求,把它移到低位),并把它赋予 n,用语句
n=packed_data.type;
3.使用联合
(1)一个无符号整型数与一个结构(其中包含许多无符号变量)共用一存储区,当无符号整型数被赋值后,可通过结构变量获得各位的值。
例如,定义一个联合
union {
unsigned equi;
struct {
unsigned boot :1;
unsigned copr :1;
unsigned rsize:2;
unsigned vmode:2;
unsigned dnum :2;
unsigned :1;
unsigned cnum :3;
unsigned gnum :1;
unsigned :1;
unsigned pnum :2;
}beq;
}eq;
当调用BIOS INT 11H中断后,将AX的值赋给eq.equi,就可以从eq.beq.boot得到PC机有无系统盘的信息;从eq.beq.copr得到PC机有无浮点运算部件的信息。......
(2)两个结构共享同一存储区域
例如:union REGS
struct WORDREGS{unsigned int ax,bx,cx,dx,si,di,cflag,flags};
struct BYTEREGS{unsigned char al,ah,bl,bh,cl,ch,dl,dh};
union REGS {struct WORDREGS x;struct BYTEREGS h;}
四 、位运算
1.数的编码—补码
(1).正数的补码与原码同。
(2).负数的补码为
①第一位(符号位)为 1;
②剩余原码位数逐位取反;
③然后对整个数加 1。
2.位逻辑运算的特殊用途
(1).取一个数中的某些字节
例 a & 0x00ff得到a的低字节,a & 0xff00得到a的高字节。
┌─┬───┬────┬────────┐
│数│十进制│十六进制│ 补码 │
├─┼───┼────┼────────┤
│ a│ │0x2cac │0010110010101100│
│ │ │0x00ff │0000000011111111│
├─┴───┼────┼────────┤
│ 按位与 │ ox00ac │0000000010101100│
│ 运算结果 │ │ │
└─────┴────┴────────┘
(2).将一个数的某些特定位置1
例 a | 0x0f使a的低4位改为1。
┌─┬───┬────┬────────┐
│数│ │十六进制│ 补码 │
├─┼───┼────┼────────┤
│a │ │0x0030 │0000000000110000│
│ │ │0x000f │0000000000001111│
├─┴───┼────┼────────┤
│按位或 │ │0000000000111111│
│运算结果 │ │ │
└─────┴────┴────────┘
(3).将某数特定位置翻转
例 a ^ 0x000f使a的低4位翻转(0变1;1变0)。
┌─┬───┬────┬────────┐
│数│ │十六进制│ 补码 │
├─┼───┼────┼────────┤
│a │ │ 0x007a │0000000001111010│
│ │ │ 0x000f │0000000000001111│
├─┴───┼────┼────────┤
│ 按位异或 │ │0000000001110101│
│ 运算结果 │ │ │
└─────┴────┴────────┘
(4)将a的右起第2位反向变化(1变0,0变1)
a=a^0x02;//(0x02=00000010),异或的意义是"同值为0"
(5).将两个数(整型数)的值互换
例 a=a^b;b=b^a;a=a^b; //三步使得a、b的值互换
3.移位运算的特殊用途
(1).将某数除以2(右移1位)
例 a>>2 使得a被4除
①对于 signed a=-8,a>>2
a=-8
┌─┬─┬─┬─┬─┬─┬─┬─┐
│1 │1 │1 │1 │1 │0 │0 │0 │
└─┴─┴─┴─┴─┴─┴─┴─┘
├─┬─┐ ──> └───┐
┌─┬─┬─┬─┬─┬─┬─┬─┐
│1 │1 │1 │1 │1 │1 │1 │0 │
└─┴─┴─┴─┴─┴─┴─┴─┘
a=-2
②对于unsigned a=248,a>>2
a=248
┌─┬─┬─┬─┬─┬─┬─┬─┐
│1 │1 │1 │1 │1 │0 │0 │0 │
└─┴─┴─┴─┴─┴─┴─┴─┘
└───┐ ──> └───┐
┌─┬─┬─┬─┬─┬─┬─┬─┐
│0 │0 │1 │1 │1 │1 │1 │0 │
└─┴─┴─┴─┴─┴─┴─┴─┘
补0──┴─┘ a=62
(2).将某数乘以2(左移1位)
注 左移时signed 与unsigned变量的情况一样,均要补0。
(3)将x的右起第n(n>=0)位置0
x&=~(1《n); 若x是long,则x&=~((long)1《n);
(4)将x的右起第n(n>=0)位置1
x|=1《n;
若x是长整形数则 x|=(long)1《n;
五、C语言访问CPU寄存器的方法
1.使用联合REGS,和函数 int86() / int86x() / intr()
REGS是用来在进行 DOS软中断调用时向各个寄存器传输数据或从各个寄存器取出返回值。
union REGS 示意图
struct struct
WORDREGS BYTEREGS
┌ ┌───────┬──────┐──┬── ┐
│ │ │ al │ 1 byte │
│ │ ax ├──────┤──┴─ 2 bytes
│ │ │ ah │ │
│ ├───────┼──────┤───── ┘
│ │ │ bl │
│ │ bx ├──────┤
│ │ │ bh │
│ ├───────┼──────┤
│ │ │ cl │
│ │ cx ├──────┤
│ │ │ ch │
│ ├───────┼──────┤
│ │ │ dl │
│ │ dx ├──────┤
│ │ │ dh │
union regs├───────┼──────┤
│ │ │ │
│ │ si │ │
│ │ │ │
│ ├───────┤ │
│ │ │ │
│ │ di │ │
│ │ │ │
│ ├───────┤ │
│ │ │ │
│ │ cflag │ │
│ │ │ │
│ ├───────┤ │
│ │ │ │
│ │ flags │ │
│ │ │ │
└ └───────┴──────┘
│ x 两个结构变量 h │
└── 共享同一存储域 ──┘
2.使用伪变量和函数geninterrupt()
Turbo C 允许使用伪变量直接访问相应的8086寄存器。伪变量的类型有两种。
① unsigned int : _AX、 _BX、 _CX、 _DX、 _CS、 _DS、 _SS、 _ES、 _SP、 _BP、 _DI、 _SI
② unsigned char: _AL、 _AH、 _BL、 _BH、 _CL、 _CH、 _DL、 _DH
六、C语言使用内存和寄存器的方法
1.段和段寄存器
CS用来存放代码段的段地址;DS用来存放全局变量和静态变量所在段(数据段)的段地址;SS用来存放局部变量,参数所在段(堆栈)的段地址。 此外,还有堆段,是动态分配的内存。
2.微模式编译时段的使用情况
只有一个段,从底往高依此装入代码,静态变量和全局变量,堆。从高往低装入堆栈。
3.小模式编译时段的使用情况
数据、堆栈和近堆共用一个段,代码用一个段,还有一个远堆(用far指针存取)。
4.中模式编译时段的使用情况
中模式有多个代码段,其余与小模式一样。函数指针用far指针。
5.紧凑模式编译时段的使用情况
代码,静态数据,堆栈,堆(只有远堆)各有自己的段。静态数据的总量不得超过64K。
6.大模式编译时段的使用情况
静态数据,堆,堆栈的分配与紧凑模式一样;代码段的分配与中模式一样。数据指针和函数指针都是远指针。静态数据的总量不得超过64K。
7.巨模式编译时段的使用情况
来自不同源文件的代码放在不同的段内,来自不同源文件的静态数据也放在不同的段内,只有堆栈是合在一起的。
8.运行库函数分配的内存:
常规内存区
远堆(数据段之外) 用_fmalloc()分配,得到32位指针
├─────────┤
64│堆(未使用的内存)│用malloc()分配,得到16位的位移地址
KB├─────────┤
数│ 栈(局部变量) │
据├─────────┤
段│ 全局和静态变量 │
├─────────┤
七、用C语言写中断服务程序(如果中断服务程序不牵涉到中断链以及 DOS和其本身的重入问题。) ---Turbo C
1.函数类型为interrupt 的中断服务程序定义如下:
#include
void interrupt 函数名(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags);
unsigned int bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags;
2.得先保留原中断函数地址
void interrupt (*保留函数名)( );
保留函数名=getvect(0x中断号);
3.在main函数中用自定义的中断服务程序替换原来的程序
setvect(0x中断号,函数名);
4.在main函数中激活自定义的中断服务程序
(1)先设置要用到的寄存器的值(用伪变量),
(2)geninterrupt(0x中断号);
若替换的是计时中断程序,因PC机内的计时器每秒产生18.2次中断,则每秒自动执行18.2次新的中断程序。
5.事后得将原中断函数地址装回向量表中
setvect(0x中断号,保留函数名);
相关推荐
C语言是计算机科学中的一门基础语言,了解C语言的几个重要知识点对于程序员来说是非常重要的。本文将从内存构造、指针、字符串处理、数组等几个方面来讲解C语言的几个重要知识点。 一、内存构造 在C语言中,每个...
下面将详细讲解C语言中几个关键的数据结构及其应用。 1. 数组:数组是最基本的数据结构,它允许存储相同类型的一组元素。在C语言中,数组可以是一维、二维或多维的。一维数组类似于线性列表,常用于存储顺序数据;...
递归是程序设计中的一个重要概念,一个函数调用自身的过程。在C语言中,递归可以解决许多问题,如阶乘计算、斐波那契数列、树的遍历等。递归的关键在于正确地定义基本情况和递归情况,确保能够终止并避免无限循环。...
数组和指针是C语言中非常重要的概念,它们用于处理数据集合以及内存地址的操作。 - 数组:是相同数据类型元素的集合,可以通过数组名和索引来访问元素。 - 指针:是一种变量,其值为另一个变量的地址,用于动态内存...
本文件内容围绕指针及数组的几个重要表达式展开,详细解读了指针的操作细节,以下是基于文件提供的内容对指针相关知识点的详细阐释。 首先,指针变量通过赋值操作可以存储一个内存地址。如文档中所述,数组a[6]和...
在这个压缩包中,包含220个C语言编写的大型项目,这些项目可以作为学习C语言深入实践的宝贵资源。下面我们将对这些项目进行详细的知识点解析。 首先,"综合CAD系统"通常指的是计算机辅助设计(Computer-Aided ...
这个压缩包“几个C语言小游戏源码”提供了几个使用C语言编写的简单小游戏的源代码,是学习C语言编程的好材料。通过分析这些源码,我们可以深入理解C语言的语法结构、控制流程以及如何运用C语言来实现游戏逻辑。 ...
"几个简单的C语言程序"这个主题涵盖了C语言的基础概念和编程实践,通过一系列实例帮助初学者理解并掌握C语言的核心知识。 首先,C语言是一种结构化编程语言,它的语法简洁明了,强调数据类型和过程式编程。在"程序...
在C语言课程设计中,实训的重要性体现在以下几个方面:首先,实训可以让学生更好地理解C语言的概念和原理,提高学生的编程能力和问题解决能力。其次,实训可以让学生体验到C语言的实际应用,提高了对C语言的兴趣和...
总的来说,这个“十几个C语言源码集合”是一个丰富的学习资料库,涵盖了C语言的基本概念、常用操作以及一些进阶主题。无论是新手还是老手,都可以从中受益,提升自己的编程技能。通过对这些源码的学习和实践,可以更...
首先,类型转换是C语言中的一个重要概念。在教学时,教师需要让学生了解各种数据类型,并强调在使用数据时类型应当保持一致性。然而,在实际编程中,类型转换是一个不可回避的问题。当需要将一个数据类型转换为另一...
8. 预处理器:预处理器负责在编译前处理源代码,如宏定义、条件编译等,它是C语言中的一个重要组成部分。 在"C语言深度剖析"的文档中,可能会对以上这些知识点进行深入讲解,包括它们的工作原理、常见陷阱以及最佳...
在学习51单片机的C语言编程时,需要掌握以下几个关键点: 1. 寄存器操作:了解和掌握51单片机中各种寄存器的功能和操作方法,如SFR(特殊功能寄存器)等,是进行底层开发的基础。 2. 外设编程:包括对I/O口的控制...
2. **函数**:函数是C语言中的重要概念,用于组织代码和实现模块化。课件可能讲解如何定义和调用函数,以及函数的参数传递机制。 3. **指针**:C语言的精髓之一就是指针,它允许直接操作内存。课件会深入解析指针的...
C语言的特点主要包括以下几个方面: 1. 结构化编程:C语言强调结构化编程,支持选择结构(if-else)、循环结构(for, while, do-while)以及函数模块化,使得程序设计逻辑清晰,易于理解和维护。 2. 丰富的运算符...
它们是C语言中实现面向数据结构编程的重要工具。 5. **文件操作**:C语言提供了标准I/O库,如fopen、fwrite、fread、fclose等函数,用于文件的读写操作,这对于数据存储和程序间的数据交换至关重要。 6. **预...
在本压缩包中,我们关注的是与C语言编程相关的实践工作,特别是涉及到“学生成绩管理系统”的几个实例。这些例子提供了深入理解C语言基础以及如何利用C语言开发实际应用的宝贵资源。 首先,"C语言实验"标签表明了这...
本文将基于“几个C语言2级考试试题”这个主题,深入解析相关知识点,帮助备考者巩固和提升C语言技能。 1. **基本语法**:C语言的语法结构严谨,包括变量声明、数据类型、运算符、流程控制语句(如if-else,switch-...
在C语言中,编程题目是学习和掌握语言基础的重要途径。C语言因其高效、简洁而被广泛应用于系统编程、嵌入式开发以及各种算法实现。本压缩包包含了一些经典C语言例题,这些例题旨在帮助学习者巩固基础知识,提高编程...