之前自己学过一些c语言的知识,刚开始就在进制转换那里卡住了,所以看到毕老师讲的进制转换的知识,很有感觉,呵呵
看懂后,就想用C语言试试写一下,发现了很多问题,代码中都有说明。代码下载
文件说明:
思考及实现过程和存在的问题注释里都有详细说明
可以直接运行对应的exe文件测试效果
进制转换.c
仿照毕老师Java教程中的进制转换方法写的
测试结果:
C语言中没有无符号右移,所以不能直接用这个方法转换负数
如果输入负数,会出现问题,继续思考实现方法
在进制转换Update.c文件中已经实现了负数转换
/*
2012年11月21日9:19:25
仿照毕老师Java教程中的进制转换来一下
测试结果:
C语言中没有无符号右移,所以不能直接用这个方法转换负数
如果输入负数,会出现问题,继续思考实现方法
在进制转换Update.c文件中已经实现了负数转换
*/
#include
void trans(int, int, int);
int main(void)
{
int num, base;
char ch;
while (1)
{
printf("输入要转换的数字:");
scanf("%d", &num);
printf("输入要转换的进制(2,8,16):");
scanf("%d", &base);
switch (base)
{
case 2: trans(num, 1, 1);
break;
case 8: trans(num, 7, 3);
break;
case 16:trans(num, 15, 4);
break;
default: printf("不支持的类型转换\n");
}
printf("继续请输入“Y”或“y”,退出请按任意键:");
getchar();
ch = getchar();
if (ch=='Y' || ch=='y')
{
continue;
}
else
{
break;
}
}
return 0;
}
//只将转换后的结果输出吧,因为都是字符,还不能参加运算
void trans(int num, int base, int offset)
{
char chs[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
char arr[32] = { ' '};
int pos = 32-1, temp;
while (num!=0)
{
temp = num & base;
arr[pos--] = chs[temp];
num = num >> offset; //C语言中不知道有没有无符号右移
}
for (temp=pos; temp<32; temp++)
{
printf("%c ", arr[temp]);
}
}
进制转换update.c
已经可以实现十进制数到2、8、16进制之间的转换
另一个进制转换toInt.c文件中是实现其他进制到十进制的转换
/*
2012年11月21日9:19:25
仿照毕老师Java教程中的进制转换来一下
C语言中没有无符号右移,所以不能直接用这个方法转换负数
下面的程序已经可以实现十进制数到2、8、16进制之间的转换
另一个进制转换toInt.c文件中是实现其他进制到十进制的转换
*************************
2012年11月23日10:38:03
负数转换方法想出来了
思路:
转换时先判断下是否是负数,是的话先往数组尾部写一个负号
然后按照原来步骤与上一个base数据,再右移offset位
再次判断是否是负数,因为高位补1后就还是负数
如果右移后还是负数(高位补1),就将右移后的数据再与上一个对应的数将前边的几位0转换为1后继续循环
高位1换为0要与上的数(用16进制表示):C语言中注意int在不同系统中所占字节数的大小
sizeof(int) = 4时
1111-1111 1111-1111 1111-1111 1111-1111
toBin 0111-1111 1111-1111 1111-1111 1111-1111 0X 7-F F-F F-F F-F
toOct 0001-1111 1111-1111 1111-1111 1111-1111 0X 1-F F-F F-F F-F
toHex 0000-1111 1111-1111 1111-1111 1111-1111 0X 0-F F-F F-F F-F
sizeof(int) = 2时
1111-1111 1111-1111
toBin 0111-1111 1111-1111 0X 7-F F-F
toOct 0001-1111 1111-1111 0X 1-F F-F
toHex 0000-1111 1111-1111 0X 0-F F-F
*/
//总算OK了 2012年11月23日13:26:34
#include
void trans(int, int, int);
int main(void)
{
int num, nbase;
char ch;
while (1)
{
printf("输入要转换的数字:");
scanf("%d", &num);
printf("输入要转换的进制2/8/16:");
scanf("%d", &nbase);
switch (nbase)
{
case 2: trans(num, 1, 1);
break;
case 8: trans(num, 7, 3);
break;
case 16:printf("0X"); trans(num, 15, 4);
break;
default: printf("不支持该进制类型的转换\n");
break;
}
printf("继续请输入“Y”或“y”,退出请按任意键:");
getchar();
ch = getchar();
if (ch=='Y' || ch=='y')
{
continue;
}
else
{
break;
}
}
return 0;
}
//不用那么复杂了 直接来吧
void trans(int num2, int base, int offset)
{
char chs[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
char arr[32] = { ' '};
int pos = 32-1, temp;
int val; //用来存放将高位转换为0时要与上的数据
int num = num2;
if (num2==0)
{
printf("0\n");
return ;
}
while (num!=0)
{
if (num<0 && base!=1) //如果是负数, 二进制就不用写负号了,所以最后还要判断num是否是负数
{ //因此函数中不能改动num原值,二进制的话直接将其二进制形式输出即可
// chs[pos--] = '-'; //这里又搞错了 因为打印时是倒着打印的 所以不应该先加负号 应该最后加负号
num = -1*num; //已经写完负号了 就标记为负数了 剩下的直接转正数部分就OK了
}
temp = num & base;
arr[pos--] = chs[temp];
num = num >> offset;
//还要判断 因为上面的没有管负数二进制情况
if (num<0) //如果高位补的是1,还是负数,就将高位置0
{
int sizeInt = sizeof(int); //判断int类型所占的字节数
if (sizeInt==4)
{
val = 0x7fffffff;
}
else if (sizeInt==2)
{
val = 0x7fffffff>>16; //右移两个字节
}
num = num & val;
}
//最后再次判断输入的数是否负数 在数组中加上负号 二进制排除在外
if (num2<0 && base!=1)
{
arr[pos] = '-';
}
}
//输出
for (temp=pos; temp<32; temp++)
{
printf("%c ", arr[temp]);
}
printf("\n");
}
//下面的都没什么用了 不用那么复杂了
/*感兴趣的可以看看我当时的思考过程
//用来获取修改高位补0的数据,根据不同进制转换时的基数返回相应的值
//默认int类型占4个字节,用时进行sizeof(int)判断,2字节时将结果右移16位即可
int getVal(int base)
{
switch (base)
{
case 1: return 0X7FFFFFFF;
break;
case 7: return 0X1FFFFFFF;
break;
case 15: return 0X0FFFFFFF;
break;
default: printf("不支持的转换进制");
}
return 0;
}
//****试试看
//先将负数提升为long类型,将高位全置为0,右移一次后在转为int
//不行 试验后知道,VC中int和long全是4个字节 转后还是负数 失败呀 浪费好长时间 还不知道原因呢
void trans2(int num, int base, int offset)
{
char chs[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
char arr[32] = { ' '};
int pos = 32-1, temp;
long l;
if (num==0)
{
printf("0\n");
return ;
}
while (num!=0)
{
if (num<0 && base!=1) //如果是负数, 二进制就不用写负号了
{
chs[pos--] = '-';
l = (long)num & 0xFFFFFFFF; //将num转换为long并将有效位保留,高位置0
printf("%l\n", l);
}
temp = l & base;
arr[pos--] = chs[temp];
l = l >> offset;
num = (int)l;
}
for (temp=pos; temp<32; temp++)
{
printf("%c ", arr[temp]);
}
printf("\n");
}
*/
//修改转换过程,加入负数判断
//**********负数二进制可以转换了,8、16进制负数转换会出错,原因还没找到,先吃饭
/*
************问题出在这里了,看打印提示:
输入要转换的数字:10
输入要转换的进制:8
1: temp= 10 & 7 = 2
2: num= 1 >> 3 = 1
第一次操作后temp=2 num=1
1: temp= 1 & 7 = 1
2: num= 0 >> 3 = 0
第一次操作后temp=1 num=0
输入要转换的数字:-10
输入要转换的进制:8
判断num《0 写负号成功
1: temp= -10 & 754974727 = 754974726
这里&上的数应该是7 怎么变这么大了???
10——12
-10——-12
-10 二进制形式:
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0
& 1 1 1
--------------------------------------------------------------------
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0
#############################################################
※ 终于灵光一现 知道解决方法了
※ 负数转二进制就按原来方式转就可以了,因为内存中存储的本身就是二进制形式
※ 转8、16进制只想在正数基础上加一个负号,就不能按负数二进制形式转了
※ 因为负数在计算机中是按反码加1存在的,直接转出来肯定不对了,都不是原来的数据了
※ 所以判断 只要是负数转8、16进制,就先写一个负号后,立马将其转为正数即可
※ 妈的 这么简单的问题被我搞的这么复杂
※※※※※※※※※※※※※※※※※※※※※※※※※※※※※
※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※
※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※
#############################################################
*/
/*
void trans_分析出原因了(int num, int base, int offset)
{
char chs[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
char arr[32] = { ' '};
int pos = 32-1, temp;
int val; //用来存放将高位转换为0时要与上的数据
if (num==0)
{
printf("0\n");
return ;
}
while (num!=0)
{
if (num<0 && base!=1) //如果是负数, 二进制就不用写负号了
{
chs[pos--] = '-';
printf("判断num《0 写负号成功\n");
}
temp = num & base;
printf("1: temp= %d & %d = %d\n", num, base, temp);
arr[pos--] = chs[temp];
num = num >> offset;
printf("2: num= %d >> %d = %d\n", num, offset, num);
printf("第一次操作后temp=%d num=%d\n", temp, num);
if (num<0) //如果高位补的是1,还是负数,就将高位置0
{
int sizeInt = sizeof(int); //判断int类型所占的字节数
printf("第一次移位后补的是1,还为负\n");
if (sizeInt==4)
{
val = getVal(base);
}
else if (sizeInt==2)
{
val = getVal(base)>>16; //右移两个字节
}
num = num & val;
printf("第一次移位为负,高位补0 & 0X %X 后num=%d\n", val, num);
}
}
for (temp=pos; temp<32; temp++)
{
printf("%c ", arr[temp]);
}
printf("\n");
}
//只将转换后的结果输出吧,因为都是字符,还不能运算
void trans_old(int num, int base, int offset)
{
char chs[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
char arr[32] = { ' '};
int pos = 32-1, temp;
while (num!=0)
{
temp = num & base;
arr[pos--] = chs[temp];
num = num >> offset; //C语言中不知道有没有无符号右移
}
for (temp=pos; temp<32; temp++)
{
printf("%c ", arr[temp]);
}
}
*/
进制转换toInt.c
趁热打铁 再写一个将2、8、16进制转换为10进制的程序
/*
2012年11月23日13:27:44
趁热打铁 再写一个将2、8、16进制转换为10进制的程序吧
10进制转2、8、16进制程序参看:进制转换update.c
目前的程序没有对负数进行判断,所以还不能接收负数进行转换
没有解决的问题:
C中没有字符串的概念,字符串都是以字符数组的形式存在的,
最后打印的结果中想把原来输入的数据也打印一遍发现不太好弄
想用一个函数将字符数组中的字符组成一个字符串返回,发现即便是返回了也还是一个字符数组
字符数组打印时用一个%s接收打印出的结果真是无法想像呀,试试就知道了
还有一个问题,输入二进制数据时1、11都可以正常转换,
但输入111就应该是7却转换为6,其他二进制也有不同形式的错误,
还没有解决的问题,先记录下来,目前主攻方向是Java,这个算课余消遣即兴发挥了
思路:
用字符数组接收其他进制数据,输入时就指定好输入的数据属于那种进制类型
计算出数组长度,因为要从低位开始转换
字符转数字
数字 ASCII
0 48
a 97
A 65
char[] arr 接收数据
len=arr.length
for(i=len-1, x=1; i>=0; i--, x=x*base)
sum = sum + arr[i]*x;
↑---------------------↑
上面的arr[i]要转换成数字,sum运算之前 先判断arr[i]
if 0=
void trans(char[], int);
int main(void)
{
char arr[32] = {'\0'}; //不初始化判断长度时就是32'1','a','\0',
int base = 0;
char ch;
while (1)
{
printf("请输入要转换的数据:");
scanf("%s", arr);
getchar(); //这里没有问题
// //gets(arr);
/* //可能是这里有问题
for (base=0; base<32; base++)
{
ch=getchar();
if (ch!=' '&& ch!='\n')
arr[base] = ch;
else
break;
getchar();
}
*/
printf("请输入要转换成十进制数据的进制类型:");
scanf("%d", &base); //奇怪 base指定没问题 运行期间输入就不行了
getchar(); //奇什么怪呀 输入时要用&base 只写base往哪里存呀 知道了
// base=8;
//怎么到这里都走不下去了?? 测试下看看
printf("你要转换的 %s 是 %d 进制类型的\n", arr, base);
/*指定数据就可以运行 真是奇怪了 数组初始化110 也能运行 就是输入不能运行
arr[0]='1';
arr[1]='1';
arr[2]='0';
base = 2;
*/
switch (base)
{
case 2: trans(arr, 2);
break;
case 8: trans(arr, 8);
break;
case 16: trans(arr, 16);
break;
default : printf("不支持的进制类型\n");
return 0;
}
printf("继续请输入“Y”或“y”,退出请按任意键:");
ch = getchar();
if (ch=='Y' || ch=='y')
{
continue;
}
else
{
break;
}
}
return 0;
}
void trans(char * arr, int base)
{
int i, x, len = 0; //len记录数组长度
int sum = 0; //存放转换后的结果
for (i=0; arr[i]!='\0'; i++)
{
len++;
}
// printf("%s长度为%d\n", arr, len);
for (i=len-1, x=1; i>=0; i--, x=x+base-1)
{
if (arr[i]>='0' && arr[i]<='9')
{
arr[i] = arr[i] - '0';
}
else if (arr[i]>='a' && arr[i]<='z')
{
arr[i] = arr[i] - 87;
}
else if (arr[i]>='A' && arr[i]<='Z')
{
arr[i] = arr[i] - 55;
}
else
{
printf("你输入的数据中含有非法字符:%c\n", arr[i]);
return ;
}
sum = sum + (arr[i]*x);
}
printf("%d进制数:%s 转换为十进制数是:%d\n", base, arr, sum);
//最后输出提示信息时不能用%s直接输出数组中原来的内容,所以用一个函数将数组中的字符组成一个字符串
//Java学的时间常了竟然忘了C中没有字符串的概念,没法返回字符串呀,都是字符数组的形式
}