C17中任意长十进制字符串转十六进制字符串的实现方法问询
大十进制字符串转十六进制字符串的C17实现
对于超大十进制数(无法用基本整数类型存储)转十六进制,核心思路是模拟大整数的除法取余操作——反复将十进制数除以16,收集每次的余数(对应十六进制的一位),最后将余数倒序排列得到结果。以下是具体实现方案:
一、内存分配与计算
十六进制最大位数的整数计算方式:
十进制数的最大二进制位数为 n * log2(10)(n为十进制字符串长度),十六进制每4位二进制对应一位,因此最大十六进制位数可通过整数运算避免浮点误差:
size_t max_hex_len = (n * 10 + 11) / 12; // 等价于ceil(n * log2(10)/4)
先分配max_hex_len + 1(预留字符串终止符空间)的内存,待收集完所有余数后,再通过realloc调整到实际需要的长度,避免内存浪费。
二、核心实现步骤
- 模拟大整数除以16:
- 用临时数组存储每一步除法后的商(十进制),初始商为输入的十进制字符串副本。
- 遍历当前商的每一位,计算当前位数值加上前一位余数*10的总和,除以16得到新的商位,余数则是当前十六进制位的数值。
- 当商变为全零状态时,停止计算。
- 收集并反转余数:
- 余数范围是0-15,对应十六进制字符
0-9A-F。 - 收集的余数是从低位到高位的顺序,最后需反转数组得到正确的十六进制字符串顺序。
- 余数范围是0-15,对应十六进制字符
三、完整代码示例
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> // 十进制字符串转十六进制字符串,返回的内存需调用者free char* dec_to_hex(const char* st_in) { if (!st_in || !*st_in) return NULL; size_t n = strlen(st_in); // 计算最大十六进制位数,加1存终止符 size_t max_hex_len = (n * 10 + 11) / 12; char* hex_digits = malloc(max_hex_len + 1); if (!hex_digits) return NULL; // 临时存储商(十进制字符串),初始为输入的副本 char* quotient = malloc(n + 1); if (!quotient) { free(hex_digits); return NULL; } strcpy(quotient, st_in); size_t hex_idx = 0; int has_non_zero = 0; while (1) { int remainder = 0; char new_quotient[n + 1] = {0}; size_t q_idx = 0; // 遍历当前商的每一位,计算新的商和余数 for (size_t i = 0; quotient[i]; i++) { int digit = quotient[i] - '0'; int current = remainder * 10 + digit; new_quotient[q_idx] = (current / 16) + '0'; remainder = current % 16; // 跳过前导零,只保留有效商位 if (new_quotient[q_idx] != '0' || q_idx > 0) { q_idx++; } } new_quotient[q_idx] = '\0'; // 处理余数:避免输入全零时生成多余的0 if (!has_non_zero && remainder == 0) { if (strcmp(quotient, "0") == 0) { hex_digits[hex_idx++] = '0'; break; } } else { has_non_zero = 1; // 余数转大写十六进制字符 hex_digits[hex_idx++] = (remainder < 10) ? (remainder + '0') : (remainder - 10 + 'A'); } // 更新商为新的商,若商为空则退出循环 free(quotient); if (q_idx == 0) { quotient = NULL; break; } quotient = malloc(q_idx + 1); if (!quotient) { free(hex_digits); return NULL; } strcpy(quotient, new_quotient); } // 反转十六进制字符数组,得到正确顺序 for (size_t i = 0; i < hex_idx / 2; i++) { char temp = hex_digits[i]; hex_digits[i] = hex_digits[hex_idx - 1 - i]; hex_digits[hex_idx - 1 - i] = temp; } hex_digits[hex_idx] = '\0'; // 调整内存到实际需要的大小 char* result = realloc(hex_digits, hex_idx + 1); if (result) { hex_digits = result; } if (quotient) free(quotient); return hex_digits; } // 测试示例 int main(int argc, char* argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s <decimal-string>\n", argv[0]); return 1; } // 验证输入是否仅含数字 for (size_t i = 0; argv[1][i]; i++) { if (!isdigit(argv[1][i])) { fprintf(stderr, "Input must contain only digits.\n"); return 1; } } char* st_out = dec_to_hex(argv[1]); if (st_out) { printf("%s\n", st_out); free(st_out); } else { fprintf(stderr, "Memory allocation failed.\n"); return 1; } return 0; }
四、内存管理说明
- 初始分配的
hex_digits按最大可能长度分配,最后通过realloc缩小到实际使用的长度(hex_idx + 1),避免多余内存占用。 - 临时的
quotient数组每次循环后都会释放并重新分配,确保内存不泄漏。 - 返回的十六进制字符串由调用者负责调用
free释放。
内容的提问来源于stack exchange,提问作者CopperCableIsolator
相关产品推荐
相关产品推荐

