C语言课堂上的题目解答3

C语言课堂上的题目解答3

_

1.进制转换

转换方法:1)整数部分——辗转除r取余直到商为0,将余数作反向排列;

2)小数部分——反复乘r取整数部分,直到小数部分为0(若不能为0,则取整数个数最多5位),将各次所取整数正向排列

由于我们只有10个数字和26个字母,所以理论上我们可以实现36进制的转换。首先我们需要一个将数字转换为字符的函数(因为大于十进制的进制会出现英语字母,所以我们输出的结果应为一个字符串),在数字小于10的时候,直接转换为对应的数字字符,当数字大于或等于10的时候,将其按照 10 ->A ,11 -> B , 12 -> C ........ 35 -> Z 的方式转换,如下

char digit_to_char(int value)
{
    return (value < 10) ? ('0' + value) : ('A' + (value - 10));
    /*
    digit_to_char 将数值位映射成单个字符:若 value 在[0,9],返回 '0'+value 得到 '0' 到 '9';否则返回 'A'+(value-10),即把 10↦'A'、11↦'B' …… 35↦'Z'
    */
}

现在我们实现进制转换的函数,该函数接受一个浮点数(待转换的数)和一个整数(需要转换的进制),返回一个字符串(C语言风格的字符串实际上是一个字符数组char str[] 所以我们的返回值应为一个字符类型的指针char*)在函数内部,我们首先要判断需要转换的进制是否在[2,36]内,如果不在,直接返回NULL 。然后为了方便,我们需要对带转换的数取绝对值,然后在组合结果字符串的是否再判断是否要添加负号,所以我们在取绝对值之前要先用一个变量来存储是否需要负号


bool is_negative = dec < 0;//记录符号位
double abs_dec = fabs(dec);//取绝对值进行转换

接下来就是提取整数部分和小数部分

long long int_part = (long long)abs_dec;//整数部分
double frac_part = abs_dec - (double)int_part;//小数部分

然后我们就需要两个数组来分别存储整数和小数的转换结果,这里整数部分数组长度可以稍微大一点,小数部分根据题目要求直接取5,同时为了节省结果字符串的的内存,我们可以用两个变量来分别记录两个数组的实际使用长度

char res_int[128];//存储整数部分转换结果的字符数组
char res_frac[5];//存储小数部分转换结果的字符数组
int size_int = 0;
int size_frac = 0;

接下来就是转换的过程,直接根据进制转换的方法实现即可

    if (int_part == 0)
    {
        res_int[size_int] = '0'; //处理整数部分为 0 的特殊情况
        size_int++;
    }
    else
    {
        while (int_part > 0 && size_int < (int)(sizeof(res_int)))//转换整数部分
        {
            int digit = (int)(int_part % r);
            res_int[size_int] = digit_to_char(digit);
            size_int++;
            int_part /= r;
        }
    }

    while (frac_part > 0.0 && size_frac < (int)(sizeof(res_frac)))//转换小数部分
    {
        frac_part *= r;
        int temp = (int)frac_part;
        res_frac[size_frac]= digit_to_char(temp);
        size_frac++;
        frac_part -= temp;
        if (fabs(frac_part) < 1e-12)
        {
            frac_part = 0.0;
        }
    }

在转换完之后,我们就要拼接结果字符串,在那之前,我们可以简单的判断一下传入的数是否有小数部分

bool needs_decimal = size_frac > 0;//判断是否需要小数点

接下来我们申请结果字符串的内存,内存大小可以这样计算:

1.如果为负数,需要用一个单位内存来存储负号

2.整数部分的结果

3.如果为小数,需要一个单位内存来存储小数点

4.小数部分的结果

5.由于我们想要得到一个字符串,所以还要在结尾加上一个'\0'标志字符串的结尾

基于以上要点,我们计算所需的总内存然后申请

