17章练习题-C语言程序设计:现代方法(第2版)课后答案

17.1 

       每次调用时都检查函数malloc(或其他任何内存分配函数)的返回值是件很烦人的事情。请编写一个名为my_malloc的函数作为malloc函数的“包装器”。当调用函数my_malloc并且要求分配n个字节时,它会调用malloc函数,判断malloc函数确实没有返回空指针,然后返回来自malloc的指针。如果malloc返回空指针,那么函数my_malloc显示出错消息并且终止程序。

void *my_malloc(size_t n) {
    void *p;
    if ((p = malloc(n)) == NULL) {
        printf("Error: malloc failed.\n");
        exit(EXIT_FAILURE);
    }
    return p;
}

17.2

        编写名为duplicate的函数,此函数使用动态存储分配来创建字符串的副本。例如,调用
        p = duplicate(str);
将为和str长度相同的字符串分配内存空间,并且把字符串str的内容复制到新字符串,然后返回指向新字符串的指针。如果分配内存失败,那么函数duplicate返回空指针。

char *duplicate(char *str) {
    char *news = (char *) malloc(strlen(s) + 1);
    if (news == NULL) {
        printf("Error: malloc failed\n");
        return NULL;
    }
    strcpy(news, str);
    return news;
}

17.3        

        编写下列函数:

        int *create_array(int n, int initial_value);
函数应返回一个指向动态分配的n元int型数组的指针,数组的每个成员都初始化为initial_
value。如果内存分配失败,返回值为NULL。

int *create_array(int n, int initial_value) {
    int *a, *p;
    if ((a = (int *) malloc(n * sizeof(int)) == NULL) {
        printf("Error: malloc failed\n");
        return NULL;
    }
    for (p = a; p < a + n; p++)
        *p = initial_value;
    return a;
}

17.4

        假设下列声明有效:
        struct point { int x, y; };
        struct rectangle { struct point upper_left, lower_right; };
        struct rectangle *p; 

假设希望p指向一个rectangle结构,此结构的左上角位于(10, 25)的位置上,而右下角位于(20, 15)
的位置上。请编写一系列语句用来分配这样一个结构,并且像说明的那样进行初始化。

p = (struct rectangle *) malloc(sizeof(struct rectangle));
p->upper_left = {10, 25};
p->lower_right = {20, 15};

17.5

         假设f和p的声明如下所示:
        struct {
                union {
                        char a, b;
                        int c;
                } d;
                int e[5];
        } f, *p = &f;
那么下列哪些语句是合法的?
(a) p->b = ' ';
(b) p->e[3] = 10;
(c)(*p).d.a = '*';
(d) p->d->c = 20;

b和c是合法的,a应该是p->d.a = ' ';    d应该是p_>d.c = 20;

17.6

        请修改函数delete_from_list使它使用一个指针变量而不是两个(即cur和prev)。 

struct node *delete_from_list(struct node **list, int n) {
    struct node *item = *list;
    while (item) {
        if (item->value == n) {
            *list = item->next;
            free(item);
            break;
        }
        list = &item->next;
        item = item->next;
    }
    return *list;
}

17.7

        下列循环希望删除链表中的全部结点,并且释放它们占用的内存。但是,此循环有错误。请解释错误是什么并且说明如何修正错误。
        for (p = first; p != NULL; p = p->next)
        free(p); 

//循环释放了p,然后试图将p设置为它的下一个成员,而这个成员被取消了分配。
//解决这个问题的一个方法是创建一个指向下一个节点的指针,然后在p被反分配后将p分配给它。
struct node *next_node;

while (p != NULL) {
    next_node = p->next;
    free(p);
    p = next_node;
}

17.8

        15.2节描述的文件stack.c提供了在栈中存储整数的函数。在那一节中,栈是用数组实现的。请修改程序stack.c从而使栈现在作为链表来存储。使用单独一个指向链表首结点的指针变量(栈“顶”)来替换变量contents和变量top。在stack.c中编写的函数要使用此指针。删除函数is_full,用返回true(如果创建的结点可以获得内存)或false(如果创建的结点无法获得内存)的函数push来代替。 

#include <stdio.h>
#include <stdlib.h>
#include "stack.h"

struct node {
  int data;
  struct node *next;
};

static struct node *top = NULL;

static void terminate(const char *message)
{
  printf("%s\n", message);
  exit(EXIT_FAILURE);
}

void make_empty(void)
{
  while (!is_empty())
    pop();
}

bool is_empty(void)
{
  return top == NULL;
}

bool is_full(void)
{
  return false;
}

void push(int i)
{
  struct node *new_node = malloc(sizeof(struct node));
  if (new_node == NULL)
    terminate("Error in push: stack is full.");

  new_node->data = i;
  new_node->next = top;
  top = new_node;
}

int pop(void)
{
  struct node *old_top;
  int i;

  if (is_empty())
    terminate("Error in pop: stack is empty.");

  old_top = top;
  i = top->data;
  top = top->next;
  free(old_top);
  return i;
}

 17.9

        判断:如果x是一个结构而a是该结构的成员,那么(&x)->a与x.a是一样的。验证你的答案。

真。当扩展时,右箭头运算符(->),扩展为解除引用运算符和点运算符(*和.);
因此,(&x)->a扩展为*(&x).a。解除引用和寻址运算符相抵消,产生x.a。

17.10

        修改16.2节的print_part函数,使得它的形式参数是一个指向part结构的指针。请使用->运算符。

void print_part(struct part *p)
{
    printf("Part number: %d\n", p->number);
    printf("Part name: %s\n", p->name);
    printf("Quantity on hand: %d\n", p->on_hand);
}

 17.11

        编写下列函数:
        int count_occurrences(struct node *list, int n);
其中形式参数list指向一个链表。函数应返回n在该链表中出现的次数。node结构的定义见17.5节。

int count_occurrences(struct node *list, int n) {
    int sum = 0;
    while (list != NULL) {
        if (list->value == n)
            sum++;
        list = list->next;
    }
    return sum;
}

17.12

        编写下列函数:
        struct node *find_last(struct node *list, int n);
其中形式参数list指向一个链表。函数应返回一个指针,该指针指向最后一个包含n的结点,如果n
不存在则返回NULL。node结构的定义见17.5节。 

struct node *find_last(struct node *list, int n) {
    struct node *answer = NULL;
    while (list != NULL) {
        if (list->value == n)
            answer = list;
        list = list->next;
    }
    return answer;
}

17.13 

 下面的函数希望在有序链表的适当位置插入一个新结点,并返回指向新链表首结点的指针。但是,函数无法做到在所有的情况下都正确。解释问题所在,并说明如何修正。node结构的定义见17.5节。
struct node *insert_into_ordered_list(struct node *list, struct node *new_node)
{
        struct node *cur = list, *prev = NULL;
        while (cur->value <= new_node->value) {
                prev = cur;
                cur = cur->next;
        }
        prev->next = new_node;
        new_node->next = cur;
        return list;
}

该函数没有处理这样的边缘情况:当新节点必须插入到列表的第一个项目之前(当prev为NULL时),
以及当新节点必须插入到列表的最后一个项目之后(当cur为NULL时)。一个解决方案是使用一个指
向列表的指针,这也将消除有两个变量来插入新节点的必要性。
struct node *insert_into_ordered_list(struct node *list, struct node *new_node)
{
    struct node **pp = &list;
    while (list != NULL) {
        if (list->value >= new_node->value)
            break;
        pp = &list->next;
        list = list->next;
    }
    *pp = new_node;
    new_node = list;
}

 17.14

        修改函数delete_from_list(17.5节),使函数的第一个形式参数是struct node **类型(即指向链表首结点的指针的指针),并且返回类型是void。在删除了期望的结点后,函数delete_from_list必须修改第一个实际参数,使其指向该链表。

void delete_from_list(struct node **list, int n) {
    struct node *entry = *list;

    while (entry != NULL) {
        if (entry->value == n) {
            *list = entry->next;
            free(entry);
        }
        list = &entry->next;
        entry = entry->next;
    }
}

17.15 

        请说明下列程序的输出结果,并解释程序的功能。
#include <stdio.h>
int f1(int (*f)(int));
int f2(int i);
int main(void)
{
        printf("Answer: %d\n", f1(f2));
        return 0;
}
int f1(int (*f) (int))
{
        int n = 0;
        while ((*f)(n))  n++;
        return n;
}
int f2(int i)
{
        return i * i + i - 12;
}

Answer: 3

f1(f2) calls f(n) from n = 0 to n = 3 (where f2 returns 0). 
f1 then returns 3, and the printf call prints Answer: 3.

17.16 

         编写下列函数。调用sum(g, i, j)应该返回g(i) + ... + g(j)。
        int sum(int (*f)(int), int start, int end);

int sum(int (*f)(int), int start, int end) {
    int result = 0;
    while (start <= end) {
        result += (*f)(start);
        start++;
    }
    return result;
}

17.17

        设a是有100个整数的数组。请编写函数qsort的调用,只对数组a中的后50个元素进行排序。(不需要编写比较函数。) 

qsort(&a[50], 50, sizeof(a[0]), compare);

17.18

        请修改函数compare_parts使零件根据编号进行降序排列 

int compare_parts(const void *p, const void *q)
{
    return ((struct part *) q)->number - ((struct part *) p)->number;
}

17.19

         请编写一个函数,要求在给定字符串作为实际参数时,此函数搜索下列所示的结构数组寻找匹配的命令名,然后调用和匹配名称相关的函数:
struct {
        char *cmd_name;
        void (*cmd_pointer)(void);
} file_cmd[] =
{       {"new", new_cmd},
        {"open", open_cmd},
        {"close", close_cmd},
        {"close all", close_all_cmd},
        {"save", save_cmd},
        {"save as", save_as_cmd},
        {"save all", save_all_cmd},
        {"print", print_cmd},
        {"exit" , exit_cmd}
};

void run_command(char *str) {
    int i;
    for (i = 0; i < sizeof(file_cmd)/sizeof(file_cmd[0]); i++)
        if (strcmp(str, file_cmd[i].cmd_name) == 0)
            return (*file_cmd[i].cmd_pointer)();
    return;
}

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值