C语言程序设计现代方法 第八章 数组 编程题答案

练习8-1
修改 8.1 节的程序 repdigit.c,使其可以显示出哪些数字有重复(如果有的话):
Enter a number: 939577
Repeated digit(s): 7 9

#include <stdio.h>
#include <stdbool.h>


int main(void) {
    bool digit_repeat[10] = {false};
    bool digit_seen[10] = {false};
    long n;

    printf("输入数字:");
    scanf("%ld", &n);

    do {
        int t = n % 10;

        if (digit_repeat[t])
            digit_seen[t] = true;
        else
            digit_repeat[t] = true;
    } while (n /= 10);

    printf("显示重复:");
    for (n = 0; n < 10; ++n)
        if (digit_seen[n])
            printf("%d ", n);
    putchar('\n');

    return 0;
}

练习8-2
修改 8.1 节的程序 repdigit.c,使其打印出一份列表,显示出每个数字在数中出现的次数:
Enter a number: 41271092
Digit: 0 1 2 3 4 5 6 7 8 9
Occurrences: 1 2 2 0 1 0 0 1 0 1

#include <stdio.h>

int main(void) {
    int digit[10] = {0};
    int i;
    long n;

    printf("输入数字:");
    scanf("%ld", &n);

    do {
        ++digit[n % 10];
    } while (n /= 10);

    printf("数字:");
    for (i = 0; i < 10; ++i)
        printf("%3d", i);
    putchar('\n');

    printf("次数:");
    for (i = 0; i < 10; ++i)
        printf("%3d", digit[i]);
    putchar('\n');

    return 0;
}

练习8-3
修改 8.1节的程序 repdigit.c,使得用户可以输入多个数进行重复数字的判断。当用户输入的数小于或 等于 0 时,程序终止。

#include <stdbool.h>
#include <stdio.h>

int main(void) {
    bool digit_seen[10] = {false};
    int digit;
    long n;

    for (;;) {
        printf("请输入数字:");
        scanf("%ld", &n);

        if (n <= 0) return 0;

        do {
            digit = n % 10;
            if (digit_seen[digit])
                break;
            digit_seen[digit] = true;
        } while (n /= 10);

        printf("%s\n\n", n ? "有重复数字" : "无重复数字");
    }
}

练习8-4
修改 8.1 节的程序 reverse.c,利用表达式(int)(sizeof(a) / sizeof(a[0]))(或者具有相同值的宏) 来计算数组的长度。

#include <stdio.h>

#define SIZE (int) (sizeof(a) / sizeof(a[0]))

int main(void) {
    int a[5], i;

    printf("输入%d个数:", SIZE);

    for (i = 0; i < SIZE; i++)
        scanf("%d", &a[i]);

    printf("按相反的顺序:");
    for (i = SIZE - 1; i >= 0; i--)
        printf(" %d", a[i]);
    printf("\n");

    return 0;
}

练习8-5
修改 8.1 节的程序 interest.c,使得修改后的程序可以每月整合一次利息,而不是每年整合一次利息。 不要改变程序的输出格式,余额仍按每年一次的时间间隔显示。

#include <stdio.h>

#define NUM_RATES ((int) (sizeof(value) / sizeof(value[0])))
#define INITIAL_BALANCE 100.00

int main(void) {
 int i, j, low_rate, num_years, year;
 double value[5];

 printf("输入利率:");
 scanf("%d", &low_rate);
 printf("输入年数:");
 scanf("%d", &num_years);

 printf("\nYears");
 for (i = 0; i < NUM_RATES; i++) {
     printf("%6d%%", low_rate + i);
     value[i] = INITIAL_BALANCE;
 }

 printf("\n");
 for (year = 1; year <= num_years; year++) {
     printf("%3d ", year);
     for (i = 0; i < NUM_RATES; i++) {
         for (j = 0; j < 12; ++j)
             value[i] += (low_rate + i) / 1200.0 * value[i];
         printf("%7.2f", value[i]);
     }
     printf("\n");
 }

 return 0;
}

