📄 数据类型转换.01
字号:
元,但下列表达式运算的结果却都为“假”,从而得出错误的结论:
if(a==b)....
if(b==c)....
if(c==d)....
if(d==e)....
if(a==c)....
if(a==d)....
第二,当用“>”、“>=”,“<”和“<=”关系操作符对指针进
行比较操作时,比较的仅仅是偏移量部分,即按无符号的16位整数进
行比较。因此,对于上面这个例子,下列表达式运算的结果将都为
“真”,也得出错误的结论:
if(e>d)....
if(d>c)....
if(c>b)....
if(b>a)....
if(e>a)....三、巨(huge)指针
只有巨指针才是一般C 语言教科书上所说的指针,它像远指针也
占4个字节。与远指针的显著差别是:当增量或减量超过64K字节段边
界时,巨指针会自动修正段基址的值。因此,巨指针不但可以寻址内
存中的任一区域,而且所寻址的数据目标可以超过64K字节。例如:
char huge *hp=(char huge *)0xb800ffff;
hp++;
在指针加1后,hp将指向C800:0000。但是,巨指针总是比较慢的,
因为编译必须生成一小段程序对指针进行32位而不是16位的加减运算。
此外,由于huge指针是规则化指针,每一个实际内存地址只一个
huge指针,所有在指针比较时不会产生错误。四、基(based)指针
前面已经说过,巨指针综合了近指针和远指针的优点。像近指针
一样,基指针只占两个字节,这两个字节是地址的偏移量。像远指针
一样,基指针可以寻址内存中的任一区域。近指针的段地址隐含地取
自程序的数据段,远指针的段地址取自指针本身,基指针的段地址取
法以及基指针的许多技术和应用问题,请见第11章。
五、各类指针之间的转换
far指针可以强制转换为near 指针,做法很简单,抛掉段地址只
保留偏移量。near指针也可以转换为far指针,Turbo C的做法是从相
应的段寄存器中取得段地址。
far指针有时也需要转换为huge 指针,以便对指针进行比较或做
其它操作。一种方法是通过下面这样一个规则化函数:
void normalize(void far **p) {
*p=(void far *)(((long)*p^0xffff000f)+
(((long)*p^0x0000fff0)<<12));
}
另一种办法就是通常的强制类型转换,但强制类型转换不能自动
使转换后的结果规则化。解决的办法是使转换后的huge指针再做一次
加法。例如,设转换后的huge指针是Hp,做一次Hp+=0就使Hp 规则化
了。有返回值的函数
这类函数是最常见的函数,如返回一个字符,返回一个整数,返
回一个指针等,在函数的说明中就说明了要返回什么类型的数据。因
返回整数是最常见的,所以在这种情况下函数说明前的int可以省略。
这里要强调一点的是:函数除可以返回一些C语言标准类型的数外,
还可以返回用户自定义的数据类型,如结构、联合、枚举等。例如,
下面这个对两个字符串相加的程序就是返回一个结构。
struct string {
char str[256];
int strlen;
};
struct string concat(struct string str1,struct string str2)
{
struct string result;
int i,j;
result.str[0]='\0';
result.strlen=0;
if(str1.strlen>0){
for(i=0;i<str1.strle;i++)
result.str[i]=str1.str[i];
result.strlen=str1.strlen;
}
if(str2.strlen>0) {
j=stre1.strlen;
for(i=0;i<str2.strlen;i++)
result.str[i+j]=str2.str[i];
result.strlen+=str1.strlen;
}
return result;
}
无返回值的函数
无返回值的函数与PASCAL等其它结构化语言中的过程很相似,它
们既不返回结果,又不修改参数,而只是执行某一特定的任务。例如,
下面的清屏函数就是这样一个函数。 void clrscr(void)
{
printf("\xlb[2J");
} 既然不返回值,则调用的办法也不一样,不是把函数名放在某一
表达式内调用,而是把函数名连同其调用参数单独人微言轻一个语句。
修改参数的函数
由于C 语言是按传值方式把参数传递给函数的,因此,被调用的
函数不能直接改变调用函数中的变量。但有时确实需要修改调用函数
的参数,尤其在返回值多于一个的函数中必须再借用参数来返回结果。
在这些情况下,必须利用指针来从函数的参数,典型的例子是交换两
个变量的值的函数。如下所示: void swap int(int *i,int *j)
{
int temp;
temp=*i;
*i=*j;
*j=temp;
}
递归函数
C 语言是支持递归调用的。显然,当一个问题蕴含递归关系且结
构比较复杂时,采用递归调用技巧将使程序变得简洁,并增加程序的
可读性。但递归调用技巧的使用是在牺牲存储空间的基础上得到的,
因为它必须在某处维护一个要处理的值的栈。同时,递归也不能提高
执行速度,只是其代码比较紧凑易读。对于像树和链表这样的递归定
义的数据结构,递归函数尤为适用。下面是用递归计算阶乘的例子。
double factorial(int n)
{
if(n>1) return factorial(n-1)*(double)n;
else return 1.0L;
}
参数个数不定的函数
C语言中的某些函数,如vfprintf和vprintf,允许在一些固定参
数之后再带一些不定数目的可变参数。不但如此,C 语言还允许用户
自定义的函数也这样做。为了便于用户编程,Turbo C中提供了以
“va”开头的4个定义va_list数据类型,va_stat,va_arg和va_end
3个宏(函数)。这些定义都在头文件stdarg.h中。 借助于这些宏可以
一步一步地通过整修参数表,尽管被调用函数事先不知道有多少个参
数,也不知道这些参数的类型。
为了编写具有不定数目的可变参数函数,应遵守如下几点:
第1,在C源中包含stdarg.h文件。
第2,如果函数的返回值不是int型,则在调用函数中应做如下形
式的函数说明: <类型><函数名>(<固定参数表>,....);
这个调用形式表明,参数表中至少必须有一个参数是固定的。
第3,函数应按如下形式定义:
<类型><函数名>(<固定参数表>,....);
第4,定义一个表指针,其类型应是va_list,以表明它指向可变
参数表。如下所示:
va_list <可变参数表指针>
第5,调用va_start,初始化表指针: va_start(<可变参数表指针>,<最后一个固定参数的名字>)
这样初始化后,表指针就指向了调用函数传来的可变参数中的第1 个参数。
第6,调用va_arg,取可变参数:
<变量>=va_arg(<可变参数表指针>,<参数的数据类型>)
第1次调用va_arg时,它返回可变参数表中的和第1个参数。随后每一
次调用,它返回表中的下一个参数。每次调用之后自动修正表指针的
值,使它指向随后的一个参数。为了正确地停止读可变参数表,应该
在调用函数可变参数表的最后放一个表结束符(例如-1 或0),在被调
用函数中再去检查这个表结束符。While 循环很适合做这件事情,如
下面的例子所示。
第7,调用va_end,返回到调用函数;
va_end(<可变参数表指针>) 它帮助被调用函数正常返回到调用函数。应在va_arg读完所有参数之后,才调用va_end返回,否则可能
会引起意想不到的结果。
下面这个例子利用一个具有可变参数表的函数,从一个数字表中
挑选值最大的那个数。
#include<stdio.h>
#include<stdarg.h>
#define EOL -1
main()
{
int big;
void vmax(int *,char *,...);
vmax(&big,"The largest of 55,67,41 and 28 is",55,67,41,28,EOL);
printf("%d\n",big);
}
void vmax(int *large,char *message,...)
{
int num;
va_list num_ptr;
va_start(num_ptr,message);
printf("%s",message);
*large=-1;
while((num=va_arg(num_ptr,int))!=EOL)
if(num>*(large)) *(large)=num;
va_end(num_ptr);
}
函数指针及其应用
函数名后面跟一对圆括号(兴许括号内还有参数),将导致去计算
这个函数。仅仅一个函数名则意味着是一个指针,是指向这个函数的
指针。函数指针有两个特殊用途,不太熟练的程序员可能很少使用函
数指针,但在某些场合下若借助于函数指针,则会使程序显得非常精
练。
第1 种用途是把函数名赋给一个指针,然后用这个指针去间接引
用函数。请看下面这个例子: #include<stdio.h>
main()
{
double x;
const double delta=1.0;
const double first=0.0;
const double last=10.0;
double (*fx)();
double quad_poly(double);
fx=quad_poly;
x=first;
while(x<=last){
printf("f(%1f)=%1f\n",x,fx(x));
x+=delta;
}
}
double quad_poly(double x)
{
double a=1.0,b=-3.0,c=5.0;
return ((x*a)*x+b)*x+c;
}
在这个例子里,语句double(*fx)() 说明fx是一个函数指针,该
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -