存档

作者存档

【转载】不随便牵手,更不随便放手

2010年8月12日 6 条评论

不随便牵手,更不随便放手
你发觉了吗?爱的感觉,总是在一开始的时候甜蜜,总觉得多了一个人陪。多了一个人帮你分担,你终于不在孤寂单了,因为至少有一个人想着你、恋着你,不论做什么事情,只要能在一起,就是好的。

但是慢慢的,随着认识的加深,你开始发现了对方的缺点,于是问题一个接一个出现,你开始烦、累、甚至想要逃避,有人说爱情就像捡石头,总想捡到一个适合自己的,但是你又如何知道什么时候能捡到呢?她适合你,那你又适合他吗?

其实,爱情应该像磨石子儿,或许刚捡到的时候,你不是那么满意,但是请记住,人是有弹性的,很多事情是可以改变的,只要你有心,有勇气,与其到处去捡未知的石头,还不如将自己已经拥有的石头磨亮磨光。你开始磨了吗?很多人以为,是感情淡了,人才会变得懒惰,其实人是先被懒惰征服,感情才慢慢变淡的。

在某个聚餐的场合,有人提议多吃点虾对身体好,这时候有个中年男人忽然说:“十年前当我老婆还是我女朋友的时候,她说要吃十只虾,我就剥20只给她!现在如果她要我帮他剥虾壳,简直是开玩笑!我连帮她夹菜都没兴趣了,还剥虾壳呢。”

难怪越来越多的人只想谈一次恋爱,却迟迟不肯走入婚姻。因为婚姻容易让人变得懒惰。

如果每个人都懒得讲话,懒得倾听,懒得制造惊喜。懒得温柔体贴,那么夫妻或是情人之间,又怎会不渐行渐远渐无声呢?所以请记住:有活力的爱情,是需要适度殷勤来灌溉的,谈恋爱更是不可以偷懒的。

有一对情侣,相约下班后去用餐、逛街,可是女孩因为公司会议延误了,当她冒雨赶到的时候已经迟到了30多分钟,她男朋友很不高兴的说:“你每次都这样,现在哦什么心情也没了,我以后再不会等你了!”刹那间女孩的心堤崩溃了,她在想:或许,他们再也没有未来了。

同样,在同一个地点,另一对情侣也面临同样的困境,女孩赶到的时候也迟到了半个小时,她的男朋友说:“我想你一定忙坏了吧?”接着他为女孩拭去脸上的雨水,此刻,女孩流泪了。但是流过她脸颊的泪却是温馨幸福的。

你体会到了吗?其实爱恨往往只在我们一念之间!爱不仅要懂得宽容更要及时,很多事可能只在于你心境的转变罢了。如果有个人爱上你,而你也觉得他不错,那并不代表你会选择他。

我们总说:“我要找一个很爱很爱的人,才会谈恋爱。”但是当对方问你,怎样才算很爱很爱的时候,你却无法回答他,因为你自己也不知道。

没错,我们总是以为,我们会找到一个自己很爱很爱的人,可是后来,当我们猛然回首,才发觉自己曾经多么天真。假如从来没有开始,你怎么知道自己会不会很爱很爱那个人呢?其实,很爱很爱的感觉,是要在一起经历了许多事情以后才会发现的。每个人都希望找到自己心目中百分之百的伴侣,但是你有没有想过,在你身边早有人对你默默付出了,只是你没发觉而已。

所以,还是仔细看看身边的人吧,他或许已经等你很久了。当你爱一个人的时候,爱到八分绝对刚刚好。所有的期待和希望都只有七八分,剩下两三分用来爱自己。如果你还继续爱得更多,很可能给对方造成沉重的压力,让彼此喘不过气来,完全丧失了爱情的乐趣。

所以请记住;喝酒不要超过六分醉,吃饭不要超过七分饱。如果你正在为爱迷茫,下面这段话或许可以给你些启示:爱一个人要了解也要开解;要道歉也要道谢;要体贴也要体谅;是接受而不是忍受;是支持而不是支配;是慰问而不是质问;是倾诉而不是控诉;是难忘而不是遗忘;是彼此交流而不是凡事交代;是为对方默默祈求而不是问对方诸多要求。可以浪漫但不是浪费,不要随便牵手,更不要随便放手。

分类: 生活 标签:

poj2503 Babelfish–hash解决实现快速匹配

