《C Primer Plus》(第六版)第十二章:存储类别、链接和内存管理|复习题与编程练习答案参考

复习题

1.哪些类别的变量可以成为它所在函数的局部变量?

自动存储类别、寄存器存储类别、静态无链接存储类别。

2.哪些类别的变量在它所在程序的运行期一直存在?

静态无链接存储类别、静态内部链接存储类别、静态外部链接存储类被

3.哪些类别的变量可以被多个文件使用?哪些类别的变量仅限于在一个文件中使用?

静态外部链接存储类别可以被多个文件使用;静态内部链接存储类别仅限于一个文件中使用。

4.块作用域变量具有什么链接属性?

无链接

5.extern关键字有什么用途?

关键字extern用在声明处,表明该变量或函数已经在别处定义。

6.考虑下面两行代码,就输出的结果而言有何异同:

int * p1 = (int *)malloc(100 * sizeof(int));
int * p1 = (int *)calloc(100, sizeof(int));
两者都分配了一个内含100字节的int类型数组,calloc把数组中的每个元素设置为0

7.下面的变量对哪些函数可见?程序是否有误?

/* 文件 1 */
int daisy;
int main(void)
{
int lily;
...;
}
int petal()
{
extern int daisy, lily;
...;
}
/* 文件 2 */
extern int daisy;
static int lily;
int rose;
int stem()
{
int rose;
...;
}
void root()
{
...;
}
默认情况下, daisy 只对 main() 可见,以 extern 声明的 daisy 才对 petal() 、 stem()和 root() 可见。文件 2 中的 extern int daisy; 声明使得 daisy 对文件 2 中的所有函数都可见。第1 lily main() 的局部变量。 petal() 函数中引用的 lily 是错误的,因为两个文件中都没有外部链接的lily 。虽然文件 2 中有一个静态的lily,但是它只对文件 2 可见。第 1 个外部 rose root() 函数可见,但是 stem() 中的局部rose 覆盖了外部的 rose

8.下面程序会打印什么?

#include <stdio.h>
char color = 'B';
void first(void);
void second(void);
int main(void)
{
extern char color;
printf("color in main() is %c\n", color);
first();
printf("color in main() is %c\n", color);
second();
printf("color in main() is %c\n", color);
return 0;
}
void first(void)
{
char color;
color = 'R';
printf("color in first() is %c\n", color);
}
void second(void)
{
color = 'G';
printf("color in second() is %c\n", color);
}
color in main() is B
color in first() is R
color in main() is B
color in second() is G
color in main() is G
first()函数使用的color仅限在这个函数使用,调用完了以后,该值就会销毁;
second()函数使用的是主函数声明的静态外部链接color,所以将color的值修改成立G。

9.假设文件的开始处有如下声明:

static int plink;
int value_ct(const int arr[], int value, int n);
a. 以上声明表明了程序员的什么意图?
b. const int value const int n 分别替换 int value int n ,是否对主调程序
的值加强保护。
a.声明告诉我们,程序将使用一个变量 plink ,该文件包含的函数都可以使用这个变量。calu_ct() 函数的第 1 个参数是指向一个整数的指针,并假定它指向内含n 个元素的数组。这里关键是要理解该程序不允许使用指针 arr修改原始数组中的值。
b. 不会。 value n 已经是原始数据的备份,所以该函数无法更改主调函数中相应的值。这些声明的作用是防止函数修改value n 的值。例如,如果用const 限定 n ,就不能使用 n++ 表达式。

编程练习

1.不使用全局变量,重写程序清单12.4

#include<stdio.h>
void critic(int *n);

int main(void) {
	int units;

	printf("How mant pounds to a firkin of butter?\n");
	scanf_s("%d", &units);
	while (units != 56)
		critic(&units);
	printf("You must have looked it up\n");

	return 0;
}

void critic(int *n)
{
	printf("No luck,my friend.Try again.\n");
	scanf_s("%d", n);

}

2.在美国,通常以英里/加仑来计算油耗;在欧洲,以升/100 公里来计算。下面是程序的一部分,提示用户选择计算模式(美制或公制),然后接收数据并计算油耗。

// pe12-2b.c
// pe12-2a.c 一起编译
#include <stdio.h>
#include "pe12-2a.h"
int main(void)
{
int mode;
printf("Enter 0 for metric mode, 1 for US mode: ");
scanf("%d", &mode);
while (mode >= 0)
{
set_mode(mode);
get_info();
show_info();
printf("Enter 0 for metric mode, 1 for US mode");
printf(" (-1 to quit): ");
scanf("%d", &mode);
}
printf("Done.\n");
return 0;
}
下面是是一些输出示例:
Enter 0 for metric mode, 1 for US mode: 0
Enter distance traveled in kilometers: 600
Enter fuel consumed in liters: 78.8
Fuel consumption is 13.13 liters per 100 km.
Enter 0 for metric mode, 1 for US mode (-1 to quit): 1
Enter distance traveled in miles: 434
Enter fuel consumed in gallons: 12.7
Fuel consumption is 34.2 miles per gallon.
Enter 0 for metric mode, 1 for US mode (-1 to quit): 3
Invalid mode specified. Mode 1(US) used.
Enter distance traveled in miles: 388
Enter fuel consumed in gallons: 15.3
Fuel consumption is 25.4 miles per gallon.
Enter 0 for metric mode, 1 for US mode (-1 to quit): -1
Done.
如果用户输入了不正确的模式,程序向用户给出提示消息并使用上一次
输入的正确模式。请提供 pe12-2a.h 头文件和 pe12-2a.c 源文件。源代码文件应
定义 3 个具有文件作用域、内部链接的变量。一个表示模式、一个表示距
离、一个表示消耗的燃料。 get_info() 函数根据用户输入的模式提示用户输入
相应数据,并将其储存到文件作用域变量中。 show_info() 函数根据设置的模
式计算并显示油耗。可以假设用户输入的都是数值数据。
#ifndef PE12_2A_H
#define PE12_2A_H

// 函数声明
void set_mode(int mode);
void get_info(void);
void show_info(void);

#endif // pe12-2a.h
//pe12-2a.c
#include <stdio.h>
#include "pe12-2a.h"

// 文件作用域变量,具有内部链接
static int current_mode = -1; // 当前模式,初始化为无效值
static double distance = 0.0; // 行驶距离
static double fuel = 0.0;     // 消耗的燃料

void set_mode(int mode) {
    if (mode == 0 || mode == 1) {
        current_mode = mode;
    }
    else {
        printf("Invalid mode specified. Mode %d(last valid mode) used.\n", current_mode == -1 ? 1 : current_mode);
    }
}

void get_info(void) {
    if (current_mode == 0) { // 公制模式
        printf("Enter distance traveled in kilometers: ");
        scanf_s("%lf", &distance);
        printf("Enter fuel consumed in liters: ");
        scanf_s("%lf", &fuel);
    }
    else if (current_mode == 1) { // 美制模式
        printf("Enter distance traveled in miles: ");
        scanf_s("%lf", &distance);
        printf("Enter fuel consumed in gallons: ");
        scanf_s("%lf", &fuel);
    }
}

void show_info(void) {
    if (current_mode == 0) { // 公制模式
        double consumption = (fuel / distance) * 100;
        printf("Fuel consumption is %.2f liters per 100 km.\n", consumption);
    }
    else if (current_mode == 1) { // 美制模式
        double consumption = distance / fuel;
        printf("Fuel consumption is %.1f miles per gallon.\n", consumption);
    }
}
// pe12-2b.c
// 与 pe12-2a.c 一起编译
#include <stdio.h>
#include "pe12-2a.h"
int main(void)
{
	int mode;
	printf("Enter 0 for metric mode, 1 for US mode: ");
	scanf_s("%d", &mode);
	while (mode >= 0)
	{
		set_mode(mode);
		get_info();
		show_info();
		printf("Enter 0 for metric mode, 1 for US mode");
		printf(" (-1 to quit): ");
		scanf_s("%d", &mode);
	}
	printf("Done.\n");
	return 0;
}

3.重新设计编程练习2,要求只使用自动变量。该程序提供的用户界面不变,即提示用户输入模式等。但是,函数调用要作相应变化。

暂时先放着~

4.在一个循环中编写并测试一个函数,该函数返回它被调用的次数。

#include<stdio.h>
int count(void);
int num = 0;

int main(void) {
	int n;

	n=count();
	n=count();
	n=count();

	printf("count()函数被调用了%d次", n);

	return 0;
}

int count(void)
{
	extern int num;
	num++;
	return num;
}

*5.编写一个程序,生成100110范围内的随机数,并以降序排列(可以把第11章的排序算法稍加改动,便可用于整数排序,这里仅对整数排序)。

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void sort(int ch[], int n);

