C Primer Plus 第6版 编程练习——第15章

1.编写一个函数,把二进制字符串转换为一个数值。例如,有下面的语句:

char * pbin = "01001001";

那么把pbin作为参数传递给该函数后,它应该返回一个int 类型的值73。

cpp 复制代码
#include <stdio.h>

int bin_to_int(const char* pbin) {
    int result = 0;
    if (pbin == NULL) return 0;  // 处理空指针

    while (*pbin != '\0') {
        // 左移当前结果并叠加新位
        result = (result << 1) + (*pbin - '0');
        pbin++;
    }
    return result;
}

// 测试示例
int main() {
    const char* pbin = "01001001";
    printf("%d\n", bin_to_int(pbin));  // 输出:73
    return 0;
}

2.编写一个程序,通过命令行参数读取两个二进制字符串,对这两个二进州数使用~运算你、&运算徐、|运算符和^运算行,并以二进制字符串形式打印结果(如果无法使用命令行环境,可以通过交互式让程序读取字符串)。

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 二进制字符串转整数
unsigned int bin_to_int(const char* pbin) {
    unsigned int result = 0;
    if (pbin == NULL) return 0;

    while (*pbin != '\0') {
        result = (result << 1) + (*pbin - '0');
        pbin++;
    }
    return result;
}

// 整数转二进制字符串
char* int_to_bin(unsigned int num, int bits) {
    char* str = (char*)malloc(bits + 1);
    if (str == NULL) return NULL;

    str[bits] = '\0';
    for (int i = bits - 1; i >= 0; i--) {
        str[i] = (num & 1) ? '1' : '0';
        num >>= 1;
    }
    return str;
}

int main(int argc, char* argv[]) {
    if (argc != 3) {
        printf("Usage: %s <binary_str1> <binary_str2>\n", argv[0]);
        printf("Example: %s 01001001 00101110\n", argv[0]);
        return 1;
    }

    char* bin_str1 = argv[1];
    char* bin_str2 = argv[2];

    // 确定最大位数
    size_t len1 = strlen(bin_str1);
    size_t len2 = strlen(bin_str2);
    int max_bits = (len1 > len2) ? (int)len1 : (int)len2;

    // 转换为整数
    unsigned int num1 = bin_to_int(bin_str1);
    unsigned int num2 = bin_to_int(bin_str2);

    // 执行位运算
    unsigned int not1 = ~num1;
    unsigned int not2 = ~num2;
    unsigned int and_result = num1 & num2;
    unsigned int or_result = num1 | num2;
    unsigned int xor_result = num1 ^ num2;

    // 转换为二进制字符串
    char* not1_str = int_to_bin(not1, max_bits);
    char* not2_str = int_to_bin(not2, max_bits);
    char* and_str = int_to_bin(and_result, max_bits);
    char* or_str = int_to_bin(or_result, max_bits);
    char* xor_str = int_to_bin(xor_result, max_bits);

    // 打印结果(只显示有效位)
    printf("~%s: %s\n", bin_str1, not1_str + (strlen(not1_str) - max_bits));
    printf("~%s: %s\n", bin_str2, not2_str + (strlen(not2_str) - max_bits));
    printf("%s & %s: %s\n", bin_str1, bin_str2, and_str);
    printf("%s | %s: %s\n", bin_str1, bin_str2, or_str);
    printf("%s ^ %s: %s\n", bin_str1, bin_str2, xor_str);

    // 清理内存
    free(not1_str);
    free(not2_str);
    free(and_str);
    free(or_str);
    free(xor_str);

    return 0;
}

3.编写一个函数,接受一个 int 类型的参数,并返回该参数中打开位的数量。在一个程序中测试该函数。

cpp 复制代码
#include <stdio.h>

// 计算整数中1的位数(打开位数量)
int count_bits(int num) {
    int count = 0;
    unsigned int unum = (unsigned int)num;

    while (unum) {
        count++;
        unum &= (unum - 1);  // 清除最低位的1
    }
    return count;
}