2010年8月8日 1 条评论
http://acm.pku.edu.cn/JudgeOnline/problem?id=2503
其实这个题目,使用qsort+二分查找应该是比较简单可以实现的,使用trie应该也可以,但是不晓得速度怎么样,另外不晓得有没有人直接用STL中的map做了没有,呵呵,那个一定很水。
我使用hash来做的目的是想熟悉一下指针以及hash的操作。这个题目我想到了使用ELFHash,并且使用拉链法处理冲突问题。
但是在POJ上运行的时间并不是很理想,后来我查看了一下,才晓得。为了节省空间,每个单词,每次去malloc空间,其实这样不太好,每次都去浪费时间去malloc,既然题目中明显说出仅有10000条数据,且每个单词不超过10个字节,那么完全可以用数组固定大小,或者用malloc一次分配完成,这样不会每次都浪费时间。不过,我还是觉得不浪费空间适应性更强,更适合工程上的项目。
所以就不再改了,代码贴出来讨论,呵呵
另外,其中,在调试的时候,一直WA,调试好久,在我电脑上运行结果正常,而到POJ上确实WA,郁闷至极的时候突然发现:查不到单词输出 “eh” 而我输出的是”en”,真是悲剧,en 和 eh差别那么小,呵呵。低级错误!
Babelfish
Time Limit: 3000MS Memory Limit: 65536K
Total Submissions: 15393 Accepted: 6765
Description
You have just moved from Waterloo to a big city. The people here speak an incomprehensible dialect of a foreign language. Fortunately, you have a dictionary to help you understand them.
Input
Input consists of up to 100,000 dictionary entries, followed by a blank line, followed by a message of up to 100,000 words. Each dictionary entry is a line containing an English word, followed by a space and a foreign language word. No foreign word appears more than once in the dictionary. The message is a sequence of words in the foreign language, one word on each line. Each word in the input is a sequence of at most 10 lowercase letters.
Output
Output is the message translated to English, one word per line. Foreign words not in the dictionary should be translated as “eh”.
Sample Input
dog ogday
cat atcay
pig igpay
froot ootfray
loops oopslay
atcay
ittenkay
oopslay
Sample Output
cat
eh
loops

/*
author:yqshare
*/
#include<stdio.h>
#include<string.h>
#include <stdlib.h>
#define M 30000

struct word_entry{
       char * word;
       char * foreign_word;
       struct word_entry * next;
       };
typedef struct word_entry WORD_ENTRY;
ELFHash(char * str)
{
    unsigned int hash = 0;
	unsigned int x    = 0;
	while (*str)
	{
		hash = (hash << 4) + (*str++);
		if ((x = hash & 0xF0000000L) != 0)
		{
			hash ^= (x >> 24);
			hash &= ~x;
		}
	}
	return (hash & 0x7FFFFFFF);

}
WORD_ENTRY  * alloc_entry(char * word , char * foreign)
{
   WORD_ENTRY  * word_entry =NULL;
   word_entry = (WORD_ENTRY *)malloc(sizeof(WORD_ENTRY));
   word_entry->foreign_word = ( char * )malloc(strlen(foreign)+1);
   strcpy(word_entry->foreign_word,foreign);
   word_entry->word = ( char * )malloc(strlen(word)+1);
   strcpy(word_entry->word,word);
   word_entry->next = NULL;
   return word_entry ;
}
int main()
{
    char word[11],foreign_word[11],buff[50];
    int hash_size=0,i;
    WORD_ENTRY  ** hash_base = (WORD_ENTRY *)calloc(M,sizeof(WORD_ENTRY *));
    WORD_ENTRY  * hash_tmp=NULL, * word_tmp = NULL;
    memset(word,0,10);
    memset(foreign_word,0,10);
    while(gets(buff) && strcmp (buff,"")!= 0)
    {

      for (i=0;buff[i]!=' ';i++)
         word[i]=buff[i];
       word[i++]='\0';
       strcpy(foreign_word,buff+i);
       hash_size = ELFHash(foreign_word)%M;
       hash_tmp = *(hash_base+hash_size);
       word_tmp = hash_tmp;
       hash_tmp = alloc_entry(word,foreign_word);
       hash_tmp->next = word_tmp;
       *(hash_base+hash_size) = hash_tmp;
       memset(word,0,10);
       memset(foreign_word,0,10);
       memset(buff,0,50);
    }

   while(gets(foreign_word)&& strcmp (foreign_word,"")!= 0)
    {
       hash_size = ELFHash(foreign_word)%M;
       hash_tmp = *(hash_base+hash_size);
	   while(hash_tmp)
	   {
		   if(strcmp(hash_tmp->foreign_word,foreign_word)==0)
		   break;
		   hash_tmp = hash_tmp->next;
	   }
	   if(hash_tmp != NULL)
		printf("%s\n",hash_tmp->word);
	   else
		printf("eh\n");
    }
}
分类: 算法讨论, 编程 标签:

