本文目录一览:
c语言问题
一、 算法设计及流程
1. 点
不管什么样的图形归根结底到屏幕,都是由一些颜色不一的象素点组成,为提高图形的显示效率,没有用到系统的画点函数,而采用了640*480*16模式下的直接写屏技术画点,该模式下的直接写屏比320*200*256的直接写屏要复杂的多,后者的视频缓冲区是线性编址的,一个字节对应屏幕上一点的颜色,而前者的视频缓冲区被分成四个位面,屏幕上一点的颜色由每个位面上的一位组成的四位二进制数决定,由于四位二进制数的最大表示范围是16,所以在这种模式下最多可同时显示16种颜色。
在对视频缓冲区的读写时,是一个字节一个字节写的,只需要其中某一位时,就要用到位掩码屏蔽掉其他的位,位掩码就在图形控制寄存器的位屏蔽寄存器里设置。先通过向端口号为0x3ce的索引寄存器写入位屏蔽寄存器的索引号8,然后向端口号为0x3cf的寄存器写入位掩码值。设置好位掩码后,直接向视频缓冲区相应位置写入颜色即为画点函数。
取屏幕上一点颜色其实也就是画点的反操作,画点是将一个四位的二进制颜色值分配到四个位面,而取一点的颜色是将四个位面的颜色组合成一个四位二进制数。
2. 线
线其实就是由点组成的,通过连续的改变点的坐标,也就可以得到一条线。所以画线的函数归根结底也就是如何改变画点的坐标。
画线通常有DDA算法,BRESENHAM算法,这里采用的是BRESENHAM算法。这种算法从根本上讲,是通过横线与竖线的倍数关系来实现的。每次循环画点后x、y中位移大的坐标变化一个单位,而当循环次数是两者倍数关系时,x、y中位移小的坐标变化一个单位。为了使画线函数能在八个方向都能画,将增量为负的都转化正的增量。
画图程序经常要用到moveto、lineto等函数,用于把点移动到某点或从当前点画线到某点,为了模拟这些函数,设置了SX,SY两个全局变量用来作为Moveto()的目的地和Drawlineto()的起始坐标。
3. 矩形及填充矩形
矩形是通过两点确定的对角线来画的,直接连上各点的坐标就可以了。填充矩形是通过一条线一条线画的。这种算法速度比较慢,较好的方法是用Fillscreen()里面用到的方法,那是一个字节一个字节处理的。就因为画矩形并不一定是整字节开始整字节结束的,开始处和结尾处就有了问题。我也把它们单独拿出来处理,但还是没做好,等有时间了再改吧。
4. 圆及弧
画圆采用的是参数方程的方法。为了提高速度,角度的sin、cos值建立了一个表,要用时直接查表。这是因为在用BRESENHAM算法画椭圆时,效果不是很好,画的椭圆不但厚薄不一,而且不闭合。估计是程序哪里出问题了,干脆都用参数方程的方法,又简单,又省事。我这人通常是比较懒的。
弧主要是用来画圆角矩形的,且只能画圆弧。这也是用参数方程来画的,跟画圆不同的只是有了角度的限制。
5. 贝塞尔曲线
贝塞尔曲线其实主要也就是一个公式,跟参数方程画圆是一回事,只是要传入的参数要多一些。在用鼠标控制时,因为有四个点,而用鼠标对多点的采集有点不好做,于是先就初始化了一个四点的数组,用不按键、按左键、按右键分别控制三个点,左右键同时按时,确定下一条曲线。
其实用鼠标画贝塞尔曲线因该把一次、二次、三次的处理函数都写出来,在按下左键时,标记下这点,再一次按下左键时,用画一次贝塞尔曲线的函数画,按下第三次时,用画二次曲线的函数画,按下第四次时才用画三次曲线的函数画。这样就不用为每个点分配一个鼠标按键了。
6. 填充
填充也是采用的种子填充法,不过不是直接从种子开始填色,而是先从种子出发,找到种子沿x最小的边界,然后填上一点,判断这一点的上边一点和下边一点,如果不为边界并且未被填色,则压入栈中,然后x增1后判断是否到达这一行x的最大值(既边界),如不是,则循环处理这一行,直到到达边界,再弹出一个点继续循环处理。由于是一个点一个点处理,所以速度比较慢。
为了对一个图形的不同颜色边界也能填充,填色时没有传入图形的边界颜色,而是采用先取出种子的颜色,在填充下一个点时,把下一点的颜色和种子颜色比较,如果相同则填色,不同则作为边界。
7. 汉字及字符
图形模式下显示汉字其实是一件比较麻烦的事,一般要用到汉字字库,生成的可执行文件也得在有字库的环境下运行。我这里采用了汉字无字库技术,生成的文件不依赖任何其他文件。
无字库技术是通过从字库文件提取需要的中文点阵字模建立一个类似字库的字库数组。它可以大大提高汉字的显示速度。在建立字库数组时,将字模数组进行了排序,所以在显示汉字时
文章来自: 好喜爱学习网() 网址:
求51单片机仿真程序c语言的
用51单片机设计多路竞赛抢答器,这种题目,在百度上真是泛滥成灾了,随便一搜就能搜到一大堆,有仿真图和程序全部资料的。或者百度文库里也同样可以搜索到,还是毕业论文,更是详细。
下图是一个8路抢答器的仿真图。
请大家帮忙用C语言换种方法表达下面单片机的编程,但其单片机仿真的结果要与原来完全一样。
假定原语句和标点符号是对的,例如 while(S2==0); 带分号。-- 不给你修改。
把变量改用数组:
#includereg52.h
#define uint unsigned int
#define uchar unsigned char
sbit S[4];
sbit LAMP[4];
void main()
{
int i;
for (i=0;i4;i++) {
S[i]=P1^i;
LAMP[i]=P2^i;
}
for (i=0;i4;i++){
if (S[i]==0){
while(S[i]==0);
LAMP[i]=~LAMP[i];
};
}
C语言类型强制转换的注意事项
1.类型说明符和表达式都必须加括号(单个变量可以不加括号),如把(int)(x+y)写成(int)x+y则成了把x转换成int型之后再与y相加了。
2.无论是强制转换或是自动转换,都只是为了本次运算的需要而对变量的数据长度进行的临时性转换,而不改变数据说明时对该变量定义的类型。
例1:
main()
{
float f=5.75;
printf(f=%d,f=%f\n,(int)f,f);
}
f=5,f=5.750000
将float f强制转换成int f float f=5.75;printf((int)f=%d,f=%f\n,(int)f,f); 本例表明,f虽强制转为int型,但只在运算中起作用, 是临时的,而f本身的类型并不改变。因此,(int)f的值为 5(删去了小数)而f的值仍为5.75。
例2:
比如我们可以(int)'A',这样转换后的结果为A的ASCII码数值,因为那块内存本来就存的那个数,只是换个形式使用而已。 知道上面的原则,我们可以对任何数据类型进行转换,但是转换的结果可能不是你想像的结果,举例(int)'9'的结果为多少?不是9而是0x39。来个高深点的printf(%d,‘12’);的输出是什么?正确答案是12594,因为printf(%d,'12'),打印的是存储12的内存地址上的内容,即ASCII码值2存储在低位,1储在高位地址,0x32就是2的ASCII码,0x31就是1的ASCII码,所以是0x3132,转换成10进制就是12594!
● 字符型变量的值实质上是一个8位的整数值,因此取值范围一般是-128~127,char型变量也可以加修饰符unsigned,则unsigned char 型变量的取值范围是0~255(有些机器把char型当做unsighed char型对待, 取值范围总是0~255)。
● 如果一个运算符两边的运算数类型不同,先要将其转换为相同的类型,即较低类型转换为较高类型,然后再参加运算,转换规则如下图所示。
double ←── float 高
↑
long
↑
unsigned
↑
int ←── char,short 低
● 图中横向箭头表示必须的转换,如两个float型数参加运算,虽然它们类型相同,但仍要先转成double型再进行运算,结果亦为double型。 纵向箭头表示当运算符两边的运算数为不同类型时的转换,如一个long 型数据与一个int型数据一起运算,需要先将int型数据转换为long型, 然后两者再进行运算,结果为long型。所有这些转换都是由系统自动进行的, 使用时你只需从中了解结果的类型即可。这些转换可以说是自动的,当然,C语言也提供了以显式的形式强制转换类型的机制。
● 当较低类型的数据转换为较高类型时,一般只是形式上有所改变, 而不影响数据的实质内容, 而较高类型的数据转换为较低类型时则可能有些数据丢失。
赋值中的类型转换
当赋值运算符两边的运算对象类型不同时,将要发生类型转换, 转换的规则是:把赋值运算符右侧表达式的类型转换为左侧变量的类型。具体的转换如下:
(1) 浮点型与整型
● 将浮点数(单双精度)转换为整数时,将舍弃浮点数的小数部分, 只保留整数部分。将整型值赋给浮点型变量,数值不变,只将形式改为浮点形式, 即小数点后带若干个0。注意:赋值时的类型转换实际上是强制的。
(2) 单、双精度浮点型
● 由于C语言中的浮点值总是用双精度表示的,所以float 型数据只是在尾部加0延长为double型数据参加运算,然后直接赋值。double型数据转换为float型时,通过截尾数来实现,截断前要进行四舍五入操作。
(3) char型与int型
● int型数值赋给char型变量时,只保留其最低8位,高位部分舍弃。
● char型数值赋给int型变量时, 一些编译程序不管其值大小都作正数处理,而另一些编译程序在转换时,若char型数据值大于127,就作为负数处理。对于使用者来讲,如果原来char型数据取正值,转换后仍为正值;如果原来char型值可正可负,则转换后也仍然保持原值, 只是数据的内部表示形式有所不同。
(4) int型与long型
● long型数据赋给int型变量时,将低16位值送给int型变量,而将高16 位截断舍弃。(这里假定int型占两个字节)。 将int型数据送给long型变量时,其外部值保持不变,而内部形式有所改变。
(5) 无符号整数
● 将一个unsigned型数据赋给一个占据同样长度存储单元的整型变量时(如:unsigned→int、unsigned long→long,unsigned short→short) ,原值照赋,内部的存储方式不变,但外部值却可能改变。
● 将一个非unsigned整型数据赋给长度相同的unsigned型变量时, 内部存储形式不变,但外部表示时总是无符号的。
/*例:赋值运算符举例 */
main()
{
unsigned a,b;
int i,j;
a=65535;
i=-1;
j=a;
b=i;
printf((unsigned)%u→(int)%d\n,a,j);printf((int)%d→(unsigned)%u\n,i,b);
}
运行结果为:(unsigned)65535→(int)-1(int)-1→(unsigned)65535
● 计算机中数据用补码表示,int型量最高位是符号位,为1时表示负值,为0时表示正值。如果一个无符号数的值小于32768则最高位为0,赋给 int型变量后、得到正值。如果无符号数大于等于32768,则最高位为1, 赋给整型变量后就得到一个负整数值。反之,当一个负整数赋给unsigned 型变量时,得到的无符号值是一个大于32768的值。
● C语言这种赋值时的类型转换形式可能会使人感到不精密和不严格,因为不管表达式的值怎样,系统都自动将其转为赋值运算符左部变量的类型。
● 而转变后数据可能有所不同,在不加注意时就可能带来错误。 这确实是个缺点,也遭到许多人们批评。但不应忘记的是:c语言最初是为了替代汇编语言而设计的,所以类型变换比较随意。当然, 用强制类型转换是一个好习惯,这样,至少从程序上可以看出想干什么。