练习8-6
有一个名叫 B1FF 的人,是典型的网络新手,他有一种独特的编写消息的方式。下面是一条常见的 B1FF 公告: H3Y DUD3, C 15 R1LLY C00L!!! 编写一个“B1FF 过滤器”,它可以读取用户输入的消息并把此消息翻译成 B1FF 的表达风格: Enter message: Hey dude, C is rilly cool In B1FF-speak: H3Y DUD3, C 15 R1LLY C00L!!! 程序需要把消息转换成大写字母,用数字代替特定的字母(A→4、B→8、E→3、I→1、O→0、S→ 5),然后添加 10 个左右的感叹号。提示:把原始消息存储在一个字符数组中,然后从数组头开始逐 个翻译并显示字符。

#include <stdio.h>

#define MAX 100


int main(void) {
    char msg[MAX + 1];
    int ch;
    int i;
    
    for (i = 0; (ch = getchar()) != '\n' && i < MAX; ++i) 
        msg[i] = ch;

    printf("转换后的:");
    for (i = 0; msg[i]; ++i) {
        switch (msg[i]) {
            case 'A': case 'a': putchar('4'); break;
            case 'B': case 'b': putchar('8'); break;
            case 'E': case 'e': putchar('3'); break;
            case 'I': case 'i': putchar('1'); break;
            case 'O': case 'o': putchar('0'); break;
            case 'S': case 's': putchar('5'); break;
            default:  putchar(msg[i]);
        }
    }

    printf("!!!!!!!!!!\n");

    return 0;
}

练习8-7
编写程序读取一个 5×5 的整数数组,然后显示出每行的和与每列的和。 Enter row 1: 8 3 9 0 10 Enter row 2: 3 5 17 1 1 Enter row 3: 2 8 6 23 1 Enter row 4: 15 7 3 2 9 Enter row 5: 6 14 2 6 0 Row totals: 30 27 40 36 28 Column totals: 34 37 37 32 21

#include <stdio.h>

int main(void) {
    int arr[5][5];
    int i, j;

    for (i = 0; i < 5; ++i) {
        printf("输入第%d行:", i + 1);
        for (j = 0; j < 5; ++j)
            scanf("%d", arr[i][j]);
    }

    int sum;

    puts("行总和:");
    for (i = 0; i < 5; ++i) {
        sum = 0;
        for (j = 0; j < 5; ++j)
            sum += arr[i][j];
        printf("%d ", sum);
    }

    putchar('\n')

    puts("列总和:");

    for (i = 0; i < 5; ++i) {
        sum = 0;
        for (j = 0; j < 5; ++j)
            sum += arr[j][i];
        printf("%d ", sum);
    }

    putchar('\n');

    return 0;
}

练习8-8
修改编程题 7,使其提示用户输入每个学生 5 门测验的成绩,一共有 5 个学生。然后计算每个学生的 总分和平均分,以及每门测验的平均分、高分和低分。

#include <stdio.h>

int main(void) {
    int arr[5][5];
    int i, j;

    for (i = 0; i < 5; ++i) {
        printf("输入学生%d分数:", i + 1);
        for (j = 0; j < 5; ++j)
            scanf("%d", arr[i][j]);
    }

    int sum;

    for (i = 0; i < 5; ++i) {
        sum = 0;
        for (j = 0; j < 5; ++j)
            sum += arr[i][j];
        printf("学生%d总分%d,平均分%.1f\n", i + 1, sum, sum / 5.0);
    }

    return 0;
}

