8.1在缺少函数原型的函数调用中,编译器是如何处理的 答:编译器先假定调用是正确的,同时还假定被调用函数将返回一个整型值,如果调用 事实上是错误的,编译器不能捕获这个错误,要运行这个程序才知道错了:如果被调用函数 返回的不是整数,也将导致错误。 8.2一个定义返回值类型为T1的函数,但该函数体内的 return语句却返回一个类型为 T2的表达式,调用会发生什么情况? 答:如果编译器通过算术转换能够把表达式为T2的类型转换为T1的类型时,程序能正 常运行;否则,编译器将捕获到这个错误 8.3一个定义返回值类型为void的函数,但该函数返回一个值,这将导致什么错误? 答:这是一个语法错误 8.4一个定义返回值类型为非void的函数,但该函数没有返回一个值。这将导致什么 后果? 答: ANSI C认为这种行为是未定义的。未定义的行为其后果是无法预料的。 8.5如果函数的返回值类型不是int类型,并且函数定义出现在函数调用之后,当缺少 函数原型声明会发生什么情况? 答:有些编译器认为这是一个语法错误。这当然是幸运的。但 ANSI C并不检测这个错 误,因此,如果编译器认定函数返回一个整型值,它将产生整数指令处理这个值,如果这个 值实际上不是整型值,其结果通常是错误的。 8.6传递给函数的参数个数、类型和顺序应该与函数定义匹配,编译器能够用函数原型 校验函数调用是否正确。但对于那些没有原型的函数,如果传递的实参与形参不匹配,会出 现什么情况? 答:如果定义在前,调用在后,参数个数不匹配这个错误将被捕获;类型不匹配将实参 自动进行类型提升,例如,char和 short类型的实参被转换为int型, float类型将向 double 类型转换。如果调用在前,定义在后,其结果不可预料。 8.7为什么说在一个表达式内部调用没有返回值的函数将是一个严重的错误? 答:因为该表达式的值将是不可预测的。 8.8对于如下定义语句: 其定义点出现在函数外部和函数内部时,它们在行为上有什么不同? 答:出现在函数外部时,它是外部变量,仅被初始化一次:出现在函数内部时,它是自 动变量,每次进入该代码块时都被初始化一次 8.9如果在某代码块内有如下定义语句 extern int a: 其中a是自动变量。试问:它在语法上是否有错?为什么? 答:它在语法上没有错误。因为关键字 extern对自动变量不起作用,也就不能改变自 动变量的链接属性, extern在这个定义语句中是多余的。但是,如果定义者的本意是想在 此处引用其它函数定义的自动变量a,那他在概念上犯了一个大错误 10下面的程序存在什么错误?为什么? #include <stdio. h float f(float, int) int maino float x=3.14 static int y= f(x, 3)
1 8.1 在缺少函数原型的函数调用中,编译器是如何处理的? 答: 编译器先假定调用是正确的,同时还假定被调用函数将返回一个整型值,如果调用 事实上是错误的,编译器不能捕获这个错误,要运行这个程序才知道错了;如果被调用函数 返回的不是整数,也将导致错误。 8.2 一个定义返回值类型为 T1 的函数,但该函数体内的 return 语句却返回一个类型为 T2 的表达式,调用会发生什么情况? 答:如果编译器通过算术转换能够把表达式为 T2 的类型转换为 T1 的类型时,程序能正 常运行;否则,编译器将捕获到这个错误。 8.3 一个定义返回值类型为 void 的函数,但该函数返回一个值,这将导致什么错误? 答:这是一个语法错误。 8.4 一个定义返回值类型为非 void 的函数,但该函数没有返回一个值。这将导致什么 后果? 答:ANSI C 认为这种行为是未定义的。未定义的行为其后果是无法预料的。 8.5 如果函数的返回值类型不是 int 类型,并且函数定义出现在函数调用之后,当缺少 函数原型声明会发生什么情况? 答:有些编译器认为这是一个语法错误。这当然是幸运的。但 ANSI C 并不检测这个错 误,因此,如果编译器认定函数返回一个整型值,它将产生整数指令处理这个值,如果这个 值实际上不是整型值,其结果通常是错误的。 8.6 传递给函数的参数个数、类型和顺序应该与函数定义匹配,编译器能够用函数原型 校验函数调用是否正确。但对于那些没有原型的函数,如果传递的实参与形参不匹配,会出 现什么情况? 答:如果定义在前,调用在后,参数个数不匹配这个错误将被捕获;类型不匹配将实参 自动进行类型提升,例如,char 和 short 类型的实参被转换为 int 型,float 类型将向 double 类型转换。如果调用在前,定义在后,其结果不可预料。 8.7 为什么说在一个表达式内部调用没有返回值的函数将是一个严重的错误? 答:因为该表达式的值将是不可预测的。 8.8 对于如下定义语句: int x = 10; 其定义点出现在函数外部和函数内部时,它们在行为上有什么不同? 答:出现在函数外部时,它是外部变量,仅被初始化一次;出现在函数内部时,它是自 动变量,每次进入该代码块时都被初始化一次。 8.9 如果在某代码块内有如下定义语句: extern int a; 其中 a 是自动变量。试问:它在语法上是否有错?为什么? 答:它在语法上没有错误。因为关键字 extern 对自动变量不起作用,也就不能改变自 动变量的链接属性,extern 在这个定义语句中是多余的。但是,如果定义者的本意是想在 此处引用其它函数定义的自动变量 a,那他在概念上犯了一个大错误。 8.10 下面的程序存在什么错误?为什么? #include <stdio.h> float f(float,int); int main() { float x = 3.14; static int y = f(x,3);
printf(%f", y) float f(float x, int y) 答:存在编译错。因为只能用常量表达式初始化一个静态变量,而函数调用不是一个常 量表达式。 8.11编写一个函数,对给定的整数 value,函数返回该值中值为1的位的个数 算法分析:根据整数在机内的表示形式,可以采用逐位右移的方法来统计它含“1”的 个数。下面是它的一种比较简洁的实现方案: int count bits(unsigned value) int ones if(value &1)!=0) ones += 1 /*如果最低位为1,计数器的值加1*/ return ones 8.12写一个函数,对有n个元素的 float型指针数组,要求函数返回一个指针,指向 那n个 float型数中最大数。它的函数原型为: float *NumMax(float *p[, int n 算法分析:设置一个指针pMax和一个指针数组p[],pMax用于指向那个最大的数。算 法思想是:pMax初始化为指向p[0]所指向的对象,而p[0]指向第一个 float数,通过for 循环,使p[i]所指对象与pMax所指对象相比较,并将pMax更新为指向其中的较大者。这 样当循环终止时,pMax必指向那个最大的数。下面是它的一种实现方案: float* max(float* pl, int n float* pMax =p[0] int l for(i =1:i<n:i++ if(*p[i] >*pMax) pMax pli] return pMax 8.13仿照例8.6编程:魔术师的猜牌术。魔术师手拿13张迭在一起的黑桃牌,牌面朝 下。对观众说:我不看牌,只数数就可以猜到每张牌是什么。接着,魔术师将最上面的那张 牌数为1,把它翻过来正好是黑桃A,将黑桃A放在桌子上,然后按顺序从上到下数手上的 余牌,第二次数1、2,将第一张牌放在这迭牌的下面,将第二张牌翻过来,正好是黑桃2, 也将它放在桌子上,第三次数1、2、3,将前面两张依次放在这迭牌的下面,再翻第三张牌 正好是黑桃3。这样依次进行将13张牌全翻出来,准确无误。问魔术师手中的牌原始顺序 是怎样安排的? 算法分析:本题与例8.6的求解思路类似,请参考教材,这里不再赘述。所不同的是 这里的空盒数每次要递增1。下面所给程序完全仿照例8.6。 #include <stdio. h
2 printf("%f",y); } float f(float x,int y) { return x+y; } 答:存在编译错。因为只能用常量表达式初始化一个静态变量,而函数调用不是一个常 量表达式。 8.11 编写一个函数,对给定的整数 value,函数返回该值中值为 1 的位的个数。 算法分析:根据整数在机内的表示形式,可以采用逐位右移的方法来统计它含“1”的 个数。下面是它的一种比较简洁的实现方案: int count_bits(unsigned value) { int ones; for(ones = 0; value != 0; value >>= 1) if((value &1) != 0) ones += 1; /* 如果最低位为 1,计数器的值加 1 */ return ones; } 8.12 写一个函数,对有 n 个元素的 float 型指针数组,要求函数返回一个指针,指向 那 n 个 float 型数中最大数。它的函数原型为: float *NumMax(float *p[], int n); 算法分析:设置一个指针 pMax 和一个指针数组 p[],pMax 用于指向那个最大的数。算 法思想是:pMax 初始化为指向 p[0]所指向的对象,而 p[0]指向第一个 float 数,通过 for 循环,使 p[i]所指对象与 pMax 所指对象相比较,并将 pMax 更新为指向其中的较大者。这 样当循环终止时,pMax 必指向那个最大的数。下面是它的一种实现方案: float* max(float* p[], int n) { float* pMax = p[0]; int i; for(i = 1; i < n; i++) if(*p[i] > *pMax) pMax = p[i]; return pMax; } 8.13 仿照例 8.6 编程:魔术师的猜牌术。魔术师手拿 13 张迭在一起的黑桃牌,牌面朝 下。对观众说:我不看牌,只数数就可以猜到每张牌是什么。接着,魔术师将最上面的那张 牌数为 1,把它翻过来正好是黑桃 A,将黑桃 A 放在桌子上,然后按顺序从上到下数手上的 余牌,第二次数 1、2,将第一张牌放在这迭牌的下面,将第二张牌翻过来,正好是黑桃 2, 也将它放在桌子上,第三次数 1、2、3,将前面两张依次放在这迭牌的下面,再翻第三张牌 正好是黑桃 3。这样依次进行将 13 张牌全翻出来,准确无误。问魔术师手中的牌原始顺序 是怎样安排的? 算法分析:本题与例 8.6 的求解思路类似,请参考教材,这里不再赘述。所不同的是, 这里的空盒数每次要递增 1。下面所给程序完全仿照例 8.6。 #include <stdio.h>
#include<stdlib. h #definen 13 id print(void) int pick (int, int) int main (ve inti,pos, index=0;/* index为数组下标*/ pick(i, index) index pos return EXIT SUCCESS int pick(inti, int index)/从当前位置 index开始,找一个合适的空盒 nt count 1 /*对空盒计数*/ do i if( indexⅫN-1) index=0;/*到达数组尾端,下标从头开始*/ if(a[ index]) index++;/*跳过非空的盒子* else( if( count==i) return index;/*找到合适的空盒位置*/ index++; count+;/*对空盒计数,数组下标指向下一个盒子* Iwhile(count<=i) /*控制空盒计数为I*/ void print(void)/*输出*/ printf("the original order of %d cards is: \n,N) printf(%d, ali) printf("b%cn",’) 8.14任取一个十进制整数,将其倒过来后与原数相加,得到一个新的整数后重复以上 步聚,则最终可得到一个回文数。回文数的这一形成规则目前还属于一个猜想,尚未得到数 学上的证明。有些回文数要经历上百个步骤才能获得。请编程验证
3 #include<stdlib.h> #define N 13 void print(void); int pick(int,int); int a[N] = {0}; int main(void) { int i,pos,index = 0; /* index 为数组下标 */ a[0] = 1; for(i = 2; i <= N; ++i) { pos = pick(i,index); a[pos] = i; index = pos; } print(); return EXIT_SUCCESS; } int pick(int i, int index) /* 从当前位置 index 开始,找一个合适的空盒 */ { int count = 1; /* 对空盒计数 */ do{ if(index>N-1) index = 0; /* 到达数组尾端,下标从头开始 */ if(a[index]) index++; /* 跳过非空的盒子 */ else{ if(count==i) return index; /* 找到合适的空盒位置 */ index++;count++; /* 对空盒计数,数组下标指向下一个盒子 */ } }while(count<=i); /* 控制空盒计数为 I */ } void print(void) /* 输出 */ { int i; printf("The original order of %d cards is:\n",N); for(i = 0; i < N; i++) printf("%d,",a[i]); printf("\b%c\n",' '); } 8.14 任取一个十进制整数,将其倒过来后与原数相加,得到一个新的整数后重复以上 步聚,则最终可得到一个回文数。回文数的这一形成规则目前还属于一个猜想,尚未得到数 学上的证明。有些回文数要经历上百个步骤才能获得。请编程验证
算法分析:题目中给出的处理过程很清楚。显然,这里的主要问题是如何将原数倒过来 其方法在教材中已经解决。整个程序在结构上可以考虑用三个函数实现,即main函数、求 个数的反序数和判断是否是回文数函数。程序如下 #include<stdio. h> # define max4294967295/*32位 unsigned long类型的最大值* unsigned long reverse( unsigned long int isPalindrome(unsigned long) int main(void) unsigned long Num, Sum: t count 0 printf(Please enter a number optionaly: scanf (%ld", &Num) printf( the generation process of palindrome: \n") while(!isPalindrome((Sum=reverse(Num))+Num)) /*判整数与其反序之和是否回文数* f (Sum Num > MAX) printf( input error, break. \n"): br else printf("[%d]: %ld+%ld =%ld\n",++count, Num, Sum, Sum+ Num) Num + Sum printf( "[%d]: %ld %ld =%ld\n",++count, Num, Sum, Sum+Num) unsigned long reverse(unsigned long Num) /*求输入整数的反序数*/ uni gned long reNum for(reNUM=0: Num >0: Num/=10) reNum reNum *k 10+ Num 10 return reNu int isPalindrome( uni gned long iNum)/*断给定的整数是否是回文数*/ if(reverse(iNt iNum) return 1 /*若是回文数则返回1*/ else return 0 /*否则返回0 8.15写一函数,用二分法在多个字符串中查找给定的串。其函数原型为:
4 算法分析:题目中给出的处理过程很清楚。显然,这里的主要问题是如何将原数倒过来, 其方法在教材中已经解决。整个程序在结构上可以考虑用三个函数实现,即 main 函数、求 一个数的反序数和判断是否是回文数函数。程序如下: #include<stdio.h> #define MAX 4294967295 /* 32 位 unsigned long 类型的最大值 */ unsigned long reverse( unsigned long); int isPalindrome(unsigned long); int main(void) { unsigned long Num,Sum; int count = 0; printf("Please enter a number optionaly:"); scanf("%ld",&Num); printf("The generation process of palindrome:\n"); while(!isPalindrome((Sum=reverse(Num))+Num)) { /* 判整数与其反序之和是否回文数 */ if(Sum + Num >= MAX) { printf("input error,break.\n"); break; } else { printf("[%d]:%ld + %ld = %ld\n",++count,Num,Sum,Sum+Num); Num += Sum; } } printf("[%d]:%ld + %ld = %ld\n",++count, Num,Sum,Sum+Num); } unsigned long reverse(unsigned long Num) /* 求输入整数的反序数 */ { unsigned long reNum; for(reNUM = 0;Num > 0;Num /= 10) reNum = reNum * 10 + Num % 10; return reNum; } int isPalindrome(unsigned long iNum) /* 断给定的整数是否是回文数 */ { if(reverse(iNum) == iNum) return 1; /* 若是回文数则返回1*/ else return 0; /* 否则返回0 */ } 8.15 写一函数,用二分法在多个字符串中查找给定的串。其函数原型为:
char *binary (char *sp, char *s, int n) 其中的三个参数含义是: (1)sp:指针,它指向备查的多个串的指针数组 (2)s:指针,它指向要查找的串 (3)n:备查串的个数 算法分析:二分法查找又称为折半查找,它的基本思想是:反复的将数组分为两部分, 然后在可能包含目标值的那部分中进行查找。由于二分法查找的前提是要求被查找对象是已 经排好序的,因此,如果这个前提已经成立,算法就很简单。已知备查的n个字符串存储于 个指针数组中,下面是它的一个实现方案 char *binary(char spo, char *s, int n) int low =0, high, mid high = n-1 while(low < higt) mid =(low+ high)/2 if( strcmp(s,sp[mid])<0)/*如果s<sp[mid], strcmp返回负数*/ high d-1 f( strcmp(s,sp[mid])>0)/*如果s>sp[mid], strcmp返回正数*/ else return sp[mid];/*目标已经找到*/ return 0 8.16用递归法求解: m=0,n> g(m-1,2n)+n 算法分析:由于递归式已经显式给出,递归结束的条件为m=0,于是可以直接写出它 的递归函数。下面用一个完整的程序验证该函数的正确性 #include<stdio. h> nt g(int m, int n) if(m = 0) return 0: else return g(m-1, 2*n)+n int maino int m, n, val printf("Input m and n:") scanf(%d%",&m, &n)
5 char *binary(char *sp[],char *s,int n); 其中的三个参数含义是: (1)sp:指针,它指向备查的多个串的指针数组 (2)s: 指针,它指向要查找的串 (3)n: 备查串的个数 算法分析:二分法查找又称为折半查找,它的基本思想是:反复的将数组分为两部分, 然后在可能包含目标值的那部分中进行查找。由于二分法查找的前提是要求被查找对象是已 经排好序的,因此,如果这个前提已经成立,算法就很简单。已知备查的 n 个字符串存储于 一个指针数组中,下面是它的一个实现方案。 char *binary(char *sp[],char *s,int n) { int low = 0,high,mid; high = n-1; while(low <= higt) { mid = (low + high) / 2; if( strcmp(s,sp[mid]) < 0 ) /* 如果 s<sp[mid],strcmp 返回负数 */ high = mid-1; else if(strcmp(s,sp[mid]) > 0) /* 如果 s>sp[mid],strcmp 返回正数 */ low=mid+1; else return sp[mid]; /* 目标已经找到 */ } return 0; } 8.16 用递归法求解: 0 m=0,n>=0 g(m,n)= g(m-1,2n)+n m>0,n>=0 算法分析:由于递归式已经显式给出,递归结束的条件为 m = 0,于是可以直接写出它 的递归函数。下面用一个完整的程序验证该函数的正确性。 #include<stdio.h> int g(int m,int n) { if(m == 0) return 0; else return g(m-1,2*n)+n; } int main() { int m,n,val; printf( "Input m and n: " ); scanf("%d%d",&m,&n); val = g(m,n);