由腾讯笔试题想到的–ELFHash分析

2010年8月3日 4 条评论
在一个cache系统中,需要实现一个域名白名单,域名为下列数据:
www.qq.com、www.baidu.com、sohu.com 等
该白名单需要在程序启动时加载一次,主要执行查询操作。请设计一个数据结构和相应的初始化查询函数,使得检索尽可能的快。(不能使用stl::map,等等key-value刑类库)。
我们可以看到,该题目提出了字符串的快速查找,并且只加载一次。使用Hash比较好。
我们可能首先就是想到使用 C++ 中的 MAP ,题目中给出了不允许使用MAP,那么肯定第二选择就是使用Berkeley DB (DB)这种的文件数据库了,但是题目中明显提出不允许使用key-value类型库。
我们思考Berkeley DB (DB)的原理可以晓得,这个就是一个Hash的过程,map其实也是hash的思想。
自己设计一个hash系统咯。冲突处理…
字符串hash可能就想到使用ELFhash算法,主要分析下ELFHash算法。
ELFhash函数在UNIX系统V 版本4中的“可执行链接格式”( Executable and Linking Format,即ELF )中会用到,ELF文件格式用于存储可执行文件与目标文件。ELFhash函数是对字符串的散列。它对于长字符串和短字符串都很有效,字符串中每个字符都有同样的作用,它巧妙地对字符的ASCII编码值进行计算,ELFhash函数对于能够比较均匀地把字符串分布在散列表中。
这些函数使用位运算使得每一个字符都对最后的函数值产生影响。

// ELF Hash Function

unsigned int ELFHash(char *str)

{

 unsigned int hash = 0;

 unsigned int x = 0;

 

 while (*str)

 {

 hash = (hash << 4) + (*str++);//hash左移4位,当前字符ASCII存入hash低四位。 

if ((x = hash & 0xF0000000L) != 0)

{//如果最高的四位不为0,则说明字符多余7个,如果不处理,再加第九个字符时,第一个字符会被移出,因此要有如下处理。

//该处理,如果对于字符串(a-z 或者A-Z)就会仅仅影响5-8位,否则会影响5-31位,因为C语言使用的算数移位

hash ^= (x >> 24);

//清空28-31位。

hash &= ~x;

}

}

//返回一个符号位为0的数,即丢弃最高位,以免函数外产生影响。(我们可以考虑,如果只有字符,符号位不可能为负)

return (hash & 0x7FFFFFFF);

}

 


 

分类: Linux专区, 算法讨论 标签:

有关“数独”游戏…

2010年7月13日 4 条评论

很有幸,通过了华为编程大赛的初赛,进入决赛。
决赛时间是7.9号 8:00–15:00,在重庆大学。这次大赛的题目,是关于sudoku的,关于判局、求解、生成游戏。

本次比赛的题目是数独游戏相关的,我就不说了吧,百度一下,网上一大把!

在整整一天的比赛时间里,我花了一个上午的时间写一个MFC的界面,好痛苦。比赛环境,连个MSDN都没得,而且,最近这一年都一直在linux下做,很久没有MFC了。不过还好的是,把界面给做出来了。
中午和下午想了两个算法。

1)判局,也就是要判断用户,填入的数据是不是合法的,首先要判断每一行、每一列、每个九宫格,是不是仅有1-9的全部数字组成。判断这个我使用了位图算法,即,在一个int中的底9位用来匹配行中出现的数字,如果该行是由1,2,3,4,5,6,7,8,9,组成,那么该int的第九位便全部为1,否则会有为0的位,因此该bitmap肯定小于511,这样通过一次遍历就实现了一个匹配。用同样的方法遍历列,以及九宫格。只有个O(N)就可以解决这个问题了,呵呵

2)求解
这个方法应该的比较多的,一般都是DFS来求解。

1.按下标blank由小到大的顺序逐个获取空白位置;
2.对空白位置blank试图填数,填数的规律为从l-9依次由小到大选择(有序);
3.若找到一个可以填人的数据(调用check(blank),检查当前字符所在的行、列、九宫格是否满足规定,若不满足,即找不到合适数据填人该位置),将数据填人sudoku[blank],并将blank入栈push;否则转5.;
4.获取下一个空白位置,若有空白位置则转2.,否则转6.;
5.进行回溯,即pop得到上一次填数的位置sp,重新对该位置试图填数,为了递推的高效性,此时可以仅从当前sp存放的数字大l开始试图填数,转(3);
6.填数结束。

注:当然还有很多其他的方法,这个是应该是比较想的,呵呵