练习8-9
编写程序,生成一种贯穿 10×10 字符数组(初始时全为字符’.')的“随机步法”。程序必须随机地 从一个元素 “走到”另一个元素,每次都向上、向下、向左或向右移动一个元素位置。已访问过的 元素按访问顺序用字母 A~Z 进行标记。下面是一个输出示例:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

#define MAX 100

#define UP 0
#define DOWN 1
#define LEFT 2
#define RIGHT 3

int main(void) {
    char arr[10][10];
    int directions[4];
    int n;
    int i, j;
    int ch = 'A';

    srand(time(NULL));

    for (i = 0; i < 100; ++i)
        arr[0][i] = '.';

    i = 0; j = 0;
    arr[0][0] = ch;

    while (++ch <= 'Z') {
        n = 0;
        if (i - 1 >= 0 && arr[i - 1][j] == '.')
            directions[n++] = UP;
        if (i + 1 < 10 && arr[i + 1][j] == '.')
            directions[n++] = DOWN;
        if (j - 1 >= 0 && arr[i][j - 1] == '.')
            directions[n++] = LEFT;
        if (j + 1 < 10 && arr[i][j + 1] == '.')
            directions[n++] = RIGHT;

        if (n == 0) break;

        switch (directions[rand() % n]) {
            case UP:    arr[--i][j] = ch; break;
            case DOWN:  arr[++i][j] = ch; break;
            case LEFT:  arr[i][--j] = ch; break;
            default:    arr[i][++j] = ch; break;
        }
    }

    for (i = 0; i < 10; ++i) {
        for (j = 0; j < 10; ++j)
            printf("%c ", arr[i][j]);
        putchar('\n');
    }

    return 0;
}

练习8-10
修改第 5 章的编程题 8,用一个数组存储航班起飞时间,另一个数组存储航班抵达时间。(时间用整 数表示,表示从午夜开始的分钟数。)程序用一个循环搜索起飞时间数组,以找到与用户输入的时间 最接近的起飞时间。

#include <stdio.h>

int main(void) {
    const int departure_times[] = {480, 583, 679, 767, 840, 945,  1140, 1305};
    const int arrival_times[] =   {616, 712, 811, 900, 968, 1075, 1280, 1438};
    int hour, minute;
    int index;

    printf("输入预计时间:");
    scanf("%d :%d", &hour, &minute);

    int time = hour * 60 + minute;

    if (time > 1440 || time < 0)
        return -1;

    if (1440 - departure_times[7] > departure_times[0] && time > departure_times[7] + ((1440 - departure_times[7]) + departure_times[0]) / 2)
        index = 7;
    else if (time < departure_times[0] - ((1440 - departure_times[7]) + departure_times[0]) / 2)
        index = 0;
    else {
        for (index = 0; index < 7; ++index)
            if (time <= departure_times[index] + (departure_times[index + 1] - departure_times[index]) / 2)
                break;
    }

    hour = departure_times[index] / 60;
    minute = departure_times[index] % 60;

    if (hour == 12)
        printf("起飞时间是 12:%02d PM,", minute);
    else if (hour == 0)
        printf("起飞时间是 12:%02d AM,", minute);
    else if (hour > 12)
        printf("起飞时间是 %02d:%02d PM,", hour - 12, minute);
    else
        printf("起飞时间是 %02d:%02d AM,", hour, minute);

    hour = arrival_times[index] / 60;
    minute = arrival_times[index] % 60;

    if (hour == 12)
        printf("抵达时间是 12:%02d PM。\n", minute);
    else if (hour == 0)
        printf("抵达时间是 12:%02d AM。\n", minute);
    else if (hour > 12)
        printf("抵达时间是 %02d:%02d PM。\n", hour - 12, minute);
    else
        printf("抵达时间是 %02d:%02d AM。\n", hour, minute);

    return 0;
}

练习8-11
修改第 7 章的编程题 4,给输出加上标签: Enter phone number: 1-800-COL-LECT In numeric form: 1-800-265-5328 在显示电话号码之前,程序需要将其(以原始格式或数值格式)存储在一个字符数组中。可以假定电话号码的 长度不超过 15 个字符。

#include <stdio.h>
#include <ctype.h>

#define MAX 15

int main(void) {
    char value[26] = {
        '2', '2', '2', '3', '3', '3', '4', '4', '4', '5', '5', '5', '6',
        '6', '6', '7', '7', '7', '7', '8', '8', '8', '9', '9', '9', '9'
    };
    char msg[MAX + 1];
    int ch;
    int i;

    printf("输入电话号:");

    for (i = 0; (ch = getchar()) != '\n'; ++i)
        msg[i] = ch;
    msg[i] = '\0';

    printf("以数字表示:");

    for (i = 0; msg[i]; ++i) {
        if (islower(msg[i]))
            putchar(value[msg[i] - 'a']);
        else if (isupper(msg[i]))
            putchar(value[msg[i] - 'A']);
        else
            putchar(msg[i]);
    }

    putchar('\n');

    return 0;
}

练习8-12
修改第 7 章的编程题 5,用数组存储字母的面值。数组有 26 个元素,对应字母表中的 26 个字母。例 如,数组元素 0 存储 1(因为字母 A 的面值为 1),数组元素 1 存储 3(因为字母 B 的面值为 3),等 等。每读取输入单词中的一个字母,程序都会利用该数组确定字符的拼字值。使用数组初始化器来 建立该数组。

#include <stdio.h>
#include <ctype.h>


int main(void) {
    char values[26] = {
        1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3,
        1, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10
    };
    int sum = 0;
    int ch;

    printf("输入:");

    while ((ch = getchar()) != '\n')
        if (islower(ch))
            sum += values[ch - 'a'];
        else if (isupper(ch))
            sum += values[ch - 'A'];

    printf("拼字值结果是:%d\n", sum);

    return 0;
}

练习8-13
修改第 7 章的编程题 11,给输出加上标签: Enter a first and last name: Lloyd Fosdick You enered the name: Fosdick, L. 在显示姓(不是名)之前,程序需要将其存储在一个字符数组中。可以假定姓的长度不超过 20 个字符

#include <stdio.h>

#define MAX 20

int main(void) {
    char first_name[MAX + 1];
    int ch;

    printf("输入名字和姓氏:");

    // 跳过前面空格
    while ((ch = getchar()) == ' ')
        ;

    char last = ch;

    // 跳过名字剩余内容
    while (getchar() != ' ')
        ;

    scanf("%s", first_name);

    printf("你输入了这个名字:%s, %c.\n", first_name, last);

    return 0;
}

练习8-14
编写程序颠倒句子中单词的顺序: Enter a sentence: you can cage a swallow can’t you? Reversal of sentence: you can’t swallow a cage can you? 提示:用循环逐个读取字符,然后将它们存储在一个一维字符数组中。当遇到句号、问号或者感叹 号(称为“终止字符”)时,终止循环并把终止字符存储在一个 char 类型变量中。然后再用一个循 环反向搜索数组,找到最后一个单词的起始位置。显示最后一个单词,然后反向搜索倒数第二个单 词。重复这一过程,直至到达数组的起始位置。最后显示出终止字符。

#include <stdio.h>

#define MAX 100

int main(void) {
    char sentence[MAX + 1];
    char end;
    int i, j;
    int k;

    for (i = 0; i < MAX; ++i) {
        if ((sentence[i] = getchar()) == '\n')
            return 0; // 没有结束字符
        if (sentence[i] == '.' || sentence[i] == '?' || sentence[i] == '!') {
            end = sentence[i];
            goto skip;
        }
    }
    return 0; // 没有结束字符
    
    skip:
    // 记住改变的位置
    sentence[i] == ' ';
    k = i;

    while (--i != -1) {
        if (sentence[i] == ' ') {
            for (j = i + 1; sentence[j] != ' '; ++j)
                putchar(sentence[j]);
            putchar(' ');
        }
    }

    while (sentence[++i] != ' ')
        putchar(sentence[i]);
    printf("%c\n", end);

    sentence[k] = end; // 还回字符

    return 0;
}

练习8-15
目前已知的最古老的一种加密技术是恺撒加密(得名于 Julius Caesar)。该方法把一条消息中的每个字 母用字母表中固定距离之后的那个字母来替代。(如果越过了字母 Z,则会绕回到字母表的起始位 置。例如,如果每个字母都用字母表中两个位置之后的字母代替,那么Y就被替换为A,Z就被替换 为 B。)编写程序用恺撒加密方法对消息进行加密。用户输入待加密的消息和移位计数(字母移动的 位置数目)

#include <stdio.h>
#include <ctype.h>

#define MAX 80

int main(void) {
    char str[MAX + 1];
    int n;
    int m;

    printf("输入:");
    for (n = 0; n < MAX; ++n)
        if ((str[n] = getchar()) == '\n')
            break;
    str[n] = '\0';

    printf("输入加密:");
    scanf("%d", &m);

    while (--n >= 0) {
        if (islower(str[n]))
            str[n] = (str[n] - 'a' + m) % 26 + 'a';
        else if (isupper(str[n]))
            str[n] = (str[n] - 'A' + m) % 26 + 'A';
    }

    printf("结果:%s\n", str);

    return 0;
}

练习8-16
编程测试两个单词是否为变位词(相同字母的重新排列): Enter first word: smartest Enter second word: mattress The words are anagrams. Enter first word: dumbest Enter second word: stumble The words are not anagrams. 用一个循环逐个字符地读取第一个单词,用一个 26 元的整数数组记录每个字母的出现次数。(例 如,读取单词 smartest 之后,数组包含的值为 10001000000010000122000000,表明 smartest 包 含一个 a、一个 e、一个 m、一个 r、两个 s 和两个 t。)用另一个循环读取第二个单词,这次每读取 一个字母就把相应数组元素的值减 1。两个循环都应该忽略不是字母的那些字符,并且不区分大小 写。第二个单词读取完毕后,再用一个循环来检查数组元素是否为全 0。如果是全 0,那么这两个单 词就是变位词。提示:可以使用中的函数,如 isalpha 和 tolower。

#include <stdio.h>
#include <ctype.h>


int main(void) {
    int character[26] = {0};
    int ch;

    printf("输入第一个单词:");

    while ((ch = getchar()) != '\n')
        if (isalpha(ch))
            character[toupper(ch) - 'A'] += 1;

    printf("输入第二个单词:");

    while ((ch = getchar()) != '\n')
        if (isalpha(ch))
            character[toupper(ch) - 'A'] -= 1;

    for (int i = 0; i < 26; ++i)
        if (character[i] != 0) {
            printf("不是变位词。\n");
            return 0;
        }

    printf("是变位词。\n");
    
    return 0;
}

练习8-17
编写程序打印 n×n 的幻方(1, 2, …, n2的方阵排列,且每行、每列和每条对角线上的和都相等)。由 用户指定 n 的值: This program creates a magic square of a specified size. The size must be an odd number between 1 and 99. Enter size of magic square: 5 17 24 1 8 15 23 5 7 14 16 4 6 13 20 22 10 12 19 21 3 11 18 25 2 9 把幻方存储在一个二维数组中。起始时把数 1 放在第 0 行的中间,剩下的数 2, 3, …, n2依次向上移动 一行并向右移动一列。当可能越过数组边界时需要“绕回”到数组的另一端。例如,如果需要把下 一个数放到第1 行,我们就将其存储到第 n1 行(最后一行);如果需要把下一个数放到第 n 列, 我们就将其存储到第 0 列。如果某个特定的数组元素已被占用,那就把该数存储在前一个数的正下 方。如果你的编译器支持变长数组,则声明数组有 n 行 n 列,否则声明数组有 99 行 99 列。

#include <stdio.h>

int main(void) {
    int n;

    printf("输入幻方边长:");
    scanf("%d", &n);

    int arr[n][n];
    int i = 0, j = n / 2;
    int b = n - 1; // 幻方边界值
    int k; // 多功能索引

    n *= n; // 减少重复计算

    for (k = 0; k < n; ++k)
        arr[0][k] = 0;

    int count = -1;
    for (k = 1; k <= n; ++k) {
        arr[i][j] = k;

        // 利用规律
        if (++count == b) {
            count = -1;
            i = i + 1 > b ? 0 : i + 1;
        } else {
            i = i - 1 < 0 ? b : i - 1;
            j = j + 1 > b ? 0 : j + 1;
        }
    }

    for (i = 0; i <= b; ++i) {
        for (j = 0; j <= b; ++j)
            printf("%3d", arr[i][j]);
        putchar('\n');
    }

    return 0;
}
  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值