用户操作
[留言]  [发消息]  [加为好友] 
订阅我的博客
XML聚合    FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
seton040的公告
想要一架没有电脑和涡轮的滑翔机 在澳洲环抱大堡礁的山麓岛屿间飞行
文章分类
好友链接
刘老师
汪总
会飞的猪
褪墨
风雷
名博
时光
李先静老师
王小峰
韩寒
存档
2010年01月09日

原创 一道TCL的笔试题---递归

题目: 在下面这个程序片段中的划线处填上适当的表达式,使之逆序输出数组元素。 -------------------------------------------------------------------------------- void recur(int a[], int k) { int tmp; if(_____) { recur(_____, _____); tmp = a[0]; a[0] = a[k-1]; a[k-1] = tmp; } } -------------------------------------------------------------------------------- 这道题目要用递归的思想完成数组元素的逆序排列,我们先来复习一下有关递归函数一般解题思路。 一般而言,递归函数要有一个恰当的返回条件,以便到达那个条件的时候返回,不阅读全文>

发表于 @ 2010年01月09日 21:37:00 | 评论( loading... ) | 编辑| 举报| 收藏

2010年01月06日

原创 变参函数实现细节

C语言的函数虽然不具备C++的多态性,但也可以接受参数不确定的情况,当然,C语言中的变参函数实际在功能上是受限的,废话不多讲,下面来看看变参函数的边边角角的问题。讨论之前我们来看一下最熟悉的变参函数printf的原型声明:int printf(const char *format,  ...);注意到,在函数中声明其参数是可变的方法是三个点“...”,但同时,这个函数必须要有一个固定的参数,比如printf里面的这个format,也就是说变参函数的参数数目至少是一个。这是由C语言中实现变参的原理---计算堆栈地址---决定的。顺着printf函数我们来看看它的定义是什么:int __printf(const char *format, ...){    va_list  arg;    int done;    va_start(arg,  format);    done = vfprintf(stdout,  format, 阅读全文>

发表于 @ 2010年01月06日 15:30:00 | 评论( loading... ) | 编辑| 举报| 收藏

2009年11月20日

原创 目标文件里装了什么东西

了解程序中各种变量在编译和运行阶段的状态和属性,对我们开发程序而言是非常有益的,通过对以下几个例子的探讨,能让我们明白C语言中各种存储类对程序的影响,也让我们在编写一个程序的时候胸有成竹。就像那个谁说的那样,真正的程序员,必须对自己程序的每一个细节了如指掌。 我们看看如下这个程序代码: -------------------------------------------------------------------------------- /* simple_section.c */ int printf(const char *format, ...); int global_init_var = 1; //已初始化的全局变量 int global_uninit_var; //未初始化的全局变量 void func(int i) { printf("%d,\n", i); } int main(void) { static int local_static_阅读全文>

发表于 @ 2009年11月20日 19:57:00 | 评论( loading... ) | 编辑| 举报| 收藏

2009年11月03日

原创 一道试题引发的血案

某日,看到一道比较恶心的C语言的试题,考了很多比较绕的知识点,嘴脸如下:int main(void){ int a[4] = {1, 2, 3, 4}; int *ptr1=(int *)(&a+1); int *ptr2=(int *)((int)a+1); printf("%x, %x\n", ptr1[-1], *ptr2); return 0;}问,在x86平台下输出啥?题目虽然恶心了点,但作为一个例子来分析,还是挺好玩的。详细如下:1、&a+1首先明确,a是一个具有4个整型变量的数组的名字,具体地说是这种数组的首地址,注意,我没有说a是数组首元素的地址。因此,当&a与整数1做加法时,实际上是指针的加法,加1的含义是:令指针a指向下一个元素,下一个元素是啥?当然是紧挨着的下一个具有4个整型变量的数组了,于是a的指向了4的下一个地址。如图:由于在ptr1初始化的时候,令&a+1强制转换成整型指针,因此ptr1[-1]相当于指向了ptr阅读全文>

发表于 @ 2009年11月03日 22:40:00 | 评论( loading... ) | 编辑| 举报| 收藏

2009年10月23日

原创 字符界面编程利器——vim + ctag + Taglist

习惯了在windows下用sourceInsight编程的人,当然也希望在linux的字符终端下也能有一样酷的软件,这里要介绍给大家的是如题所示的三款软件:vim, ctag和Taglist。很多时候我们需要在多个源程序之间实现函数、宏定义、外部变量等的跳转查询,甚至有时候需要到内核或库源代码里窥视他们真面目,我们也需要有列出程序内部所使用的各个函数、变量、宏等等信息的工具,这些功能仅仅靠vim是完成不了的,但也不必失望,因为我们还有两件利器:ctag负责建立标签,为实现文本间关键字实现跳转提供基础,Taglist是一个vim插件,帮助我们罗列程序中所有出现的关键的地方。以我的系统(ubuntu-i386-9.04)为例,我们分别来看看如何使用它们。一、ctag当然,第一步就是要下载它!一条命令搞定:$sudo apt-get install ctags如果不幸提示找不到软件包ctags,首先你也许应该update一下你的软件源,还不行的话试试把ctags改成 exuberant-ctags下载完了你就可以用它来产阅读全文>

发表于 @ 2009年10月23日 15:08:00 | 评论( loading... ) | 编辑| 举报| 收藏

2009年10月21日

原创 C语言**位运算**终极剖析

C语言有时候被称为中级语言,即介于低级与高级之家的编程语言,原因是C语言不仅具有高级语言抽象机制,也具有低级语言直接操作变量个别位的能力,即我们即将要讨论的C语言强大的位操作运算。C语言的这种能力也许会让你感到奇怪,但这种能力有时确实是必须的,或者至少是有用的,例如我们通常向硬件设备发送一两个字节来控制该设备,其中的每一位都有特定的含义。许多压缩和加密操作都对单独的位进行操作。高级语言一般不处理这一级别的细节,可C语言在提供高级语言便利的同时也能够在典型的为汇编语言所保留的级别上工作,这就是C语言之所以能成为编写设备驱动程序和嵌入式代码首选语言的原因。在正式进入美妙的主题C语言位运算的讨论之前,我们必须先了解一些酷炫的背景知识:一、二进制说到计算机当然不能不知道二进制,就像玩吉他不能不知道五线谱一样,所谓二进制就是逢二进一,我们日常用的是十进制,逢十进一。另外,十进制的数字每一位对应一个10的某次幂,二进制的数字每一位对应一个2的某次幂。比如: (5017)10 = 5*103 + 0*102 + 1*101 + 7*100 = 5000 + 阅读全文>

发表于 @ 2009年10月21日 16:24:00 | 评论( loading... ) | 编辑| 举报| 收藏

2009年10月19日

原创 类型转换

类型转换是C语言中常识性的知识点,但不注意又会有让人迷惑的时候,来看一道笔试题:以下两个程序片段A和B,问那个for循环能运行?A:unsigned short i;unsigned short index=0;for(i = 0; i unsigned int -> long -> unsigned long -> long long -> unsigned long long -> float -> double -> long double注意,上面的顺序并不一定适用于你的机器,比如当int和long具有相同字长时,unsigned int的精度就会比long的精度高(事实上大多数针对32机的编译器都是如此)。另外需要注意的一点是并没有将char和short型写入上式,原因是他们可以被提升到int也可能被提升到unsigned int。阅读全文>

发表于 @ 2009年10月19日 19:33:00 | 评论( loading... ) | 编辑| 举报| 收藏

2009年09月27日

原创 IO编程 之 缓冲篇

涉及linux中IO编程的时候,我们总是不可避免地要跟各种各样的缓冲机制打交道,学好linux IO编程不是简单地掌握几个函数的用法就万事大吉,正确地运用IO需要对其缓冲机制全面的理解,切不可依葫芦画瓢,蒙混过关。切入正题之前,我们先看一个简单的程序:#include #include #include #define BUFSIZE 5*1024 int main(void){     FILE *fp1, *fp2;     char buf[BUFSIZE];     fp1 = fopen("src", "r");     fp2 = fopen("des", "w");     fgets(buf, BUFSIZE, fp1);阅读全文>

发表于 @ 2009年09月27日 01:52:00 | 评论( loading... ) | 编辑| 举报| 收藏

2009年09月22日

原创 vim编码

Vim和所有的流行文本编辑器一样,可以很好的编辑各种字符编码的文件,这当然包括 UCS-2、UTF-8 等流行的 Unicode 编码方式。而且和很多来自 Linux 世界的软件一样,这需要你自己动手设置。 Vim 有四个跟字符编码方式有关的选项,encoding、fileencoding、fileencodings、termencoding (这些选项可能的取值请参考 Vim 在线帮助 :help encoding-names),它们的意义如下: 1、 encoding: Vim 内部使用的字符编码方式,包括 Vim 的 buffer (缓冲区)、菜单文本、消息文本等。用户手册上建议只在 .vimrc 中改变它的值,事实上似乎也只有在 .vimrc 中改变它的值才有意义。 2、fileencoding: Vim 中当前编辑的文件的字符编码方式,Vim 保存文件时也会将文件保存为这种字符编码方式 (不管是否新文件都如此)。 3、fileencodings: Vim 启动时会按照它所列出的字符编码方式逐一探测即将打开的文件的字符编码方式,并且将 fileencod阅读全文>

发表于 @ 2009年09月22日 09:59:00 | 评论( loading... ) | 编辑| 举报| 收藏

2009年09月03日

翻译 开飞机

在若干年一度的“国际C语言混乱代码”(-_-!)竞赛中看到好多好玩的东西,居然还有人写了“一架飞机”,哈哈,有图为证阅读全文>

发表于 @ 2009年09月03日 10:24:00 | 评论( loading... ) | 编辑| 举报| 收藏

2009年08月31日

原创 UNIX缓冲机制

有一次学生写了一个HELLO WORLD代码,出不来结果,代码如下:#include intmain(int argc, char **argv){ printf("hello world!"); _Exit(0);}注意到,在代码中printf语句打印的字符串最后没有带换行符,而且最后调用了_Exit函数,这导致了在终端屏幕上显示不出来字符串"hello world!"。首先介绍一下UNIX里面关于标准IO的几种缓冲机制:1、全缓冲。全缓冲指的是系统在填满标准IO缓冲区之后才进行实际的IO操作;注意,对于驻留在磁盘上的文件来说通常是由标准IO库实施全缓冲。2、行缓冲。在这种情况下,标准IO在输入和输出中遇到换行符时执行IO操作;注意,当流涉及终端的时候,通常使用的是行缓冲。3、无缓冲。无缓冲指的是标准IO库不对字符进行缓冲存储;注意,标准出错流stderr通常是无缓冲的。其次介绍一下几个退出函数:1、exit()。调用exit函数之后,它首先会执行一系列的清理处阅读全文>

发表于 @ 2009年08月31日 20:21:00 | 评论( loading... ) | 编辑| 举报| 收藏

2009年08月28日

原创 解剖关键字typedef

带你解剖typedef之前,让我们先来看看POSIX.1中对信号处理函数signal的原型说明:void (*signal(int sig, void (*func)(int)))(int);对于不熟悉C语言声明的朋友,看到这样的函数原型估计离崩溃不远了,我们再来看看ANSI C中对此函数原型是作如何解释的:typedef void (*sighandler_t)(int);sighandler_t signal(int signum, sighandler_t handler);此处由于加了typedef自定义了一个新类型sighandler_t,所以第二行的函数原型看起来顺眼多了,形式跟int func(char c, int i)无异,但是如果看不懂typedef语句,这两句话仍然是噩梦。要理解typedef,只要记住一句话就差不多了,那就是:typedef在语句中所起的作用只不过是把语句原先定义变量的功能变成了定义类型的功能而已。我们只消看几个例子立即明白。例如语句 t阅读全文>

发表于 @ 2009年08月28日 23:09:00 | 评论( loading... ) | 编辑| 举报| 收藏

2009年08月27日

原创 UNIX文件权限探讨

关于unix系统中涉及权限的问题探讨,跟大家分享下首先要明白一个关键点----权限分为两种:第一种是用ls -l命令显示出来的文件性质的权限 ,比如 -rw-r--r-- foo foo file,这里的读写权限是该文件本身的性质,表示该文件本身属于foo用户,属于foo组。第二种是进程性质的权限 ,比如 -rwsr--r-- bar bar file,这个file文件本身属于bar用户,但是由于设置了用户设置ID,导致如果以foo用户来执行该文件的话,进程的有效用户ID就不是foo而是bar,该进程以bar的权限运行。一个静态程序文件在磁盘中存在时,它只有文件性质的权限,即用户ID和用户组ID;当该静态程序被加载进内存运行时,它就不仅要考虑之前的两个所有者 ID,而且还应考虑执行它的用户的ID(该文件的所有者和当前该文件的执行者当然可以不同),那么内核究竟要用哪些ID作为该进程运行时的有效ID呢?阅读全文>

发表于 @ 2009年08月27日 16:10:00 | 评论( loading... ) | 编辑| 举报| 收藏

Copyright © seton040
Powered by CSDN Blog