C语言数字各位平方拼接函数处理大数值异常,求修复方案
数字各位平方拼接函数异常问题分析与修复
问题背景
需要实现一个函数,将输入的unsigned类型数字的每一位平方后拼接成整数返回。例如输入9191,返回811181(9²=81、1²=1)。编写的C语言函数及测试用例如下:
原实现代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 128 unsigned long long square_digits (unsigned n) { char n_str[MAX]; char c_str[MAX]; char s_result[MAX]; unsigned long long converted, result; int i, len; sprintf(n_str, "%u", n); len = strlen(n_str); s_result[0] = '\0'; for (i = 0; i < len; ++i) { converted = n_str[i] - '0'; converted = converted * converted; sprintf(c_str, "%llu", converted); strcat(s_result, c_str); } result = strtol(s_result, NULL, 10); return result; }
测试用例
unsigned long long square_digits (unsigned n); #define do_test(n, expected) \ do { \ unsigned long long actual = square_digits(n); \ cr_assert_eq(actual, expected, "for n = %u, expected %llu, but got %llu", n, expected, actual);\ } while (false) Test(test_suite, sample_tests) { do_test( 3212u, 9414ull); do_test( 2112u, 4114ull); do_test( 0u, 0ull); do_test( 999u, 818181ull); do_test( 10001u, 10001ull); do_test(3210987654u, 9410816449362516ull); do_test(3999999999u, 9818181818181818181ull); // :p do_test( UINT_MAX, 164811681364948125ull); }
前6个测试用例均通过,但输入3999999999时,实际返回9223372036854775807,与预期的9818181818181818181不符。
问题原因
9223372036854775807是有符号64位整数(long long)的最大值。原代码中使用strtol函数进行字符串转整数操作,该函数返回的是long类型(多数系统为64位有符号整数)。当目标数值超过long的最大值时,strtol会返回LONG_MAX并设置errno为ERANGE。而测试用例中的预期值9818181818181818181是无符号64位整数,其值大于有符号64位整数的最大值,因此strtol无法正确转换,导致结果异常。
修复方案
将字符串转整数的函数从strtol替换为strtoull,该函数专门用于将字符串转换为unsigned long long类型,能够正确处理超出有符号整数范围的无符号数值。
修复后的代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 128 unsigned long long square_digits (unsigned n) { char n_str[MAX]; char c_str[MAX]; char s_result[MAX]; unsigned long long converted, result; int i, len; sprintf(n_str, "%u", n); len = strlen(n_str); s_result[0] = '\0'; for (i = 0; i < len; ++i) { converted = n_str[i] - '0'; converted = converted * converted; sprintf(c_str, "%llu", converted); strcat(s_result, c_str); } result = strtoull(s_result, NULL, 10); // 替换为strtoull return result; }
其他实现方式
可以避免字符串转换,直接通过数学运算实现,减少类型转换风险并提升效率:
数学运算实现
#include <stdio.h> unsigned long long square_digits(unsigned n) { unsigned long long result = 0; if (n == 0) { return 0; } // 提取所有数字(逆序存储) int digits[20]; // 足够存储unsigned类型的所有位数 int digit_count = 0; while (n > 0) { digits[digit_count++] = n % 10; n /= 10; } // 从高位到低位构建结果 for (int i = digit_count - 1; i >= 0; --i) { unsigned long long square = (unsigned long long)digits[i] * digits[i]; // 根据平方值的位数调整结果的倍数 if (square < 10) { result = result * 10 + square; } else { result = result * 100 + square; } } return result; }
该方法通过提取数字、反转顺序后直接计算拼接结果,无需依赖字符串操作,避免了类型转换带来的异常问题。
内容的提问来源于stack exchange,提问作者coed
相关产品推荐
相关产品推荐