size_t total_len = (is_negative ? 1 : 0) + size_int + (needs_decimal ? 1 + size_frac : 0) + 1;//计算总长度,包括符号位、小数点和终止符
char *result = (char *)malloc(total_len);//分配结果字符串的内存

然后就是将以上内容拼接进结果字符串

    int index = 0;//结果字符串的当前索引
    if (is_negative)//添加符号位
    {
        result[index] = '-';
        index++;
    }
    for (int i = size_int - 1; i >= 0; i--)//添加整数部分(逆序)
    {
        result[index] = res_int[i];
        index++;
    }
    if (needs_decimal)//添加小数点和小数部分
    {
        result[index] = '.';
        index++;
        for (int i = 0; i < size_frac; i++)
        {
            result[index] = res_frac[i];
            index++;
        }
    }
    result[index] = '\0';//添加字符串终止符

最后给出完整代码

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

char digit_to_char(int value)
{
    return (value < 10) ? ('0' + value) : ('A' + (value - 10));
    /*
    digit_to_char 将数值位映射成单个字符:若 value 在[0,9],返回 '0'+value 得到 '0' 到 '9';否则返回 'A'+(value-10),即把 10↦'A'、11↦'B' …… 35↦'Z'
    */
}

char *trans(double dec, int r)
{
    if (r < 2 || r > 36)
    {
        return NULL;
    } // 由于 digit_to_char 函数只能处理 0-35 的数值位,因此进制 r 必须在 [2,36) 范围内

    bool is_negative = dec < 0;//记录符号位
    double abs_dec = fabs(dec);//取绝对值进行转换
    long long int_part = (long long)abs_dec;//整数部分
    double frac_part = abs_dec - (double)int_part;//小数部分

    char res_int[128];//存储整数部分转换结果的字符数组
    char res_frac[5];//存储小数部分转换结果的字符数组
    int size_int = 0;
    int size_frac = 0;

    if (int_part == 0)
    {
        res_int[size_int] = '0'; //处理整数部分为 0 的特殊情况
        size_int++;
    }
    else
    {
        while (int_part > 0 && size_int < (int)(sizeof(res_int)))//转换整数部分
        {
            int digit = (int)(int_part % r);
            res_int[size_int] = digit_to_char(digit);
            size_int++;
            int_part /= r;
        }
    }

    while (frac_part > 0.0 && size_frac < (int)(sizeof(res_frac)))//转换小数部分
    {
        frac_part *= r;
        int temp = (int)frac_part;
        res_frac[size_frac]= digit_to_char(temp);
        size_frac++;
        frac_part -= temp;
        if (fabs(frac_part) < 1e-12)
        {
            frac_part = 0.0;
        }
    }
    
    bool needs_decimal = size_frac > 0;//判断是否需要小数点
    size_t total_len = (is_negative ? 1 : 0) + size_int + (needs_decimal ? 1 + size_frac : 0) + 1;//计算总长度,包括符号位、小数点和终止符
    char *result = (char *)malloc(total_len);//分配结果字符串的内存
    int index = 0;//结果字符串的当前索引
    if (is_negative)//添加符号位
    {
        result[index] = '-';
        index++;
    }
    for (int i = size_int - 1; i >= 0; i--)//添加整数部分(逆序)
    {
        result[index] = res_int[i];
        index++;
    }
    if (needs_decimal)//添加小数点和小数部分
    {
        result[index] = '.';
        index++;
        for (int i = 0; i < size_frac; i++)
        {
            result[index] = res_frac[i];
            index++;
        }
    }
    result[index] = '\0';//添加字符串终止符
    return result;
}

int main()
{
    double dec;
    int r;
    scanf("%lf", &dec);
    scanf("%d", &r);
    char *result = trans(dec, r);
    if (!result)
    {
        printf("invalid input\n");
        return 1;
    }
    printf("%s\n", result);
    free(result);
    result = NULL;
    return 0;
}

C语言课堂上的题目解答2 2025-12-03

评论区