3)生成游戏
我当时想到的就是用“挖洞”。即生成一个数独全局,然后随机挖去一部分数据即产生有解的数独布局。
用的就是编程之美的上的思想:产生一个不会重复的“九宫格”,然后对其他的九宫格,用行变换的思想去填充。这个比较简单。一下就把代码写出来了…

最后,感觉华为的这个编程大赛还可以,但是有些不健全。比如:可以带书进去,但是又没有集体通知,有的同学带了、有的同学没有带,这样就有些不公平,还有就是,写算法就不要让大家做MFC吗,做MFC就不能算是真正意义上的编程大赛咯!我就是浪费了很多时间到MFC上,估计其他同学也和我差不多,呵呵
这次回来,我突然有买一本《算法导论》回来看的冲动了,虽然自己平常也很注重学习算法,但是,总感觉知识储备不够…

分类: 算法讨论, 编程 标签:

固态硬盘与普通硬盘比较,有哪些优缺点

2010年6月27日 2 条评论
非常之郁闷,今天去教室看书,结果,本科生考试。杯具了。转了一圈没找到一个教室看书!愤然回来了。
翻了翻网易的笔试题。看到有谈到固态硬盘和传统硬盘。以前只有简单了解,没有仔细分析。于是…百度、谷歌…
优点:
1. 启动快,没有电机加速旋转的过程。
2. 不用磁头,快速随机读取,读延迟极小。根据相关测试:两台电脑在同样配置的电脑下,搭载固态硬盘的笔记本从开机到出现桌面一共只用了18秒,而搭载传统硬盘的笔记本总共用了31秒,两者几乎有将近一半的差距。
3. 相对固定的读取时间。由于寻址时间与数据存储位置无关,因此磁盘碎片不会影响读取时间。
4. 基于DRAM的固态硬盘写入速度极快。
5. 无噪音。因为没有机械马达和风扇,工作时噪音值为0分贝。某些高端或大容量产品装有风扇,因此仍会产生噪音。
6. 低容量的基于闪存的固态硬盘在工作状态下能耗和发热量较低,但高端或大容量产品能耗会较高。
7. 内部不存在任何机械活动部件,不会发生机械故障,也不怕碰撞、冲击、振动。这样即使在高速移动甚至伴随翻转倾斜的情况下也不会影响到正常使用,而且在笔记本电脑发生意外掉落或与硬物碰撞时能够将数据丢失的可能性降到最小。
8. 工作温度范围更大。典型的硬盘驱动器只能在5到55摄氏度范围内工作。而大多数固态硬盘可在-10~70摄氏度工作,一些工业级的固态硬盘还可在-40~85摄氏度,甚至更大的温度范围下工作。
9. 低容量的固态硬盘比同容量硬盘体积小、重量轻。但这一优势随容量增大而逐渐减弱。直至256GB,固态硬盘仍比相同容量的普通硬盘轻。
缺点:
1. 成本高。每单位容量价格是传统硬盘的5~10倍(基于闪存),甚至200~300倍(基于DRAM)。
2. 容量低。目前固态硬盘最大容量远低于传统硬盘。固态硬盘的容量仍在迅速增长,据称IBM已测试过4TB的固态硬盘。
3. 由于不像传统硬盘那样屏蔽于法拉第笼中,固态硬盘更易受到某些外界因素的不良影响。如断电(基于DRAM的固态硬盘尤甚)、磁场干扰、静电等。
4. 写入寿命有限(基于闪存)。一般闪存写入寿命为1万到10万次,特制的可达100万到500万次,然而整台计算机寿命期内文件系统的某些部分(如文件分配表)的写入次数仍将超过这一极限。特制的文件系统或者固件可以分担写入的位置,使固态硬盘的整体寿命达到20年以上。
5. 基于闪存的固态硬盘在写入时比传统硬盘慢很多,也更易受到写入碎片的影响。
6. 数据损坏后难以的恢复。传统的磁盘或者磁带存储方式,如果硬件发生损坏,通过目前的数据恢复技术也许还能挽救一部分数据。但如果固态硬盘发生损坏,几乎不可能通过目前的数据恢复技术在失效(尤其是基于DRAM的)、破碎或者被击穿的芯片中找回数据。
7. 根据实际测试,使用固态硬盘的笔记本电脑在空闲或低负荷运行下,电池航程短于使用7200RPM的2.5英寸传统硬盘。
8. 基于DRAM的固态硬盘在任何时候的能耗都高于传统硬盘,尤其是关闭时仍需供电,否则数据丢失。
9. 据用户反映,使用低廉的MLC的固态硬盘在Windows操作系统下运行比传统硬盘慢。这是由于Windows操作系统的文件系统机制不适于固态硬盘。在Linux下无此问题。
分类: 电子知识 标签:

