博文
Blog搬到新家了!(2007-04-30 15:21:00)
摘要:
经过一周的努力,终于在自己的空间里安装调试好了新博客。程序用的是Bo-Blog。
原来的Blog仍然继续使用,一来保留一下原来的习惯和风格,与新Blog形成互补,二来算是做个备份,网络上的事很难说,万一哪天其中的一个完蛋了,也不至于损失太惨重。 查看新Blog
没有专门的搬家工具,原Blog的所有文章不好直接导过去,手工搬过去又显得有些麻烦,经过最终的权衡,还是决定麻烦也要搬过去,理由如下:
保持存档的连续性。
所有日志做为资料保存下来,以便与后续日志保持连续!
便于快速查找所需日志。
新的Blog系统有全文搜索功能,可以快速找到需要的文章。
出色的代码显示功能
因为经常贴代码上来,就参考官方一个插件扩展了代码高亮显示功能,可以将C51,AVRGCC等官方未添加的语言代码按自定义的方式显示出来。这个功能用起来就是一个字:爽!
方便的边栏隐藏开关
可以通过顶部导航栏中的“边栏”将侧面的面板隐藏,这在查看日志中的代码时很有用。
自由的图片和附件空间
原Blog里只绐了5M的图片空间,单个文件也有限制,用自己的空间就随便多了。
附件同时上传、附件图文混排
这个功能可以将图片直接上传并编辑到日志中,不用像原来那样分开操作了。
留言评论回复更直接
可以在每条评论或留言下直接回复,层次清晰,能够更直接地和热心的网友交流了。
舒适而又美观的界面
新Blog系统皮肤模板可自己定制,虽然比个人比较喜欢简洁的风格,但既漂亮又不花哨的界面又怎能让我拒绝呢?
所以,花点时间把原来那些日志都搬过去是值得的,有用的也好,没用的也罢,反正已经在那了。考虑到搬过去是做为存档,旧日志仍然按原发布日期发布,新日志以今天为界按标准日期发布。
就要工作了,不知工作会有多忙,加班会有多严重,也不知还能不能顾的上更新日志,但我想只要能有所收获,我还是愿意把它记录下来……
......
[077] DDA画线算法(2007-01-15 22:19:00)
摘要:《计算机图形学》
整理一下计算机图形学上机时做过的一些小程序,某些部分参考了网上资源,由于时间已久,已经忘记出处。
所有程序均在TC环境编写测试,主要是因为在TC的图形系统下,分辨率较低,单个像素比较大,观察结果直观。另外,在TC下代码编写容易,可以把精力放在算法上。关于TC的图形系统参见:
[056] Turbo C的图形系统 。
DDA画线算法原理每本图形学的书里都有,这里将画线函数加了一个ms参数,用于延时,每画完一个点后用delay(ms)延时,这样就可以看到画线的过程了。由于TC里delay的定义有点老,所以在现在的机器上默认都不是按真正多少毫秒来执行的。
TC在我机器上默认识别的分辨率是640×480,即X方向为0~639,Y方向为0~479。所以定义X_MAX为639,Y_MAX为479。另外由于CRT显示器的原点在左上角,而我们习惯上将原点定义在左下角,所以在输出Y方向的坐标时要用高度最大值减去实际值,具体在程序中的Y_MAX - ((int) y)一句。主程序测试时画了一条由左下角到右上角的直线。
#include <math.h>
#include <stdio.h>
#include <graphics.h>
#define X_MAX 639 /* X方向最大值 */
#define Y_MAX 479 /* Y方向最大值 */
void initgr();
int LineDDA(int x1, int y1, int x2, int y2, int color, long ms);
int main(void)
{
long ms = 5000; /* 两点之间延持时间,便于观察画线过程 */
int color = 10; /* 设定颜色为绿色 */
&nbs......
[077] 任意大于6的偶数必定由两个素数组成(2007-01-01 22:17:00)
摘要:《C程序设计》(夏宝岚)
[相关] [031] 判断m是否是素数
[相关] [066] 筛选法求素数
哥德巴赫猜想的命题之一是:任意一个大于6的偶数必定由两个素数组成,试编写程序,验证并输出6至60以内的所有偶数的素数之和表达式。
由于每拆分一个偶数需要两次判断素数,因此程序中首先定义函数prime(),用于素数的判断,另外设计函数sumprime(int x),通过调用prime函数将一个偶数拆分成两个素数之和的表达式。
#include <stdio.h>
int prime(int x)
{
int i;
for (i = 2; x % i != 0; i++)
;
return x == i ? 1 : 0;
}
void sumprime(int x)
{
int t1, t2;
t1 = 1;
do
{
for (;;)
{
if (t1 <3 )
t1 = t1 + 1;
else<......
[076] 递归实现整数各位的分离(由高位到低位)(2006-12-27 21:21:00)
摘要:《C程序设计》(夏宝岚)
[相关] [048] 整数各位的分离(由低位到高位)
7.18 编写递归函数,以5位宽度左对齐的格式顺序输出正整数n中的每一位数字。例如,输入620857,则输出 6 2 0 8 5 7 。
#include <stdio.h>
void digit(long n)
{
long w;
if (n >= 10)
{
w = n / 10;
digit(w);
}
printf("%-5d", n % 10);
}
void main()
{
long x;
scanf("%ld", &x);
digit(x);
}
运行结果(VC):
=============================
620857↙
6 2 0 8 5 7
=============================
★ 输出部分,书上用的是 printf("%-5c", n % 10 + '0'); 即用字符格式输出的。在练习循环结构时,曾经写过倒序输出一......
[075] 求排列组合总数的函数(2006-12-01 12:15:00)
摘要:看到一个用C语言求排列组合总数的题,一时记不起公式了,翻了下概率书才想起,
排列数公式Pmn =m(m-1)…(m-n+1) , 可以用求阶乘的方法来做。
求出排列数,组合数就简单了,Cmn=Pmn /n! 而n!=Pnn。
根据这个思路,设计程序如下:
#include <stdio.h>
float P(int m, int n) /* 求排列数函数*/
{
int i;
float t = m;
for(i = 1; i < n; i++)
{
t = t * (m - i);
}
return t;
}
int main()
{
int m;
int n;
float s;
scanf("%d %d", &m, &n);
s = P(m, n) / P(n, n); /* 由排列数得到组合数 */
printf("C(%d,%d)=%-5.0f\n", m, n, s);
return 0;
}
运行结果(VC):
==========================
10 3↙
C(10,3)=120
==========================
[相关] [033] 阶乘->数据的范围 ......
[074] 字符串逆序输出(递归)(2006-11-19 22:18:00)
摘要:《C程序设计》(夏宝岚)
[相关] [053] 字符串逆序输出 。
编写递归函数,实现将输入的字符串以倒序输出。
#include <stdio.h>
void revers()
{
char c;
if((c = getchar()) != '\n')
revers();
if(c != '\n')
putchar(c);
}
void main()
{
revers();
printf("\n");
}
运行结果(VC):
=================
I am a student↙
tneduts a ma I
=================
★ 仔细“品”一下这个题目会发现很意思,特别是对理解递归的执行流程很有帮助(随便找一本C语言的书,都会找到执行流程的示意图)。不容易理解的就是那句putchar(c); 乍一看好像是输入回车后只会把最后的一个字符(即回车符)输出,而做了c!='\n'的限制后就应该什么都不输出才对,其实这正是递归的实质所在。
递归在编译系统里是通过堆栈来实现的,即如果函数当前层不满足结束条件,就会再次调用其本身,在调用之前,编译系统会为函数代码、形参以及函数中定义的局部变量在堆栈中分配单元,即将这些信息暂时存储起来,下一层函数若仍不满足结束条件,则重复此过程,继续将信息存储在系统堆栈中。在本题中,每一层输入的字符都已经存储在了堆栈中。当满足结束条件时,从最后层堆栈开始回归,一层层的返回。此题中从最后输入的回车符开始返回,完成了逆序将堆栈中存储的字符输出。
可能某些用词并不准确,不过我想我的理解应该没错^_^
[073] 递归函数的注意事项(2006-11-19 21:39:00)
摘要:《C程序设计》(夏宝岚)
<1> 一个正确的递归函数必须保证递推过程是有限制的,也就是说,递归函数的调用是带条件的,而且每次调用后条件会得到改变,否则将出现无休止地递推而无法回归的死递归。
<2> 递归函数的主要优点是算法设计容易,用于迭代、级数、链表等方面的算法有特殊效果,但递归函数的优点是在牺牲存储空间的基础上得到的,因为每进入下一层的调用,编译系统都将为函数代码、形式参数以及函数中定义的局部变量在堆栈中分配存储单元,只有当回归时,才从堆栈中退出。所以递归函数不能不分场合地乱用、滥用。......
[072] 求勒让德多项式(递归)(2006-11-19 21:18:00)
摘要:《C程序设计》(夏宝岚)
勒让德多项式定义为:
┌ 1 (n=0)
n!=ㄧ x (n=1)
└ ((2*n-1)*p(n-1,x)-(n-1)*p(n-2,x))/n (n>1)
#include <stdio.h>
double p(int n, double x)
{
if(n == 0)
return 1;
else
if(n == 1)
return x;
else
 ......
[071] 递归法求阶乘(2006-11-19 20:31:00)
摘要:《C程序设计第二版》(谭浩强)
[相关] [033] 阶乘->数据的范围
n!的递归公式:
┌ 1 (n = 0, 1)
n!=ㄧ
└ n * (n - 1)! (n > 1)
#include <stdio.h>
float fac(int n)
{
float f;
if(n < 0)
printf("n < 0, error!");
else
if(n == 0 || n == 1)
f = 1;
else
f = fac(n - 1) * n;
return f;
}
int main(void)
{
int n;
float y;
printf("input a integer:");
scanf("%d", &n);
y = fac(n);
&......
[070] 函数声明和函数原型(2006-11-19 16:49:00)
摘要:《C程序设计第二版》(谭浩强)
对函数的“定义”和“声明”不是一回事。“定义”是指对函数功能的确立,包括指定函数名,函数值类型、形参类型、函数体等,它是一个完整的、独立的函数单位。而“声明”的作用则是把函数的名字、函数类型以及形参类型、个数和顺序通知编译系统,以便在调用该函数时系统按此进行对照检查(例如函数名是否正确,实参与形参的类型和个数是否一致)。从程序中可以看到对函数的声明与函数定义中的函数首部基本上是相同的。因此可以简单地照写已定义的函数的首部,再加一个分号,就成为了对函数的“声明”。在函数声明中也可以不写形参名,而只写形参的类型。
在C语言中,函数声明称为函数原型(function prototype)。使用函数原型是ANSI C的一个重要特点。它的作用主要是利用它在程序的编译阶段对调用函数的合法性进行全面检查。
说明:
<1> 以前的C版本的函数声明方式不是采用函数原型,而只是声明函数名和函数类型。
如:float add(); 不包括参数类型和参数个数。系统不检查参数类型和参数个数。新版本也兼容这种用法,但不提倡这种用法,因为它未进行全面的检查。
<2> 实际上,如果在函数调用前,没有对函数作声明,则编译系统会把第一次遇到的该函数形式(函数定义或函数调用)作为函数的声明,并将函数类型默认为int型。如一个max函数,调用之前没有进行函数声明,编译时首先遇到的函数形式是函数调用"max(a, b)",由于对原型的处理是不考虑参数名的,因此系统将max()加上int作为函数声明,即int max(); 因此不少教材说,如果函数类型为整型,可以在函数调用前不必作函数声明。但是使用这种方法时,系统无法对参数的类型做检查。或调用函数时参数使用不当,在编译时也不会报错。因此,为了程序清晰和安全,建议都加以声明为好。
<3> 如果被调用函数的定义出现在主调函数之前,可以不必加以声明。因为编译系统已经先知道了已定义的函数类型,会根据函数首部提供的信息对函数的调用作正确性检查。
<4> 如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调用函数中不必对所调用的函数再作声明。
......