int main() {
    system("chcp 65001");
    int test_numbers[] = { 0, 1, 73, 255, -1, 12345 };
    int size = sizeof(test_numbers) / sizeof(test_numbers[0]);

    printf("测试结果(打开位数量):\n");
    printf("------------------------------------------------------------------\n");
    printf("%-13s | %-38s | %s\n", "十进制", "二进制", "1的位数");
    printf("------------------------------------------------------------------\n");

    for (int i = 0; i < size; i++) {
        int num = test_numbers[i];

        // 打印二进制表示(简单实现)
        printf("%-10d | ", num);
        for (int j = sizeof(int) * 8 - 1; j >= 0; j--) {
            putchar((num >> j) & 1 ? '1' : '0');
            if (j % 8 == 0 && j > 0) putchar(' ');
        }

        // 使用优化版本计算结果
        printf(" | %d\n", count_bits(num));
    }

    return 0;
}

4.编写一个程序,按受两个 int 类型的参数:一个是值:一个是位的位置。如果指定位的位置为1,该函数返回1;否则返回0。在一个程序中测试该函数。

cpp 复制代码
#include <stdio.h>
#include <limits.h>

// 检查指定位是否为1
int check_bit(int value, int position) {
    // 验证位置有效性
    if (position < 0 || position >= (int)(sizeof(int) * CHAR_BIT)) {
        printf("错误:位位置 %d 超出范围 (0-%d)\n", position, (int)(sizeof(int) * CHAR_BIT - 1));
        return 0;
    }

    // 创建掩码并检查位状态
    return (value & (1 << position)) ? 1 : 0;
}

// 打印整数的二进制表示
void print_binary(int num) {
    for (int i = sizeof(int) * CHAR_BIT - 1; i >= 0; i--) {
        putchar((num >> i) & 1 ? '1' : '0');
        if (i > 0 && i % 8 == 0) putchar(' ');
    }
}

int main() {
    system("chcp 65001");
    // 测试用例数组:{测试值, 测试位位置}
    int tests[][2] = {
        {0b10101010, 0},   // 位0:0
        {0b10101010, 1},   // 位1:1
        {0b10101010, 3},   // 位3:0
        {0b10101010, 7},   // 位7:1
        {255, 0},          // 最低位:1
        {255, 7},          // 最高位(8位):1
        {12345, 0},        // 12345的最低位
        {12345, 13},       // 12345的第13位
        {-1, 0},           // 负数测试:最低位
        {-1, 31}           // 负数测试:最高位(32位系统)
    };

    int num_tests = sizeof(tests) / sizeof(tests[0]);

    printf("位检查测试结果:\n");
    printf("----------------------------------------------------------------------------------------\n");
    printf("%-11s | %-40s | %-5s | %s\n", "值", "二进制表示", "位", "结果");
    printf("----------------------------------------------------------------------------------------\n");

    for (int i = 0; i < num_tests; i++) {
        int value = tests[i][0];
        int position = tests[i][1];
        int result = check_bit(value, position);

        printf("%-10d | ", value);
        print_binary(value);
        printf(" | %-4d | %d\n", position, result);
    }

    // 边界测试
    printf("\n边界测试:\n");
    printf("位置 -1: %d\n", check_bit(255, -1));
    printf("位置 32 (32位系统): %d\n", check_bit(255, sizeof(int) * CHAR_BIT));

    return 0;
}

5.编写一个函数,把一个 unsigned int 类型值中的所有位向左旋转指定数量的位。例如,rotate_1(x,4)把×中所有位向左移动4个位置,而且从最左端移出的位会重新出现在右端。也就是说,把高阶位移出的位放入低阶位。在一个程序中测试该函数。

cpp 复制代码
#include <stdio.h>
#include <limits.h>