说一下网络字节序

2010年6月24日 2 条评论
统计每个网段的IP个数到ipmap的映射表中,协议栈中的IP是网络字节序的,有的转过了,但部分还没有转换。找来找去,找迷糊了都…
说到网络字节序,可能不免要说道:主机字节序
不同的CPU有不同的字节序类型 这些字节序是指整数在内存中保存的顺序 这个叫做主机序。
有两种字节序 :1. Little endian:将低序字节存储在起始地址 2. Big endian:将高序字节存储在起始地址
LE little-endian
比较人的思维的字节序,地址低位存储值的低位 ,地址高位存储值的高位
BE big-endian
最直观的字节序,地址低位存储值的高位,地址高位存储值的低位
为什么说直观,不要考虑对应关系,只需要把内存地址从左到右按照由低到高的顺序写出 ,把值按照通常的高位到低位的顺序写出,两者对照,一个字节一个字节的填充进去。
例子:在内存中双字0×01020304(DWORD)的存储方式
内存地址
0X0000 0X0001 0X0002 0X0003
LE  04                     03              02             01
BE  01                     02              03               04
例子:如果我们将0x1234abcd写入到以0×0000开始的内存中,则结果为
big-endian   little-endian
0×0000   0×12       0xcd
0×0001   0×23       0xab
0×0002   0xab       0×34
0×0003   0xcd       0×12
x86系列CPU都是little-endian的字节序.
我们明白了主机字节序,就好说网络字节序了:
网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian排序方式。
为了进行转换 bsd socket提供了转换的函数 有下面四个
htons 把unsigned short类型从主机序转换到网络序
htonl 把unsigned long类型从主机序转换到网络序
ntohs 把unsigned short类型从网络序转换到主机序
ntohl 把unsigned long类型从网络序转换到主机序
在使用little endian的系统中 这些函数会把字节序进行转换
在使用big endian类型的系统中 这些函数会定义成空宏
同样 在网络程序开发时 或是跨平台开发时 也应该注意保证只用一种字节序 不然两方的解释不一样就会产生bug.

另外:1、网络与主机字节转换函数:htons ntohs htonl ntohl (s 就是short l是long h是host n是network)

分类: 编程 标签:

[收藏]简单的了解一堂 应该听的课。(曾被疯狂转载)

2010年6月18日 1 条评论

下面的内容转自:

海bar的博客

一个字一个字的敲上、一个字一个字的品读。
1、什么是孤独?孤独是从人群中偷来的享受,她高傲、优美,完全是精神的自由。孤独,是需要我们有独处的时间,做到“如我所是”,完全不需要装扮、做作,不需要戴着帽子抽根烟来装深沉。
2、什么是寂寞?寂寞是一种病,是一种精神的饥饿。既然是病,就需要治疗。寂寞的人如何找到治疗的方法?方法就是人群,寂寞的人总是需要他人的陪伴。
3、人群的治疗分为两种。一种是利益需要建造人脉,这仅仅是互为功利(确实有用,不过不会有真正的朋友);还有一种是寂寞者的相互取暖,这是廉价的交往。
4、狂欢是一群人的寂寞,孤独是一个人的狂欢。
5、孤独不求外物,反求诸己(也就是淡定)
6、寂寞是无可慰藉的牢笼。因为寂寞的人无所适从,焦躁不安。他们的思想从贫瘠而荒芜,产生自我厌弃感。
7、他比烟花更寂寞。烟花绽放于无形,消失于乌有,当中是有短暂的释放,伴随而来的是无边的寂寞。
8、孤独不是故作姿态,孤独是一种心境。沉默未必是孤独,孤独没有任何形式,那是孤独者精神上的自我流浪。装出来的叫浮躁,那是一种虚荣心,是为了招揽目光。
9、真正的朋友是二人世界。我们很安静,但是不冷清。多一个人就难免会有不能讨论的话题,这就是一种分心,从一种不设防变成了一种社交。三个人的世界太拥挤。
10、很多东西放到时间里去看就能看清楚。要么越走越远,要么越走越近。
11、如果你把朋友当做了男女朋友的备用,那你也就侮辱了友情和爱情。
12、跟朋友在一起也是一种孤独。但是这种孤独更美好,会比自己一个人的时候还自如。因为真正的朋友全然不设防。
13、朋友是奢侈品,奢侈的东西都是不实用的东西。这种东西拥有了就该满足。因为,它除了友情,什么也不能给你。
14、朋友不是附庸,不会只有赞同、妥协。朋友在现实中需要如切如磋,如琢如磨。
15、有些所谓的倾诉、出气筒,都是语言暴力。不该以“这是对朋友的信任”为借口。这是对朋友的滥用。朋友不该承担这种宣泄。soul mate是灵魂上的一体,他不该承担我的琐事。
16、朋友应该是无用的(此处的“用”指利用)。和他在一起的时候就会感到自由自在。执手相看无语,却心事了然。
17、真正的朋友之间不是尝联系也没有关系,隔上两三年,电话那头的人好像从来没有离开过。需要经常联系才能维护的所谓“友情”是不牢靠的,因为一旦不联系,他们会断。(从来也不会想起,永远也不会忘记)
18、两个戴着面具的人就不用做朋友了。
19、人和人之间要保持距离,距离产生美。靠得太近,我们就会看见对方越多的缺点。两块石头投入水里,太近水波就越会相互干扰。
20、人对最亲近的人最残忍,因为太接近,往往看不到对方点点滴滴的优点。
21、当我看不见所有人的时候,我对他们产生了一种精神上的凝望,这种凝望叫做思念。
22、周围的人太多,于是我们对人群淡漠。我们很多人喜欢旅行,是为什么?因为我们是希望找个没有人的地方去自我放逐一下。我们为什么要避开别人?因为孤独者即有趣者。孤独是自我寻乐的消遣方式。
23、人是有“贱”性的。

