C语言 练习7~12

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

练习7 7.1
char f(char ch)
{
if('A'<=ch && ch<='Z')
{
ch +=3;
if(ch>'Z')
{
ch -=26;
}
}
else if('a'<=ch && ch<='z')
ch = (ch - 'a' + 3) % 26 + 'a';
return ch;
}
7.2
int f(int x,int y)
{
int sum=x*x+y*y;
if(sum>100)
return sum/100;
return x+y;
}
7.3
int f(int n)
{
int rev = 0;
int m;
while(n > 0)
{
m = n % 10;
rev = rev * 10 + m;
n /= 10;
}
return rev;
}
7.4
//仅仅判断了三位的正整数是否为水仙花数。

int f(int n)
{
int m, sum, num = n;
sum = 0;
while(n > 0)
{
m = n % 10;
sum += m * m * m;
n /= 10;
}
return sum == num;
}
7.5
int f(int a,int b)
{
int r;
r =a % b;
while(r > 0)
{
a = b;
b = r;
r = a % b;
}
return b;
}
7.6
/*输出说明
1表示不能被2或3或5整除;2,3,5分别表示能被2,3,5整除;6表示能被2和3整除;
10表示能被2和5整除;
15表示能被3和5整除;
30表示能同时被2、3和5整除;*/
int f(int n)
{
int m = 1;
if(n % 2 == 0)
m *= 2;
if(n % 3 == 0)
m *= 3;
if(n % 5 == 0)
m *= 5;
return m;
}
7.7
E。

不可以。

无论在何种情况下,convertGrade函数都必须输出一个字符。

可以约定用函数输出字符F表明函数的输入数据非法。

7.8
不能互换使用。

库函数abs用于求整数的绝对值,而库函数fabs用于求小数的绝对值。

函数调用abs(3)的值为整数3,函数调用abs(2.3)的值为整数2;函数调用fabs(3)的值为double 型数3.0,函数调用fabs(2.3)的值为double型数2.3。

注:abs(2.3)的实参为2.3,给形参赋值后,形参的值为2,故它的返回值为2。

7.9
#include<stdio.h>
int f(int n)
{
int rev = 0;
int m;
while(n > 0)
{
m = n % 10;
rev = rev * 10 + m;
n /= 10;
}
return rev;
}
void main()
{
int a;
printf("请输入一个正整数:\n");
scanf("%d",&a);
if(f(a) == a)
printf("%d是一个回文数\n", a);
else
printf("%d不是一个回文数\n", a);
}
7.10
#include<stdio.h>
int f(int a,int b)
{
int r;
r =a % b;
while(r > 0)
{
a = b;
b = r;
r = a % b;
}
return b;
}
int main()
{
int a,b;
printf("请输入两个正整数:\n");
scanf("%d%d", &a, &b);
printf("%d和%d的最小公倍数是%d\n",a, b, a*b/f(a,b));
return 0;
}
7.11
#include<stdio.h>
char f(char ch)
{
if('A'<=ch && ch<='Z')
{
ch +=3;
if(ch>'Z')
{
ch -=26;
}
}
else if('a'<=ch && ch<='z')
ch = (ch - 'a' + 3) % 26 + 'a';
return ch;
}
void main()
{
char str[1000];
int i=0;
printf("请输入一个字符串:");
gets(str);
printf("加密前:%s\n加密后:",str);
while(str[i] != '\0')
{
str[i] = f(str[i]);
++i;
}
puts(str);
}
7.12
#include<stdio.h>
int f(int n)
{
int m = 1;
if(n % 2 == 0)
m *= 2;
if(n % 3 == 0)
m *= 3;
if(n % 5 == 0)
m *= 5;
return m;
}
void main()
{
int a, i;
printf("请输入10个正整数:");
for(i=0; i<10; ++i)
{
scanf("%d", &a);
printf("%d", a);
switch(f(a))
{
case 1:
printf("不能被2,3,5中的任一个数整除。

\n");
break;
case 2:
printf("能被2整除。

\n");
break;
case 3:
printf("能被3整除。

\n");
break;
case 5:
printf("能被5整除。

\n");
break;
case 6:
printf("能被2和3整除。

\n");
break;
case 10:
printf("能被2和5整除。

\n");
case 15:
printf("能被3和5整除。

\n");
break;
case 30:
printf("能同时被2,3,5整除。

\n");
break;
}
}
}
7.13
提示错误:fatal error C1083: Cannot open include file: '7_2.c': No such file or directory
7.14
注意函数形参的类型、个数,返回值等问题。

函数调用执行的过程为对实参求值,用实参给形参赋值,函数执行,执行结束。

7.15
局部变量m和n的作用域从5行起至第9行止。

swap函数形参x和y的作用域从第11行起至第16行止。

变量temp的作用域从12行起至第16行止。

7.16
全局变量m和变量n的作用域从3行起至第16行止。

swap函数形参x和y的作用域从第11行起至第16行止。

变量temp的作用域从12行起至第16行止。

程序的运行结果为:
7.17
交换前:m = 3, n = 5
交换后:m = 5, n = 3
7.18
m = 10, n = 5
7.19
10, 15
10, 20
10, 20
7.20
例7-11在函数calculate中计算了圆的周长并赋值给了全局变量g_circum;而main函数通过访问全局变量g_circum得到了圆的周长。

全局变量的使用方式为,一个函数为全局变量赋值,另一个函数使用全局变量的值。

例7-13(1)中函数vary1改变并使用了全局变量的值。

例7-14函数vary使用了全局变量的值。

例7-15函数vary3把全局变量g_i的作用域限制在函数中,并在函数中使用了全局变量。

全局变量可用于在函数之间传递数据,使用全局变量时应参考例7-11的用法。

7.21
程序7-8中,swap函数执行时局部变量m,n不能在swap函数使用,但这两个变量的生命期却并没有结束。

7.22
7.23
相同。

函数randomize产生的随机序列与种子有关,即与函数中变量seed的值有关。

7.24
例7-17函数sumUpFactor使用全局变量数组a时,为数组a各元素赋值。

函数print使用了全局变量数组a中的各个元素。

7.25
主调函数和被调函数是使用和被使用的关系。

函数通常且有一定的功能(作用),甚至可以将函数(库函数)理解成C语言的命令。

主调函数使用被调函数代替编码完成操作,可以提高编程效率,避免编码时可能出现的错误。

7.26
数组为形参时,数组的长度可有可无不起作用。

如有函数void test(int a[5]),则调用test函数时,实参可以是任意长度的一维int型数组,而并非只能用长度为5的一维int型数组。

因此,数组为形参时常需用另一个整型形参指出数组的长度。

数组为形参时,函数中如改变形参数组元素的值,则实参数组相对应数组元素的值也会随之改变。

7.27
void sort(int a[], int n)
{
int i, j, temp;
for(i=1; i<n; ++i)
{
temp = a[i];
for(j=i; j>=0 && temp<a[j-1]; --j)
a[j] = a[j - 1];
a[j] = temp;
}
}
7.28
//只给出了main函数。

void main()
{
int a[10],i;
printf("排序前:");
for(i=0; i<10; ++i)
{
a[i] = randomize();
printf("%d ", a[i]);
}
sort(a,10);
printf("\n排序后:");
for(i=0; i<10; ++i)
{
printf("%d ", a[i]);
}
printf("\n");
}
7.29
例6-4将转换后数据每一位上的数字都存储到了一个整数数组中,因此,相关函数也需一个数组存储输出结果。

函数的输出结果不能是数组,而数组作形参时可以修改实参数组的元素,故可以把保存输出结果的数组定义为函数的一个形参。

convert函数用于将整数n转换成base进制,转换结果每一位上的数字都存储到了rem数组中。

转换成功时convert函数会返回一个整数,否则将返回另外一个整数。

7.30
函数abc的作用为删除字符数组str存储字符串中的字符d。

程序的输出结果为abcef。

7.31
例7-20中用整型数组的第一个元素存储了数组中待处理元素的长度。

练习7.30中用空字符标示数组存储的字符串的结束位置。

7.32
#include<stdio.h>
int f(int i)
{
if(i == 1)
return 1;
return i + f(i - 1);
}
void main()
{
int i;
printf("请输入一个正整数:");
scanf("%d", &i);
printf("1+2+...+%d=%d\n", i, f(i));
}
7.33
#include<stdio.h>
int f(int i)
{
if(i<10)
return i;
return i % 10 + f(i / 10);
}
void main( )
{
int i;
printf("请输入一个正整数:");
scanf("%d", &i);
printf("%d各位数字和为%d\n", i, f(i));
}
7.34
#include<stdio.h>
int f(int a,int b)
{
if(a%b==0)
return b;
return f(b, a%b);
}
void main()
{
int a, b;
printf("请输入两个正整数:");
scanf("%d%d", &a, &b);
printf("%d和%d的公约数为%d\n", a, b, f(a,b));
}
7.35
x1 = (x0 + a / x0) / 2;
y=mySqrt(a, x1);
7.36
fun(9)=9-fun(9-2)=9-fun(7)=9-(7-fun(5))=9-(7-(5-fun(3)))=9-(7-(5-(3-fun(1))))= 9-(7-(5-(3-2))) 7.37
递归函数recMin用于返回array数组中的最小值。

5
7.38
普通算法如下:
int f(int a[], int n, int key)
{
int i;
for(i=0; i<n; ++i)
if(a[i] == key)
return i;
return -1;
}
递归算法如下:
int f(int a[], int n, int key)
{
if(n < 0)
return -1;
if(a[n-1] == key)
return n - 1;
return f(a, n-1, key);
}
查找成功时,普通算法返回第一个值为key的元素的下标,递归算法返回最后一个值为key 的元素的下标。

7.39
7.40
void f(int n)
{
if(n == 0)
return;
f(n / 2);
printf("%d", n % 2);
}
练习8
8.1预处理的作用是把源文件中不是纯粹的C语言语句转换成C语言语句,转换通常是通过简单的查找替换实现的。

预处理器和C语言编译器是程序编译的两个阶段。

预处理器先于C语言编译器对C语言源文件进行处理,经过处理后的源文件通常就只有单纯的C语言语句了,被C语言编译器处理后就能变成“可执行程序了”。

8.2程序中宏和整型变量的标识符都为A在语法上没有问题,因为程序编译分阶段
进行。

预处理时,程序中以标识符形式出现的宏会被展开,当编译时,源文件实际为:#include<stdio.h>
void main()
{
int n = 5;
printf("A = %d\n", n);
}
8.3
(1)宏名为:LSTR 宏体为:"This is a long string!"
(2)宏名为:AREA 宏体为:(r) 3.1415926 * r * r //注设AREA和(r)之间有空格。

(3)宏名为:N 宏体为:100;
8.4
宏引用N第一次展开为3 * 2 + M 第二次展开为3 * 2 + 5
宏引用N * 2第一次展开为3 * 2 + M * 2 第二次展开为3 * 2 + 5 * 2
宏引用(N) * 3第一次展开为(3 * 2 + M) * 3 第二次展开为(3 * 2 + 5) * 3
8.5 测试程序如下:
#include<stdio.h>
const double PI = 3.1415926;
void main()
{
double r;
printf("请输入圆的半径:");
scanf("%lf", &r);
printf("它的周长为:%f\n", 2 * PI * r);
printf("它的面积为:%f\n", PI * r * r);
}
8.6 简单宏没有类型,可读性不好。

8.7 宏引用ZERO(5)展开后为5-5值为0;宏引用ZERO(3+2)展开为后为3+2-3+2值为4。

可见宏引用ZERO的值不一定为0。

8.8 宏引用B(A+3)第一次展开为((A+2)*A+3),第二次展开为((10+2)*10+3)。

8.9 宏引用MAX(3+2, 3*2)展开后为3+2>3*2?3+2:3*2
8.10 宏引用PR(F(3)*3)第一次展开为printf(" %d\n”, (int)(F(3)*3)),第二次展开为printf(" %d\n”, (int)(3.2+3*3))
8.11 ZERO(3+2)展开后为(3+2)-(3+2)值为0;10*ZERO(5)展开后为10*(5)-(5)值为45。

ZERO(3)/ZERO(3)展开后为(3)-(3)/(3)-(3)值为-1。

8.12 “无歧义”的参数化宏需要多加括号。

8.13 理论上有歧义,如!SQUARE(0)展开后为!(0)*(0)结果为0即假,但0的平方为0,!0的值为1,应为真。

8.14 #define LESS(x, y) (((x) < (y)) ? (x) : (y))
8.15函数调用时实参会向形参赋值,函数myAbs的形参为整型,实参-3.5给形参x赋值后,形参x的值为-3,因此,函数调用myAbs(-3.5)的结果为3而不会是3.5。

参数化宏与函数相比,宏在预处理阶段展开,只是简单的替换,而函数在编译阶段处理,会进行执行状态切换,实参给形参赋值等复杂的操作。

8.16 宏SW AP1中使用了整型变量t,因此它只能用于交换两个整型变量的值,而宏SWAP2却可以交换整型变量或浮点型变量的值。

8.17 参数化宏只是简单的替换,一些简单功能的参数化宏可以超越数据类型的限制而具有了一定的通用性。

函数受限于数据类型的限制只能专注于一种类型,要么求两个整数的较大者,要么求两个浮点数的较大者。

8.18 区别在于到什么目录中查找要包含的文件。

8.19 经编程测试可以。

8.20 头文件不是源文件,只有扩展名为.c的源文件才可以编译。

头文件会被预处理器使用。

预处理器用头文件的内容替换相关的包含命令。

8.21 分别编译源文件test2.c和8_5.c时不会出现语法错误。

包含命令通常把头文件的内容合并到源文件中,而函数声明语句仅仅扩充了函数的作用域。

工程在链接阶段会出现错误,因为在源文件test2.c中有函数myAbs1的定义,而在源文件8_5.c中也有函数myAbs1的定义,工程中头文件header1.h被包含了两次,定义了两个同名的函数myAbs1。

8.22 与例8-5相比,头文件中只有函数声明语句,没有函数定义语句。

一个工程中可多次声明一个函数,因此即使这个头文件被多次包含到工程中也不会出现问题。

8.23 stdio.h文件具体位置在microsoft visual studio\vc98\include\stdio.h,可以用记事本程序打开。

8.24 条件编译可以根据简单的判断结果删除或保留源文件中相关的代码。

8.25 程序中从三个角度理解了宏N。

首先,ifdef判断宏N是否定义,如果已经定义就保留代码,此时,宏N的具体值无关紧要(#define N也可)。

其次,if判断宏N是否为真,即其值是否为非0。

与C语言中的关键字if相比,条件编译指令if仅能进行最简单的判断。

最后,判断宏N是正数、负数还是0。

源文件经过预处理后只剩下三条输出语句了。

8.26
#include<stdio.h>
#define UPPER
void main()
{
char str[100];
int i;
gets(str);
#ifdef UPPER
for(i=0; str[i]!='\0'; ++i)
if(str[i] >= 'a' && str[i] <= 'z')
str[i] -= 'a' - 'A';
#else
for(i=0; str[i]!='\0'; ++i)
if(str[i] >= 'A' && str[i] <= 'Z')
str[i] += 'a' - 'A';
#endif
puts(str);
}
8.27
#include<stdio.h>
void main()
{
char str[100];
int i, flag;
gets(str);
do
{
printf("请输入一个整数:1大写,2小写!\n");
scanf("%d", &flag);
} while(flag != 1 && flag != 2);
if(flag == 1)
{
for(i=0; str[i]!='\0'; ++i)
if(str[i] >= 'a' && str[i] <= 'z')
str[i] -= 'a' - 'A';
}
else
{
for(i=0; str[i]!='\0'; ++i)
if(str[i] >= 'A' && str[i] <= 'Z')
str[i] += 'a' - 'A';
}
puts(str);
}
8.28 练习8.26采用条件编译在源文件编译之前就确定了改写方案,可执行代码比较简短。

练习8.27采用选择结构在程序运行时让用户决定改写方案,功能强大。

8.29 做法可行,因为预处理器仅进行简单的替换,不认识关键字int,只是把源文件中出现的int看成宏名。

9.1
可以,但是无法确定相关储存单元的大小及编码格式。

只有知道了类型,才能确定相关存储单元的大小及编码格式,才能正确使用相关的存储单元。

9.2
整型变量存储整数,指针变量存储地址。

指针与内存地址的关系似乎更像整型与整数的关系。

准确地说,指针变量存储的是存储单元的地址而并非简单的内存地址。

存储单元的地址具有类型。

9.3
地址是整数,但整数不是地址。

多次强调,存储单元的地址有类型,而指针变量也只能用规
定类型的存储单元的地址赋值。

更进一步,指针变量只能指向程序拥有的存储单元。

因此,通常不能用整数给指针变量赋值。

理论上不可以,只有同类型间的指针变量才可以相互赋值,但实际上C语言追求效率,不保证类型安全,有些C语言编译程序“允许”不同类型的指针变量之间相互赋值。

即使单精度指针变量pf真的指向了整型变量i,通过*pf使用变量i的存储单元也没有太大的实际意义。

9.4
不等价。

double *p = &lf;是初始化语句,定义了一个双精度指针变量p,并且它被赋值为变量lf的地址;语句*p=&lf;是赋值语句,把变量lf的地址赋值给指针变量p指向的存储单元,这条语句有两个问题,首先指针变量p没有指向合法的存储单元,不能以间接引用*p的方式使用非法的存储单元,其次,*p标识存储单元的类型为双精度,不能接受变量lf的地址,两者类型不匹配。

double *p = &lf;的作用等同于double *p; p = &lf;。

9.5
程序的运行结果为:
因为语句printf(“%x”, -5);的输出结果为fffffffb,所以变量i实际的内存状态和简化后的内存状态如下:
地址变量
0x0012 ff7c 0x0012 ff7d 0x0012 ff7e 0x0012 ff7f 0x0012 ff80
i
...
1111 1011
1111 1111
1111 1111
1111 1111
...
内容
...
-5
...
内容地址
0x0012 ff7c
0x0012 ff80
实际的内存状态
简化后的内存状态变量pi与变量i的关系如下:
变 量pi
地 址0x0012 ff780x0012 ff7c -5原始状态
0x0012 ff7c i
-5i pi
形象地表示
......内容
9.6
指针变量用于存储某类型存储单元的地址,而存储单元的地址在VC6.0中均为32位,因此,无论何种类型的指针变量,其长度均为4个字节。

不相等。

sizeof(pf)的值为指针变量pf 本身的长度,长度为4个字节。

sizeof(*pf)的值为指针变量pf 指向的存储单元的长度,即双精度型存储单元的长度,为8个字节。

9.7
(1)有错误,不能用整型变量给整型指针变量赋值。

(2)00000005
9.8
程序中指针变量p1指向了整型变量i ,而语句p2=p1;使得指针变量p2也指向了整型变量i 。

因为*p1和*p2也标识了变量i 相关的存储单元,所以语句i = *p1 + *p2;相当于i = i + i;,语句执行后,变量i 的值变为6。

最终程序的输出结果为:6, 6, 6。

9.9
C 语言有直接引用和间接引用两种使用存储单元的方法。

对于指针变量p ,语句p=&i;为指针变量p 赋值为变量i 的地址,实际上是使用直接引用的方式使用了指针变量p 本身的存储单元。

语句*p = 23;就是所谓的以间接引用的方式使用指针变量p 指向的存储单元。

理论上,只要指针变量指向了某存储单元,就可以通过间接引用的方式使用该存储单元,但实际上为避免出现错误,应保证通过间接引用方式只使用合法的存储单元。

9.10
pi 不是空指针!程序的输出结果为:
可见在VC6.0中,没有赋值的局部指针变量会被赋值为0xcccccccc。

9.11
(1)无问题。

(2)无问题。

(3)有问题,其中p2 = *p1;错误,不能用整型变量给指针变量赋值。

(4)有问题,指针变量p1指向了非法的存储单元,语句*p1=*p2;中使用了非法的存储单元。

(5)无问题。

(6)有问题。

指针变量p1只能用整型地址赋值,语句p1=&p2;中&p2的结果并非整型地址而是整型指针地址。

9.12
程序的运行结果为:
a=1, b=7
m=6, n=9
分析如下:
语句a=p1==&m;中p1==&m先求值,因为指针变量p1指向了整型变量m,故求值结果为真,值为1,原语句变为a=1;。

在语句b=(++*p1)/(*p2)+5;中,*p1标识了变量m相关的存储单元,即其可与m互换,*p2可与n互换,原语句可变为b=(++m)/n+5;,变量b被赋值为7,且变量m自增1后变为6。

语句n=*p1+*p2;可变为n=m+n;即n=6+3;。

9.13
(1) #include<stdio.h>
void main()
{
int a,b,c,*pa=&a,*pb=&b,*pc=&c,t;
printf("请输入三个整数!\n");
scanf("%d%d%d", pa, pb, pc);
if(*pa > *pb)
{
t = *pa;
*pa = *pb;
*pb = t;
}
if(*pb > *pc)
{
t = *pb;
*pb = *pc;
*pc = t;
if(*pa > *pb)
{
t = *pa;
*pa = *pb;
*pb = t;
}
}
printf("a = %d, b = %d, c = %d\n",a,b,c);
}
(2) #include<stdio.h>
void main()
{
int a,b,c,*pa=&a,*pb=&b,*pc=&c,*t;
printf("请输入三个整数!\n");
scanf("%d%d%d", pa, pb, pc);
if(*pa > *pb)
{
t = pa;
pa = pb;
pb = t;
}
if(*pb > *pc)
{
t = pb;
pb = pc;
pc = t;
if(*pa > *pb)
{
t = pa;
pa = pb;
pb = t;
}
}
printf("a = %d, b = %d, c = %d\n",a,b,c);
printf("%d<%d<%d\n", *pa, *pb, *pc);
}
9.14
函数调用swap(*p1,*p2)的实参为两个整数,当实参给形参赋值时,会因类型不匹配而出错。

函数调用swap(p1,p2)对实参求值时得到了两个整型存储单元的地址,实参给形参赋值后,两个形参分别指向了整型变量i和j,函数调用swap(p1,p2)等同于swap(&i, &j)。

9.15
函数调用swap(&i, &j)执行时,形参px指向整型变量i,即它的值为0x0012ff00,形参py 指向了整型变量j,即它的值为0x0012ff04。

函数体执行时交换了两个整型指针形参px和py的值,函数执行结束时,形参px指向了变量j,形参py指向了变量i。

由于函数中并没有以间接引用的方式使用变量i和j,所以在main函数中它们并没有改变。

9.16
由于传值调用C语言函数中不可能改变实参的值。

指针作为形参时,实参应为某个存储单元的地址,函数中获得了地址的指针型形参可以用间接引用的方式使用它指向的存储单元,从而改变相关存储单元的内容。

当认为与形参指针对应的是一个存储单元表现为地址时,可以勉强说函数中可以改变“实参”的值。

确切地说指针作形参时,实参是地址,函数中可以使用(改变)此地址处的存储单元,改变并非实参本身。

9.17
不等价,因为在swap函数中变量i不可见。

在变量px和变量i的重叠作用域中,*px与变量i可以互换使用。

借助指针可以拓展存储单元的使用范围。

9.18
指针变量存储的是某类地址,值比较特别而已,与存储了整数的变量没有本质的区别。

任何变量都有作用域和生存期的限制。

9.19
scanf函数的形参显然为指针类型,函数中可以改变与实参相关的存储单元。

把用户输入的整数存入变量i中只需变量i的地址即可,而指针变量pi存储了变量i的地址,因此,可以用语句scanf("%d", pi);。

9.20
(1)scanf函数中与%c对应的地址应为一个字符型存储单元的地址,而&cp不是一个这样的地址。

改成scanf("%c",cp);后没有了语法错误,但实际上还是有问题的。

scanf函数将把用户输入的字符存入变量cp指向的存储单元,但它指向了什么存储单元呢?可以修改char ca, *cp; cp=&ca;scanf("%c", cp);。

其中语句scanf("%c", cp);与scanf("%c", &ca);等价。

(2)int *pi=(int*)malloc(sizeof(int));scanf("%d",pi); free(pi);
9.21
分析:
全局指针变量p指向了变量j。

当test函数执行时,形参x的值为5,pi也指向了变量j。

语句*p=*pi+c;可理解为j=j+c;,与j相关存储单元的内容变为5。

语句x=*pi*c ;可理解为x=j*c;,形参x的值变为15。

程序的输出结果为:
15, 5, 5
5, 5, 5
9.22
(1)
void larger(int x, int y, int *z)
{
if(z == NULL)
return;
if(x > y)
*z = x;
else
*z = y;
}
(2)
#include <stdio.h>
#include "7_1.c"
void main()
{
float m = 3.2, n = 2.3;
int i;
larger(m + n, m - n, &i);
printf("%.1f 和%.1f中较大者为%d\n", m + n, m - n, i);
}
思考:可以定义一个单精度变量f(float f;)再用larger(m+n, m-n, &f);求出较大者吗?9.23
void fac(int n, unsigned int *re)
{
if(n==0 || n==1)
*re = 1;
else
{
fac(n-1, re);
*re = n * *re;
}
}
9.24
(1)语句const double *pf = &m;中关键字const修饰的是double *可理解为指针变量pf指向的存储单元,也就是说指针变量pf可以通过赋值操作指向不同的存储单元,但它指向的存储单元不能被修改,即不能用类似*pf=3;的语句改变与变量m相关的存储单元。

(2)语句double const *pf = &m;中关键字const修饰的是*,同上也可理解为指针变量pf指向的存储单元。

(3)语句double * const pf = &m;中关键字const修饰的是指针变量pf,即不能通过赋值操作改变它指向的存储单元了,它只能指向变量m,但可以的用类似*pf=3;的语句改变与变量m相关的存储单元。

(4)语句const double * const pf = &m;中,指针变量pf只能指向变量m,也不能用类
似*pf=3;的语句改变与变量m相关的存储单元。

函数的首部类似void test(cosnt int *pi)。

9.25
B和D均可以。

9.26
表达式*p++中优先级相同、右结合,自增操作符先求值,子表达式p++的结果为p,故原表达式实为*p,即a[1],值为2,但具有左值性。

该表达式求值过程中使指针变量p自增1,再使用指针变量p时,它已经指向了数组元素a[2]。

表达式*--p中,子表达式--p先求值,指针变量p先减1,即指向了数组元素a[0],故原表达式为a[0],值为1,但具有左值性。

9.27
一维数组由地址连续的一组变量构成,只能获得了首元素的地址,就可以很容易地访问其中的变量,因此,一维数组的关键在于首元素地址。

一维整型数组变量a的值为其首元素的值为其首元素地址,即它指向了数组的首元素;整型指针变量pi可以指向任意的整型存储单元,当然也可以指向数组的首元素。

相同点:它们都存储了整型存储单元的地址。

不同点:数组变量a只能存储固定的地址,不能通过赋值操作改变它指向的存储单元;所有的数组元素的存储单元都算作数组变量a的,故它的长度较大,但整型指针变量pi的长度只有4个字节,因为VC6.0中,地址有32位。

9.28
6.5:
#include<stdio.h>
#define N 10
void main()
{
int *pi, *pmax, temp;
int arr[N];
printf("请输入%d个整数:\n", N);
for(pi=arr; pi<arr+N; ++pi)
scanf("%d", pi);
printf("处理前数组为:\n");
for(pmax=pi=arr; pi<arr+N; ++pi)
{
printf("%d ",*pi);
if(*pi > *pmax)
pmax = pi;
}
for(temp=*pmax; pmax<arr+N-1; ++pmax)
*pmax = *(pmax + 1);
*pmax = temp;
printf("\n处理后数组为:\n");
for(pi=arr; pi<arr+N; ++pi)
printf("%d ", *pi);
printf("\n");
}
6.6:
#include<stdio.h>
#define N 10
void main()
{
int *pi, *p, temp;
int a[N]={20,23,37,52,95};
printf("请输入%d个整数:\n", N-5);
for(pi=a+5; pi<a+N; ++pi)
{
scanf("%d", pi);
temp = *pi;
for(p=pi-1; p>=a &&*p>temp; --p)
*(p+1) = *p;
*(p+1) = temp;
}
printf("数组为:\n");
for(pi=a; pi<a+N; ++pi)
printf("%d ", *pi);
printf("\n");
}
6.7:
#include<stdio.h>
#define N 20
void main()
{
int *pi, *p, temp;
int a[N];
printf("请输入%d个整数:\n", N);
for(pi=a; pi<a+N; ++pi)
scanf("%d", pi);
for(pi=a; pi<a+N; pi+=2)
{
temp = *pi;
for(p=pi-2; p>=a&&*p>temp; p-=2)
*(p+2) = *p;
*(p+2) = temp;
}
printf("数组为:\n");
for(pi=a; pi<a+N; ++pi)
printf("%d ", *pi);
printf("\n");
}
9.29
int strlen(char *str)
{
int i=0;
while(str[i]!=’\0’)
++i;
return i;
}
9.30
int toInt(char *str)
{
int sum,i,flag=1;
sum = i = 0;
if(*str == '-')
{
flag = -1;
i = 1;
}
if(*str == '+')
i = 1;
while(str[i]!='\0')
{
sum = sum * 10 + (str[i++]-'0');
}
return sum * flag;
}
9.31
#include <stdio.h>
void main()
{
char str[100], temp, *p1, *p2, *p3;
gets(str);
for(p1=str; *p1!='\0'; ++p1)
{
p3 = p1;
for(p2=p3+1; *p2!='\0'; ++p2)
if(*p3 > *p2)
p3 = p2;
temp = *p1;
*p1 = *p3;
*p3 = temp;
}
puts(str);
}
9.32
相同。

形参a与一维整型数组a相比,它们的值都是一个整型存储单元的地址,但形参a可以取不同的地址,而一维整型数组不能通过赋值改变它的值。

实参可以是任意长度的一维整型数组了。

9.33
如果函数体内不需要修改指针形参指向的存储单元,都应该用const修饰指针参数。

9.34
test函数使用递归算法求出整型数组a中下标从i开始到n-1结束的最大的元素的下标,下标通过指针变量p指向的存储单元返回。

使用函数test时形参p指向的存储单元的初值必须为下标i到n-1中的任一个下标。

void main()
{
int a[5]={2, 23, -9, 101, 52};
int max = 0;
test(a, 5, 0, &max);
printf("%d", max);
}
9.35
分析:
test函数输出形参i的值,形参a为一维整型数组,但它类型实际为普通的整型指针变量,因此,sizeof(a)的值为4。

在main函数中,变量a是长度为5的一维整型数组,故sizeof(a)的值为20。

数组a指向了其首元素,*a与a[0]可以互换,因此,sizeof(*a)的值为4。

对于数组a,sizeof(a)/sizeof(*a)可以求出其“第一维”的长度。

20
20, 4
5
9.36
分析:
根据例9-29,可以采用多种办法。

9.37
6.16:
#include <stdio.h>
#define N 3
void main()
{
int m[N][N];
int i, j, sum = 0;
int *p;
printf("请输入%d行%d列整型矩阵的元素\n", N, N);
p = &m[0][0];
for(i=0; i<N; ++i)
for(j=0; j<N; ++j)
{
scanf("%d", p);
if(i == j || i + j == N - 1)
sum += *p;
++p;
}
printf("两条主对角线上元素的和为:%d\n", sum);
}
6.17:
#include <stdio.h>
#define N 3
void main()
{
int m[N][N];
int i, j, sum = 0;
int *p = (int*)m;
printf("请输入%d行%d列整型矩阵的元素\n", N, N);
for(i=0; i<N; ++i)
for(j=0; j<N; ++j)
{
scanf("%d", p);
if(i <= j)
sum += *p;
++p;
}
printf("上三角元素的和为:%d\n", sum);
}
9.38
#include<stdio.h>
void main()
{
int a[3][2]={1,2,3,4,5,6};
int i,j;
int *p=&a[0][0];
printf("按行输出:\n");
for(i=0;i<3;++i)
{
for(j=0;j<2;++j)
{
printf("%d ",*(p+i*2+j));
}
printf("\n");
}
printf("按列输出:\n");
for(i=0;i<2;++i)
{
for(j=0;j<3;++j)
{
printf("%d ",*(p+j*2+i));
}
printf("\n");
}
}
9.39
#include<stdio.h>
#define N 3
#define M 4
void main()
{
int a[N][M], k;
int (*p1)[M], *p2, *p;
for(p=&a[0][0]; p<(int*)(a+N); ++p)
scanf("%d", p);
for(p1=a; p1<a+N; ++p1)
{
p = *p1;//p指向了当前行的首元素
for(p2=p; p2<(int*)(p1+1); ++p2)
if(*p2 > *p)
p = p2;
//让p2指向最大值所在列的第0行元素
p2 = a[0] + (p - (int*)p1);
//为简便没有用指针构造循环
for(k=0;k<N;++k)
{
if(*p2 < *p)
break;
p2 += N;
}
if(k == N)
{
printf("鞍点在%d行%d列!\n", p1-a+1, p-(int*)p1+1);
return;
}
}
printf("没有鞍点!\n");
}
9.40
程序的输出结果为:
由程序的输出可知,在VC6.0中相同的字符串常量使用同一个存储单元。

9.41
str是一维字符型数组变量,有四个元素,每个元素分别存储了字符H、i、!和0号字符。

变量str1中一个普通的字符型指针变量,指向了字符串常量"Hi!"的首字符。

语句scanf("%s", str);将向从变量str指向的存储单元开始的连续的多个存储单元中存入一串字符,可是变量str并没有通过赋值操作指向某个合法的存储单元。

9.42
(1)
#include<stdio.h>
#define N 3
void main()
{
int a,b,c,*arr[N]={&a, &b, &c};
int i, j, t;
printf("请输入%d个整数!\n", N);
for(i=0; i<N; ++i)
scanf("%d", arr[i]);
for(i=1; i<N; ++i)
{
t = *arr[i];
for(j=i; j>0&&*arr[j-1]>t; --j)
*arr[j] = *arr[j-1];
*arr[j] = t;
}
printf("a = %d, b = %d, c = %d\n",a,b,c);
}
(2)
#include<stdio.h>
#define N 3
void main()
{
int a,b,c,*arr[N]={&a, &b,&c};
int i, j, *pt;
printf("请输入%d个整数!\n", N);
for(i=0; i<N; ++i)
scanf("%d", arr[i]);
for(i=1; i<N; ++i)
{
pt = arr[i];
for(j=i; j>0&&*arr[j-1]>*pt; --j)
arr[j] = arr[j-1];
arr[j] = pt;
}
printf("a = %d, b = %d, c = %d\n",a,b,c);
printf("*arr[0]=%d,*arr[1]=%d,*arr[2]=%d\n",*arr[0],*arr[1],*arr[2]); }
9.43
1 2 3
4 5 6
7 8 9
9.44
#include<stdio.h>
#include<string.h>
void main()
{
char *str[3]={"Henan","Beijing","Guangzhou"};
char *pt;
int i,j;
for(i=0;i<2;++i)
{
for(j=0;j<2-i;++j)
{
if(strcmp(str[j],str[j+1])>0)
{
pt = str[j];
str[j] = str[j+1];
str[j+1] = pt;
}
}
}
printf("%s,%s,%s\n",str[0],str[1],str[2]);
} 9.45
程序中少了三条语句。

没有变量p 的定义。

在第一个循环中使用指针时没有对其赋值。

在第二个循环中时没有调整指针变量p 指向的存储单元。

完整的程序如下。

#include<stdio.h>
#include<string.h>
void main()
{
int a=5,b=2,c=3;
int *pa[3]={&a, &b, &c};
int *pi, i;
int **p;
for(i=0; i<3; ++i)
{
pi = pa[i];
printf("%2d", *pi);
}
printf("\n");
p = pa;
for(i=0; i<3; ++i)
{
printf("%2d", **p);
++p;
}
}
指针变量和数组变量的关系如图所示。

0x0012 ff7c
pa 5...0x0012 ff78
320x0012 ff780x0012 ff740x0012 ff7c 0x0012 ff7c 0x0012 ff68...0x0012 ff74
0x0012 ff70
0x0012 ff6c 0x0012 ff68
0x0012 ff64
0x0012 ff60
0x0012 ff5c
0x0012 ff58
0x0012 ff80a b c pi p
9.46
用命令test "hello C!"执行程序时,命令行参数只有一个hello C!,即双撇号中的字符串算一个命令行参数。

测试程序如下:
#include<stdio.h>
int main(int argc, char *argv[])
{
while (argc-- > 1)
puts(argv[argc]);
return 0;
}
9.47
#include<stdio.h>
int main(int argc, char** argv)
{
char ca;
if(argc > 1)
{
ca = argv[1][1];
switch(ca)
{
case 's':
case 'S':
printf("您使用了/s选项执行了程序!\n");
printf("5+3=%d\n", 5+3);
break;
case 'p':
case 'P':
printf("您使用了/p选项执行了程序!\n");
printf("5-3=%d\n", 5-3);
break;
case 'a':
case 'A':
printf("您使用了/a选项执行了程序!\n");
printf("5*3=%d\n", 5*3);
break;
case '?':
printf("您使用了/?选项执行了程序!\n");
printf("选项/s做加法、/p做减法、/a做乘法\n");
break;
default:
printf("选项有/s、/p、/a和/?\n");
}。

相关文档
最新文档