进制转换巩固练习之c语言实现


之前自己学过一些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中没有字符串的概念,没法返回字符串呀,都是字符数组的形式

}


 

 

你可能感兴趣的:(学习笔记)