// 循环左移函数
unsigned int rotate_left(unsigned int value, int n) {
    // 获取总位数
    const int total_bits = sizeof(unsigned int) * CHAR_BIT;

    // 处理n为负数或超过总位数的情况
    n = n % total_bits;
    if (n < 0) n += total_bits;  // 将负位移转换为正位移

    // 执行循环左移
    return (value << n) | (value >> (total_bits - n));
}

// 打印无符号整数的二进制表示
void print_binary(unsigned int num) {
    for (int i = sizeof(unsigned int) * CHAR_BIT - 1; i >= 0; i--) {
        putchar((num >> i) & 1 ? '1' : '0');
        if (i > 0 && i % 8 == 0) putchar(' ');
    }
}

int main() {
    system("chcp 65001");
    // 测试用例数组:{测试值, 位移数}
    struct TestCase {
        unsigned int value;
        int shift;
    } tests[] = {
        {0x00000001, 1},   // 1左移1位 → 2
        {0x00000001, 31},  // 1左移31位 → 0x80000000
        {0x80000000, 1},   // 0x80000000左移1位 → 1
        {0x12345678, 4},   // 0x12345678左移4位 → 0x23456781
        {0xAAAAAAAA, 1},   // 1010...左移1位 → 0101...
        {0x55555555, 31},  // 0101...左移31位 → 1010...
        {0x00FF0000, 8},   // 0x00FF0000左移8位 → 0xFF000000
        {0x0000FFFF, 16}   // 0x0000FFFF左移16位 → 0xFFFF0000
    };

    int num_tests = sizeof(tests) / sizeof(tests[0]);

    printf("循环左移测试结果:\n");
    printf("-----------------------------------------------------------------------------------------------------------\n");
    printf("%-13s | %-40s | %-6s | %-13s | %s\n",
        "原始值", "二进制表示", "位移", "结果值", "结果二进制");
    printf("-----------------------------------------------------------------------------------------------------------\n");

    for (int i = 0; i < num_tests; i++) {
        unsigned int value = tests[i].value;
        int shift = tests[i].shift;
        unsigned int result = rotate_left(value, shift);

        printf("0x%08X | ", value);
        print_binary(value);
        printf(" | %-4d | 0x%08X | ", shift, result);
        print_binary(result);
        printf("\n");
    }

    // 边界测试
    printf("\n边界测试:\n");
    unsigned int test_val = 0x0000000F;
    printf("位移0位: 0x%08X\n", rotate_left(test_val, 0));
    printf("位移总位数(%d位): 0x%08X\n",
        (int)(sizeof(unsigned int) * CHAR_BIT),
        rotate_left(test_val, sizeof(unsigned int) * CHAR_BIT));
    printf("负位移(-4): 0x%08X\n", rotate_left(test_val, -4));

    return 0;
}

6.设计一个位字段结构以存储下面的信息。

字体ID:0~255之间的一个数;

字体大小:0~127之间的一个数;

对齐:0~2之间的一个数,表示左对齐、居中、右对齐;

加粗:开(1)或闭(0);

斜体:开(1)或闭(0);

在一个程序中使用该结构来打印字体参数,并使用循环菜单来让用户改变参数。例如,该程序的一个运行示例如下:

ID SIZE ALIGNMENT B I U

1 12 left off off off

f)change font s)change size a)change alignment

b)toggle bold i)toggle italic u)toggle underline

q)quit

s

Enter font size (0-127):36

ID SIZE ALIGNMENT B I U

1 36 left off off off

f)change font s)change size a)change alignment

b)toggle bold i)toggle italic u)toggle underline

q)quit

a

Select alignment:

l)left c) center r) right

r

ID SIZE ALIGNMENT B I U

1 36 right off off off

f)change font s)change size a)change alignment

b)toggle bold i)toggle italic u)toggle underline

q)quit

i

ID SIZE ALIGNMENT B I U

1 36 left off on off

f)change font s)change size a)change alignment

b)toggle bold i)toggle italic u)toggle underline

q)quit

q

Byte!

该程序要使用按位与运算符(&)和合适的掩码来把字体ID和字体大小信息转换到指定范围内。