int main(void) {
	int arr[100];

	srand(time(0));
	for (int i = 0; i < 100; i++) {
		arr[i] = rand() % 10 + 1;
	}

	sort(arr, 100);
	printf("排序后:\n");
	for (int i = 0; i < 100; i++)
	{
		printf("%d ", arr[i]);
	}

	printf("\n");
	return 0;
}

void sort(int ch[],int n)
{
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n - i; j++)
		{
			if (ch[j] < ch[j + 1])
			{
				int temp;
				temp = ch[j];
				ch[j] = ch[j + 1];
				ch[j + 1] = ch[j];
			}
		}
	}
}

*6.编写一个程序,生成1000110范围内的随机数。

不用保存或打印这些数字,仅打印每个数出现的次数。用 10 个不同的种子值运行,生成的 数字出现的次数是否相同?可以使用本章自定义的函数或ANSI C rand() 和srand()函数,它们的格式相同。这是一个测试特定随机数生成器随机性的方法。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define NUM_TRIALS 1000
#define NUM_RANGES 10
#define SEED_START 1 // 起始种子值,可以根据需要更改

void countRandomNumbers(int seed, int counts[]);

int main() {
    for (int seed = SEED_START; seed < SEED_START + 10; seed++) {
        int counts[NUM_RANGES + 1] = { 0 }; // 数组下标1-10对应数字1-10,下标0未使用

        countRandomNumbers(seed, counts);

        printf("Seed: %d\n", seed);
        for (int i = 1; i <= NUM_RANGES; i++) {
            printf("Number %d appeared %d times\n", i, counts[i]);
        }
        printf("\n");
    }

    return 0;
}

void countRandomNumbers(int seed, int counts[]) {
    srand(seed); // 设置随机数种子

    for (int i = 0; i < NUM_TRIALS; i++) {
        int num = rand() % NUM_RANGES + 1; // 生成1到10之间的随机数
        counts[num]++; // 统计数字出现的次数
    }
}

7.编写一个程序,按照程序清单12.13输出示例后面讨论的内容,修改该程序。使其输出类似:

Enter the number of sets; enter q to stop : 18
How many sides and how many dice? 6 3
Here are 18 sets of 3 6-sided throws.
12 10 6 9 8 14 8 15 9 14 12 17 11 7 10
13 8 14
How many sets? Enter q to stop: q
暂时先放着~

8.下面是程序的一部分:

// pe12-8.c
#include <stdio.h>
int * make_array(int elem, int val);
void show_array(const int ar [], int n);
int main(void)
{
int * pa;
int size;
int value;
printf("Enter the number of elements: ");
while (scanf("%d", &size) == 1 && size > 0)
{
printf("Enter the initialization value: ");
scanf("%d", &value);
pa = make_array(size, value);
if (pa)
{
show_array(pa, size);
free(pa);
}
printf("Enter the number of elements (<1 to quit): ");
}
printf("Done.\n");
return 0;
}
提供 make_array() show_array() 函数的定义,完成该程序。 make_array()
函数接受两个参数,第 1 个参数是 int 类型数组的元素个数,第 2 个参数是要赋
给每个元素的值。该函数调用 malloc() 创建一个大小合适的数组,将其每个
元素设置为指定的值,并返回一个指向该数组的指针。 show_array() 函数显
示数组的内容,一行显示 8 个数。
暂时先放着~

9.编写一个符合以下描述的函数。

首先,询问用户需要输入多少个单词。然后,接收用户输入的单词,并显示出来,使用malloc() 并回答第 1 个问题(即要输入多少个单词),创建一个动态数组,该数组内含相应的指向char的指针(注意,由于数组的每个元素都是指向 char 的指针,所以用于储存malloc() 返回值的指针应该是一个指向指针的指针,且它所指向的指针指向char )。在读取字符串时,该程序应该把单词读入一个临时的 char 数组,使用malloc() 分配足够的存储空间来储存单词,并把地址存入该指针数组(该数组中每个元素都是指向 char 的指针)。然后,从临时数组中把单词拷贝到动态分配的存储空间中。因此,有一个字符指针数组,每个指针都指向一个对象,该对象的大小正好能容纳被储存的特定单词。下面是该程序的一个运行示例:
How many words do you wish to enter? 5
Enter 5 words now:
I enjoyed doing this exerise
Here are your words:
I
enjoyed
doing
this
exercise
暂时先放着~

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值