我正在编写一个不使用printf的打印整数函数 . 该函数应该能够接受需要打印的整数,输出的基数以及要在整数值之前插入的字符 . 我已经能够制作大部分代码;然而,一旦输入超过15亿,输出保持不变,大约为10亿 . 在平台上我使用INT_MAX是21.7亿,所以我知道这肯定在int的范围内 . 另外,我想知道如何在没有静态数组的情况下创建这个函数:在我的情况下是baseDigs .
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "hw02.h"
int Pow(int a, int b);
void print_integer(int n, int radix, char* prefix){
if(radix == 0){
return -1;
}
char baseDigs[36]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','n','p','q','r','s','t','u','v','w','x','y','z'};
unsigned int buffer = n;
int dollar = 0;
int counter = 0;
int counter2 = 0;
int counter3 = 0;
int j = 0;
if (prefix[0] == '$'){
dollar++;
}
if(n < 0){
fputc('-', stdout);
buffer = -buffer;
}
while(prefix[j] != '\0'){
fputc(prefix[j], stdout);
j++;
}
while (buffer >= radix){
counter = 0;
counter2 = 0;
while((Pow(radix, counter)) <= buffer){
counter++;
}
counter--;
while(counter3 - counter > 1){
fputc('0', stdout);
counter3--;
}
counter3 = counter;
while((Pow(radix, counter)* counter2)<= buffer){
counter2++;
}
counter2--;
if (dollar > 0){
if(counter == 1){
fputc('.', stdout);
}
}
putchar(baseDigs[counter2]);
buffer-= Pow(radix,counter) * counter2;
}
while(counter3 > 1){
fputc('0', stdout);
counter3--;
}
fputc(baseDigs[buffer], stdout);
return;
}
int Pow(int a, int b){
if(b<0){
return (1/a) * Pow(a ,b-1);
}
else if (b==0) {
return 1;
}
else if (b==1){
return a;
}
else{
return a * Pow(a,b-1);
}
}
1 回答
问题在于
Pow
函数的结果:返回类型是int
(可能是32位),并且发生溢出 . 我将在此期间使用int32_t
(在stdint.h
中定义),假设您的系统具有32位整数(大多数台式计算机都有,但如果这是针对可能不是这种情况的嵌入式系统),则要明确问题是 .你使用
Pow
在n
之后获得10的下一个幂,但是对于接近INT32_MAX的值(特别是1,000,000,000之后的任何值,这是10的第一个幂小于INT32_MAX
),10的下一个幂不能表示为aint32_t
(因为10,000,000,000 > INT32_MAX
)导致溢出(我相信结果是未定义的,但实际上Pow
返回的值很可能是-(INT32_max-10,000,000,000)
) .所以,你可以通过增加
Pow
结果中使用的位数来解决这个问题,方法是让它返回int64_t
(或long long int
,如果你不想使用stdint.h
)另外,不要忘记按照我在上面的评论中提到的那样对缓冲区进行签名 . 您的编译器应该捕获并发出警告,如果没有,那么您可能没有编译启用所有警告 . 在一些(大多数?)编译器中,通过将标志-Wall传递给它来启用它 .
编辑:
请参阅chux关于为什么使
buffer
签名不是正确解决方案的评论(使用unsigned
是完全定义的并且有效) . 考虑始终使用int64_t
以避免溢出和类型转换 .