cpp 复制代码
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

// 位字段结构定义
typedef struct {
    unsigned int font_id : 8;   // 0-255 (8位)
    unsigned int font_size : 7;   // 0-127 (7位)
    unsigned int alignment : 2;   // 0-2 (2位)
    unsigned int bold : 1;   // 0-1 (1位)
    unsigned int italic : 1;   // 1位
    unsigned int underline : 1;   // 1位 (根据示例添加)
} Font;

// 对齐方式文本映射
const char* alignments[] = { "left", "center", "right" };

// 打印当前字体设置
void show_settings(const Font* f) {
    printf("\n ID   SIZE  ALIGNMENT   B    I    U\n");
    printf("%3d %6d %10s %4s %4s %4s\n",
        f->font_id,
        f->font_size,
        alignments[f->alignment],
        f->bold ? "on" : "off",
        f->italic ? "on" : "off",
        f->underline ? "on" : "off"
    );
}

// 菜单显示
void show_menu() {
    printf("\nf)change font s)change size a)change alignment\n");
    printf("b)toggle bold i)toggle italic u)toggle underline\n");
    printf("g)quit\n");
}

int main() {
    Font font = { 1, 12, 0, 0, 0, 0 }; // 初始值
    char choice;

    while (1) {
        show_settings(&font);
        show_menu();

        printf("Enter choice: ");
        scanf_s(" %c", &choice, 1); // 注意空格跳过空白字符
        choice = tolower(choice);

        switch (choice) {
        case 'f': {
            unsigned int id;
            printf("Enter font ID (0-255): ");
            scanf_s("%u", &id);
            font.font_id = id & 0xFF; // 确保0-255范围
            break;
        }
        case 's': {
            unsigned int size;
            printf("Enter font size (0-127): ");
            scanf_s("%u", &size);
            font.font_size = size & 0x7F; // 确保0-127范围
            break;
        }
        case 'a': {
            char align_choice;
            printf("Select alignment:\nl)left c)center r)right\n");
            scanf_s(" %c", &align_choice, 1);

            switch (tolower(align_choice)) {
            case 'l': font.alignment = 0; break;
            case 'c': font.alignment = 1; break;
            case 'r': font.alignment = 2; break;
            default: printf("Invalid choice!\n");
            }
            break;
        }
        case 'b': font.bold ^= 1; break;     // 切换加粗
        case 'i': font.italic ^= 1; break;   // 切换斜体
        case 'u': font.underline ^= 1; break; // 切换下划线
        case 'q':
            printf("Bye!\n");
            exit(0);
        default:
            printf("Invalid choice!\n");
        }
    }
    return 0;
}

7.编写一个与编程练习6功能相同的程序,使用unsigned long类型的变量存储字体信息,并且使用按位运算符而不是成员位来管理这些信息。

cpp 复制代码
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

// 位掩码和偏移量定义
#define FONT_ID_MASK    0xFF000u   // 字体ID掩码(位12-19)
#define FONT_ID_SHIFT   12
#define FONT_SIZE_MASK  0xFE0u     // 字体大小掩码(位5-11)
#define FONT_SIZE_SHIFT 5
#define ALIGNMENT_MASK  0x18u      // 对齐方式掩码(位3-4)
#define ALIGNMENT_SHIFT 3
#define BOLD_MASK       0x1u       // 加粗掩码(位0)
#define ITALIC_MASK     0x2u       // 斜体掩码(位1)
#define UNDERLINE_MASK  0x4u       // 下划线掩码(位2)

// 对齐方式文本映射
const char* alignments[] = { "left", "center", "right" };

// 打印当前字体设置
void show_settings(unsigned long font_info) {
    // 提取各个字段
    unsigned int id = (font_info & FONT_ID_MASK) >> FONT_ID_SHIFT;
    unsigned int size = (font_info & FONT_SIZE_MASK) >> FONT_SIZE_SHIFT;
    unsigned int align = (font_info & ALIGNMENT_MASK) >> ALIGNMENT_SHIFT;

    printf("\n ID   SIZE  ALIGNMENT   B    I    U\n");
    printf("%3d %6d %10s %4s %4s %4s\n",
        id,
        size,
        alignments[align],
        (font_info & BOLD_MASK) ? "on" : "off",
        (font_info & ITALIC_MASK) ? "on" : "off",
        (font_info & UNDERLINE_MASK) ? "on" : "off"
    );
}

// 菜单显示
void show_menu() {
    printf("\nf)change font s)change size a)change alignment\n");
    printf("b)toggle bold i)toggle italic u)toggle underline\n");
    printf("q)quit\n");
}

int main() {
    // 初始化字体信息: ID=1, 大小=12, 左对齐(0), 所有样式关闭
    unsigned long font_info = (1u << FONT_ID_SHIFT) | (12u << FONT_SIZE_SHIFT);
    char choice;

    while (1) {
        show_settings(font_info);
        show_menu();

        printf("Enter choice: ");
        scanf_s(" %c", &choice, 1);
        choice = tolower(choice);

        switch (choice) {
        case 'f': {
            unsigned int id;
            printf("Enter font ID (0-255): ");
            scanf_s("%u", &id);

            // 清除原ID,设置新ID
            font_info &= ~FONT_ID_MASK;
            font_info |= (id & 0xFFu) << FONT_ID_SHIFT;
            break;
        }
        case 's': {
            unsigned int size;
            printf("Enter font size (0-127): ");
            scanf_s("%u", &size);

            // 清除原大小,设置新大小
            font_info &= ~FONT_SIZE_MASK;
            font_info |= (size & 0x7Fu) << FONT_SIZE_SHIFT;
            break;
        }
        case 'a': {
            char align_choice;
            printf("Select alignment:\nl)left c)center r)right\n");
            scanf_s(" %c", &align_choice, 1);

            // 清除原对齐方式
            font_info &= ~ALIGNMENT_MASK;

            switch (tolower(align_choice)) {
            case 'l': font_info |= (0u << ALIGNMENT_SHIFT); break;
            case 'c': font_info |= (1u << ALIGNMENT_SHIFT); break;
            case 'r': font_info |= (2u << ALIGNMENT_SHIFT); break;
            default: printf("Invalid choice!\n");
            }
            break;
        }
        case 'b': font_info ^= BOLD_MASK; break;     // 切换加粗
        case 'i': font_info ^= ITALIC_MASK; break;   // 切换斜体
        case 'u': font_info ^= UNDERLINE_MASK; break; // 切换下划线
        case 'q':
            printf("Bye!\n");
            exit(0);
        default:
            printf("Invalid choice!\n");
        }
    }
    return 0;
}
相关推荐
银河码1 小时前
嵌入式linux驱动开发:什么是Linux驱动?深度解析与实战入门
linux·c语言·驱动开发·驱动入门
爱吃KFC的大肥羊1 小时前
C/C++常用字符串函数
c语言·数据结构·c++·算法
阿捏利2 小时前
【加解密与C】HASH系列(四)SHA-3
c语言·加解密·sha-3
C++ 老炮儿的技术栈4 小时前
在vscode 如何运行a.nut 程序(Squirrel语言)
c语言·开发语言·c++·ide·vscode·算法·编辑器
一川月白7094 小时前
数据结构---概念、数据与数据之间的关系(逻辑结构、物理结构)、基本功能、数据结构内容、单向链表(该奶奶、对象、应用)
c语言·数据结构·算法·哈希算法·单向链表·数据关系
能工智人小辰5 小时前
Educational Codeforces Round 181 (Rated for Div. 2) A-C
c语言·开发语言
饮浊酒6 小时前
初始C语言---第四讲(数组)
c语言·学习
酷飞飞8 小时前
C语言的复合类型、内存管理、综合案例
java·c语言·前端
海上Bruce9 小时前
C primer plus (第六版)第十章 编程练习第7,8,9,10,11题
c语言