看过以后总能触动心里的一部分!

分类: 生活 标签:

10的反,是多少?int型内存存放方式的一个小总结

2010年6月17日 4 条评论
昨天自习室,献哥读这本《c缺陷与陷阱》,看到激情之处,和我讨论 ~10 为多少?
想了一下,32位系统下是…结果算了半天没有一个确切的结果,我才晓得是这一块本科2年纪学的东西,都忘记差不多了。
回来翻翻书,百度、google一把,终于整明白了。
做个记录:
在计算机中,int数据是用补码形式保存的,用补码表示有两个好处:
(1)使符号位能与有效值部分一起参加运算,从而简化运算规则.
(2)使减法运算转换为加法运算,进一步简化计算机中运算器的线路设计 所有这些转换都是在计算机的最底层进行的。
关于补码的详细介绍,我们可以看百科把(点我学习补码)
因此,我们可以计算出~10的过程:
10 = 00000000 00000000 00000000 00001010 (bin)
因此对10取反即为:
~10 = 11111111 11111111 11111111 11110101 (bin)
我们晓得,计算机中用补码表示,因此对 该补码求反,然后 + 1 就得到原址,当然啦还有符号。呵呵
11111111 11111111 11111111 11110101 (bin)
计算即为
-11 = – ( 00000000 00000000 00000000 00001011 (bin) )
这个应该是比较基础的了,都是以前的学的知识,看来还是基础不够扎实啊!呵呵
突然又想起了,前天面中兴的时候那位哥哥问的一个问题:int 范围 ,这个当然晓得: 2^31到 2^31-1
但是如果,深究一下,为什么呢?解释一下?
可能又牵扯到了内存中为的存储方法了,int 在内存中存储的是反码,第一位为符号位。具体可参考1.
我比较懒。引用论坛里一大牛写的吧:
考虑8位情况00—-ff(hex),也就是00000000(10进制0)—-11111111(bin)<10进制255>
它一共能直接表示的数值个数是2^8=256个,非负数:0-127(ff hex)<128个>
负数-1~-128<128个>
于是8位的范围就是-128~127 (-128,-127….-1,0,1,2,….127 <total 256>
注意01111111,这是8位中最大正数,0是符号位,那么显然能表示的最大正数是7F(hex)=127
还有一个0,剩下的就是负数,256-1-127=128个,就是-1~-128
为什么有 -128呢?
我们可以考虑,10000000(bin),也就是说 -0 的情况,在内存中反码表示。我们可以计算,“按位取反,末位加一”的方法,即为 10000000(bin) = 128 , 加上符号位。即为 -128 。
同理,n位整型范围是-2^n~~~2^n-1
参考 :
补码:
反码:
关于2的补码:
分类: 编程 标签:

[收藏]内核中 do{}while(0) 作用

2010年6月16日 没有评论

看师兄的面经,看到了 do{}while(0),一直在想:while(0)?不会运行的吗!怎么会有这样代码?

百度之,恍然大悟!收藏下来,以供学习!

在Linux内核中,经常会看到do{}while(0)这样的语句,许多人开始都会疑惑,认为do{}while(0)毫无意义,因为他只会执行一次,加不加do{}while(0)效果是完全一样的,其实do{}while(0)主要用于宏定义中。
这里用一个简单点的宏来演示:

#define SAFE_FREE(p) do { free(p);= NULL; } while(0)

假设这里去掉do…while(0),即定义SAFE_FREE为:

#define SAFE_FREE(p) free(p);= NULL;

那么以下代码:

if (NULL != p)
SAFE_FREE(p);
else
...

会被展开为:

if (NULL != p)
free(p);= NULL;
else
...

展开的代码中存在两个问题:

  • if 分支后面有两个语句,导致else分支没有对应的if,编译失败;
  • 假设没有else分支,则SAFE_FREE中的第二个语句无论if测试是否通过都会执行。

将SAFE_FREE的定义加上{}就可以解决上诉问题了,即:

#define SAFE_FREE(p) { free(p);= NULL; }

这样,代码:

if (NULL != p)
SAFE_FREE(p);
else
...

会被展开为:

if (NULL != p)
{ free(p);= NULL; }
else
...

但是,在C程序中,每个语句后面加分号是一种约定俗成的习惯,那么,如下代码:

if (NULL != p)
SAFE_FREE(p);
else
...

将为扩展为:

if (NULL != p)
{ free(p);= NULL; };
else
...

这样,else分支就有没有对应的if了,编译将无法通过。假设用了do{}while(0),情况就不一样了,同样的代码会被扩展为:

if (NULL != p)
do { free(p);= NULL; } while(0);
else
...

不会再出现编译问题。do{}while(0)的使用完全是为了保证宏定义的使用者能无编译出错的使用宏,它不对其使用者做任何假设。

看到上面的解释,估计都很清楚了,呵呵,这个用法原来如此只经典….

分类: 生活 标签:

手动实现的C语言string.h 头文件的字符串函数

2010年5月31日 2 条评论
研究C语言,首先要明白其库函数…
#include<stdio.h>
char* strcpy(char* dest,const char* src);  //字符串拷贝
char* strcat(char* dest,const char* src);  //字符串连接,返回dest字符串
char* strncat(char* dest, const char* src, int size);//把src前n个字符串连接到dest,返回dest字符串
int   strcmp(const char* src1,const char* src2);  //字符串比较  返回值: 1:> 0:= -1<
int   strncmp(const char* src,const char* dst,int size);  //dst前n个字符和src比较返回值: 1:>  0:=  -1<
int   strlen(const char* src);  //返回字符串长度
char* strchr(const char* src, int ch); //字符ch在字符串第一次出现的位置,返回出现字符ch位置开始到字符串结束位置的指针
char* strrchr(const char* src, int ch); //字符ch在字符串最后一次出现的位置,返回出现字符ch位置开始到字符串结束位置的指针
char* strstr(const char* src, const char* sub); //字符串sub在字符串第一次出现的位置,返回出现字符串sub位置开始到字符串结束位置的指针
//memery copy operate function==================//
void* memcpy(void* dest,const void* src,unsigned int size); //把src的内容拷到dest内存里去,并返回dest指向的内存地址
void* memset(void* dst, int ch, unsigned int size); //把dst内存中的size大小用使用ch来初始化,并返回dest指向的内存地址
int   memcmp(const void* src1, const void* src2, unsigned int size); //比较内存中src1与src2中的前size 个字符是否相等,1:>  0:=  -1<  (see strncmp(const char*,const char*,unsigned int))
void* memchr(const void* dst, int ch, unsigned int size); //在内存中的某一范围内,查找特定的字符ch,并返回指向ch的指针
void* memmove(void* dst, const void* src, unsigned int size); //memmove()与memcpy()一样都是用来拷贝src所指的内存内容前n个字节到dest所指的地址上。不同的是,当src和dest所指的内存区域重叠时,memmove()仍然可以正确的处理,不过执行效率上会比使用memcpy()略慢些.返回指向dest的指针
//memery copy operate function==================//

int main()
{
// printf("the string len=%d\n",strlen("helloWorld")); 

// char dest[20];
// printf("the string is=%s\n",strcpy(dest,"helloWorld"));
// char dest[30]="hello--";
// printf("after connect sub string is=%s\n",strcat(dest,"world"));
// char dest[30]="hello--";
// printf("after connect sub string is=%s\n",strncat(dest,"world_programe",4));

// printf("the string compare result is=%d\n",strcmp("hello","aello"));
// printf("the string compare result is=%d\n",strncmp("hello","hello_good",5));
// printf("the char appear position is=%s\n",strchr("hello-r-es-d",'-'));
// printf("the char appear position is=%s\n",strrchr("hel*lo-r*-e*s-d",'*'));

// printf("the sub string is=%s\n",strstr("hello_world","lo"));
 char dest[20];
// printf("the sub string is=%s\n",memcpy(dest,"hello..111",sizeof(dest)));
 printf("the sub string is=%s\n",memset(dest,'0',sizeof(dest)));

 return 0;
}
//=========================================================//
int  strlen(const char* src)
{
 const char* p=src;
 while(*p++!='\0');
 return p-src-1;
}
//=========================================================//
char* strcpy(char* dest,const char* src)
{
 if(dest&&src)
 {
  int i=0;
  while((*(dest+i)=*(src+i))!='\0') i++;
  *(dest+i)='\0';
 // return dest;
 }
 return dest;
}
//=========================================================//
char* strcat(char* dest,const char* src)
{
 if(dest&&src)
 {
  int len=strlen(dest);
 // printf("len=%d\n",len);
  int i=0;
  while((*(dest+len+i)=*(src+i))!='\0') i++;
  *(dest+len+i)='\0';
 }
 return dest;
}
//=========================================================//
char* strncat(char* dest, const char* src, int size)
{
 if(dest&&src)
 {
  int len=strlen(dest);
  int i=0;
  while((i<size)&&((*(dest+len+i)=*(src+i))!='\0')) i++;
 }
 return dest;
}
//=========================================================//
int strcmp(const char* src1,const char* src2)
{
 int equal;
 int i=0;
 while(!(equal=*(unsigned char*)(src1+i)-*(unsigned char*)(src2+i))&&(*(src1+i))&&(*(src2+i)))
  i++;
 if(equal<0) return -1;
 else if(equal>0) return 1;
 else return 0;
}
//=================比较两个字符串前size 个字符串是否相等==========================//
int strncmp(const char* src1,const char* src2,int size)
{
 int equal;
 int i=0;
 while((i<size)&&!(equal=*(unsigned char*)(src1+i)-*(unsigned char*)(src2+i))&&(*(src1+i))&&(*(src2+i)))
  i++;
 if(equal<0) return -1;
 else if(equal>0) return 1;
 else return 0;
}
//=========================================================//
char* strchr(const char* src, int ch)
{
 int i=0;
 while(*(src+i)&&(*(src+i)!=ch)) i++;
 return (char*)(src+i);
}
//=========================================================//
char* strrchr(const char* src, int ch)
{
 int len=strlen(src);
 int i=0;
 while(i<len&&(*(src+len-i)!=ch)) i++;
 return (char*)(src+(len-i));
}
//=========================================================//
char* strstr(const char* src, const char* sub)
{
 if(src&&sub)
 {
  int subLen=strlen(sub);
  int srcLen=strlen(src);
  int nomatch=1;
  int fds=srcLen-subLen+1;
  int i=0;
  if(fds>0) //find counts in the string
   while((nomatch=strncmp(src+i,sub,subLen))&&fds--)//把当前src的指针往后推,直到找到与sub指针相同为止
    i++;
  if(nomatch)
   return 0;
  else
   return (char*)(src+i);
 }
 return 0;
}
//====================memory operate=====================================//
//====================memory operate=====================================//
void* memcpy(void* dest,const void* src,unsigned int size)
{
 if(dest&&src&&size>0)
 {
  int i=0;
     unsigned char* p=(unsigned char*)dest;
  unsigned char* q=(unsigned char*)src;
  while((i<size)&&(*(p+i)=*(q+i)))
   i++;
  return dest;
 }
 return 0;
}
//=========================================================//
void* memset(void* dst, int ch, unsigned int size)
{
 int i=0;
 unsigned char* p=(unsigned char*)dst;
 while((i<size)&&(*(p+i)=ch))
  i++;
 return dst;
}
//=========================================================//
int  memcmp(const void* src1, const void* src2, unsigned int size)
{
}
//=========================================================//
void* memchr(const void* dst, int ch, unsigned int size)
{
}
void* memmove(void* dst, const void* src, unsigned int count)
{
   void * ret = dst;
   if (dst <= src || (char *)dst >= ((char *)src + count))
   {
      while (count--)
      {
        *(char *)dst = *(char *)src;
            dst = (char *)dst + 1;
            src = (char *)src + 1;
        }
   }
   else
   {
      dst = (char *)dst + count - 1;
      src = (char *)src + count - 1;
      while (count--)
      {
        *(char *)dst = *(char *)src;
        dst = (char *)dst - 1;
        src = (char *)src - 1;
      }
   }
   return(ret);

}
分类: 编程 标签: