2010年4月27日

原来ABC还可以译作“原理,原则”来着,呵呵。。。偶然发现。

-----------------------------------------
这两天在读《设计模式精解》(其实该叫做“设计模式入门导读”),设计模式是从建筑学借来的一个词汇,是指“在某一个情景下的问题解决方案”。

在软件设计中,“四人团”总结提炼出23种模式(设计模式入门导读只列举了10种),分为结构型(Facade,Adapter,Bridge,Decorator等),行为型(Strategy,Observer等)和创建型 (Abstract Factory,Singleton等)三种大的类别。

这些模式总体上遵循一些原则:
1、封装变化。
2、优先使用对象组合,而不是优先使用继承

另外,关于对象的理解。
站在概念规格上,把对象看成是具有责任的实体;而非仅仅是在实现规格上,把它看作数据和方法的集合。 阅读全文
类别:设计模式 查看评论
文章来源:http://hi.baidu.com/janqii/blog/item/5182eb09ce178b32b1351d86.html
posted @ 2010-04-27 23:48 janqii 阅读(199) | 评论 (0)编辑 收藏
unsigned int SDBMHash(char *str)
{
unsigned int hash = 0;

while (*str)
{
// equivalent to: hash = 65599*hash + (*str++);
hash = (*str++) + (hash << 6) + (hash << 16) - hash;
}

return (hash & 0x7FFFFFFF);
}

// RS Hash Function
unsigned int RSHash(char *str)
{
unsigned int b = 378551;
unsigned int a = 63689;
unsigned int hash = 0;

while (*str)
{
hash = hash * a + (*str++);
a *= b;
}

return (hash & 0x7FFFFFFF);
}

// JS Hash Function
unsigned int JSHash(char *str)
{
unsigned int hash = 1315423911;

while (*str)
{
hash ^= ((hash << 5) + (*str++) + (hash >> 2));
}

return (hash & 0x7FFFFFFF);
}

// P. J. Weinberger Hash Function
unsigned int PJWHash(char *str)
{
unsigned int BitsInUnignedInt = (unsigned int)(sizeof(unsigned int) * 8);
unsigned int ThreeQuarters    = (unsigned int)((BitsInUnignedInt  * 3) / 4);
unsigned int OneEighth        = (unsigned int)(BitsInUnignedInt / 8);
unsigned int HighBits         = (unsigned int)(0xFFFFFFFF) << (BitsInUnignedInt - OneEighth);
unsigned int hash             = 0;
unsigned int test             = 0;

while (*str)
{
hash = (hash << OneEighth) + (*str++);
if ((test = hash & HighBits) != 0)
{
hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));
}
}

return (hash & 0x7FFFFFFF);
}

// ELF Hash Function
unsigned int 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);
}

// BKDR Hash Function
unsigned int BKDRHash(char *str)
{
unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
unsigned int hash = 0;

while (*str)
{
hash = hash * seed + (*str++);
}

return (hash & 0x7FFFFFFF);
}

// DJB Hash Function
unsigned int DJBHash(char *str)
{
unsigned int hash = 5381;

while (*str)
{
hash += (hash << 5) + (*str++);
}

return (hash & 0x7FFFFFFF);
}

// AP Hash Function
unsigned int APHash(char *str)
{
unsigned int hash = 0;
int i;

for (i=0; *str; i++)
{
if ((i & 1) == 0)
{
hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3));
}
else
{
hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5)));
}
}

return (hash & 0x7FFFFFFF);
} 阅读全文
类别:算法 查看评论
文章来源:http://hi.baidu.com/janqii/blog/item/9402270b263c24990a7b8229.html
posted @ 2010-04-27 23:48 janqii 阅读(334) | 评论 (0)编辑 收藏
如果使用概率算法的话,虽然速度较快,但会有一定的误差,而且这种误差还不稳定。
考虑使用确定算法,一般来讲,单词数量越多,第n个需要进行比较的单词操作时间越长。
今天在bbs上看到一种字典序的方法,每个单词与已经存在的单词的比较的时间花费只和自身的长度有关。也就是这样做得:
单词中的第i(0<i<n+1)位字母有26(对应26个英文字母)个预置位置,其(ASII-'a')值为其占有的位置,每个位置设置1个标志位标识该位是否是单词结束字母位置,定义每个对象都包含26个预留位置、1个标志符和指向下一个对象的指针。每个单词只需要按照顺序寻找第i位字母的对应位置,如果位置被占,直接寻找第i+1个字母的位置,如没有被占,就把这个位置new出来,直到最后一个字母,然后查看最后一位字母的位置的标识,如是被修改过,则是重复出现的单词,否则是新单词。  叙述的很乱,还是直接上代码吧。

@感谢LevinLin同学的贡献

----------------------------------------------------
 1 #include<iostream> 
 2 using namespace std; 
 3 
 4 const int kind=26
 5 int same=0
 6 
 7 struct Treenode 
 8 
 9 bool wordend;    //标识位,是否是最后一个字母
10 Treenode* next[kind];   //第i+1个字母的的位置
11 Treenode() 
12 
13 wordend=false
14 for(int i=0;i<kind;i++
15 next[i]=NULL; 
16 
17 }; 
18 
19 void insert(Treenode* root,char *word) 
20 
21 Treenode* location=root; 
22 int i=0,branch=0
23 
24 while(word[i]!='\0'
25 
26 branch=word[i]-'a'
27 if(!(location->next[branch]))     //判断第i位是否已经被占
28 
29 location->next[branch]=new Treenode(); 
30 
31 i++
32 location=location->next[branch]; 
33 
34 if (location->wordend==false
35 
36 location->wordend=true;   //修改标识
37 
38 else 
39 same++;  //标识被修改过,是重复出现的单词
40 
41 
42 int main() 
43 
44 int n,i; 
45 char word[11]; 
46 Treenode *root=NULL; 
47 root=new Treenode(); 
48 cin>>n; 
49 for (i=0;i<n;i++
50 
51 cin>>word; 
52 insert(root,word); 
53 
54 cout<<n-same; 
55 return 0
56 }
类别:算法 查看评论
文章来源:http://hi.baidu.com/janqii/blog/item/ec5ba7bcbf08b90619d81ff8.html
posted @ 2010-04-27 23:48 janqii 阅读(523) | 评论 (0)编辑 收藏

1、随机排列数组

方法1:给每个元素A[i]随机分配一个优先级p[i],然后按照优先级对数组A进行排序。例如初始A=<1,2,3,4>而且随机得到的优先级数组P=<36,3,97,19>,则得出随即数组B=<2,4,1,3>。这个过程称为PERMUTE_BY_SORTING。时间复杂度为O(nlgn)

方法2:原地排列给定数列。在第i次迭代时,元素A[i]是从元素A[i]到A[n]中随机选取的。时间复杂度为O(n)

n=length[A];

for i=1 to n

do swap(A[i], A[RANDOM(i,n)])

2、生日悖论

对于n=365,如果k=28,即如果至少有28个人,则可以期望至少有1对人的生日相同。

在n天中,k个人生日互不相同的组合有P(n,k)中,所有的组合(包括相同的)有n的k次方中,记为n^k,则k个人生日互不相同的概率为P(n,k)/n^k。

当k>=23时,P(n,k)/n^k<50%,则1-P(n,k)/n^k>50%,也就是说,当一个房间里有23个人时,至少有两个人生日相同的概率大于50%。

3、赠券收集者问题

一个人如果想要收集齐b种不同赠券中的每一种,大约需要b*lnb张随机得到的赠券才能完成。

用球和盒子的模型说明:把相同的球随机投到b个盒子中去。  

1>有多少个求落入指定的盒子中?服从二态分布(k;n,1/b),则期望值为n/b

2>在给定的盒子中至少一个球之前,平均需要投多少个球?服从几何分布,概率为1/b,成功前的期望个数为1/(1/b)=b

3>在每个盒子至少有一个球之前,要投多少个球?

我们称一次投球中落入一个空盒子为“击中”。

将n次投球分成b个阶段,阶段i包括第i-1次击中到i次击中之间的投球次数。第i阶段的每一次投球有i-1个盒子有球,n-k+1个盒子是空的,这样第i阶段的所有投球击中的概率都为(n-k+1)/b

用ni表示第i阶段的投球次数

n=SUM(ni)<i=1 to b>    每个随机变量ni都服从几何分布,成功概率为(n-k+1)/b

则      E(ni)=b/(b-k+1)

E(n)=E(SUM(ni))=SUM(E(ni))=SUM(b/(b-k+1))=b*SUM(1/(b-k+1))

根据调和级数的界可得 E(n)=b*(b+……+1/2+1)=b*(ln(n)+O(1))

所以大约投球b*lnb次就可以满足条件

4、最长序列问题

抛一枚均匀硬币n次,期望看到连续正面的最长序列有多长?答案是O(lgn)。

用X(i,k)=I{A(i,k)}表示对应于长度为k的序列开始于第i次抛硬币的指示器随机变量。

定义 X=SUM(X(i,k))<i=1 to n-k+1>

则     E(X)=E(....)=...=SUM(1/2^k)=(n-k+1)/2^k

令     k=clgn,对某个常数c,有

E(X)=......=O(1/n^(c-1))

当c<1/2时,E(X)=O(n^(1/2)),期望会有大量长为1/2*lgn的序列,因此,最长序列期望值长度为O(lgn)

5、苏格拉底的捡麦穗问题

怎么才可以捡到期望的最大麦穗呢?

方法是在前k次中不捡麦穗,但是比较找出最大麦穗并记住,在后面的n-k个麦穗中第一次遇到比前k个中的最大的还要大的麦穗就捡起,就是目标麦穗。如果没有发现比前k个还要大的,就捡最后一个第n个。

这里的关键是取好k的值,使得能够捡到最大的麦穗的可能性最大,根据算法导论(中文版)第67和68页分析,这个k值取n/e时,则可以至少有1/e的概率渠道最大的麦穗。k=n/e

阅读全文
类别:算法 查看评论
文章来源:http://hi.baidu.com/janqii/blog/item/a23e93df0fa9fdadcd1166d8.html
posted @ 2010-04-27 23:48 janqii 阅读(547) | 评论 (0)编辑 收藏

Problem D:【算法】:排列的字典序问题

Time Limit:2000MS Memory Limit:65536K
Total Submit:200 Accepted:66

Description

n个元素{1,2,..., n }有n!个不同的排列。将这n!个排列按字典序排列,并编号为0,1,…,n!-1。每个排列的编号为其字典序值。例如,当n=3时,6 个不同排列的字典序值如下:

任务:给定n 以及n 个元素{1,2,..., n }的一个排列,计算出这个排列的字典序值,以及按字典序排列的下一个排列。
Input

第1 行是元素个数n(n < 15)。接下来的1 行是n个元素{1,2,..., n }的一个排列。

Output

第一行是字典序值,第2行是按字典序排列的下一个排列。

Sample Input
8
2 6 4 5 8 1 7 3

Sample Output
8227
2 6 4 5 8 3 1 7
-----------------------------------------------------------------------------------------------------------------------

字典序法:
字典序法中,对于数字1、2、3......n的排列,不同排列的先后关系是从左到右逐个比较对应的数字的先后来决定的。例如对于5个数字的排列 12354和12345,排列12345在前,排列12354在后。按照这样的规定,5个数字的所有的排列中最前面的是12345,最后面的是 54321。
字典序算法如下:
设P是1~n的一个全排列:p=p1p2......pn=p1p2......pj-1pjpj+1......pk-1pkpk+1......pn
1)从排列的右端开始,找出第一个比右边数字小的数字的序号j(j从左端开始计算),即   j=max{i|pi<pi+1}
2)在pj的右边的数字中,找出所有比pj大的数中最小的数字pk,即 k=max{i|pi>pj}(右边的数从右至左是递增的,因此k是所有大于pj的数字中序号最大者)
3)对换pi,pk
4)再将pj+1......pk-1pkpk+1pn倒转得到排列p'=p1p2.....pj-1pjpn.....pk+1pkpk-1.....pj+1,这就是排列p的下一个下一个排列。
例如839647521是数字1~9的一个排列。从它生成下一个排列的步骤如下:
自右至左找出排列中第一个比右边数字小的数字4          839647521
在该数字后的数字中找出比4大的数中最小的一个5        839647521
将5与4交换                                                                         839657421
将7421倒转                                                                          839651247
所以839647521的下一个排列是839651247。

--------------------------------------------------------------------------------------------------------------------------

#include<stdio.h>
#include<stdlib.h>

void dict_sort(int arr[],int size);
int find_first_small(int arr[],int size);
int find_smallest(int arr[],int start,int size);
void swap(int arr[],int idx1,int idx2);
void converse(int arr[],int start,int end);
int factorial(int n);
int find_position(int arr[],int size,int *pos);

int main(void)
{
int i,n,val;
int pos;
int *a;

scanf("%d",&n);
a=(int*)malloc(n*sizeof(int));

for(i=0;i<n;i++)
{
   scanf("%d",&a[i]);
   //a[i]=val;
}

dict_sort(a,n);
find_position(a,n,&pos);

printf("%d\n",pos);
for(i=0;i<n;i++)
   printf("%d ",a[i]);

return 0;
}

void dict_sort(int arr[],int size)
{

int idx1;
int idx2;

idx1=find_first_small(arr,size);

if(idx1==-1)
{
   printf("the last one...\n");
   return ;
}

idx2=find_smallest(arr,idx1+1,size);
swap(arr,idx1,idx2);
converse(arr,idx1+1,size-1);
}

int find_position(int arr[],int size,int *pos)
{
int i,nr;
int sum=0;
for(i=0;i<size-1;i++)
{
   nr=get_counter(arr,i,size);

   if(nr>0)
    sum += nr*factorial(size-i-1);
}
*pos=sum+1;

return *pos;
}

int factorial(int n)
{
int rt=1;
while(n>0)
{
   rt *=n;
   n--;
}
}

int find_first_small(int arr[],int size)
{
int i=size-1;

for(i=size-1;i>=0;i--)
{
   if(arr[i-1]<arr[i])
    return i-1;
}

return -1;
}

int get_counter(int arr[],int start,int size)
{
int i;
int counter=0;
int start_val=arr[start];

for(i=start+1;i<size;i++)
{
   if(arr[i]<start_val)
    counter++;
}

return counter;
}

int find_smallest(int arr[],int start,int size)
{
int i;
int pos=start;
int start_val=arr[start-1];
int key=arr[start];

for(i=start+1;i<size;i++)
{
   if(arr[i]>start_val&&arr[i]<key)
   {
    key=arr[i];
    pos=i;
   }

}

return pos;
}

void swap(int arr[],int idx1,int idx2)
{
int tmp=arr[idx1];

arr[idx1]=arr[idx2];
arr[idx2]=tmp;
}

void converse(int arr[],int start,int end)
{
int i=end;

for(i=end;i>=(start+end+1)/2;i--)
{
   swap(arr,end-i+start,i);
}
}

阅读全文
类别:算法 查看评论
文章来源:http://hi.baidu.com/janqii/blog/item/a181ba5b08102b8d800a18a6.html
posted @ 2010-04-27 23:48 janqii 阅读(581) | 评论 (0)编辑 收藏

国王招来100个囚犯,对他们说:你们犯的是死罪,本应该将你们统统杀掉,但我慈悲为怀,给你们一次求生的机会。15分钟以后,你们将被关进一个有100间隔离牢房的监狱里,每人一间牢房,都与外界隔绝,什么也听不见、看不到,连时间都没法计算,更别说获得外界的任何信息。(送饭除外,但也是不规律的送)

这所监狱有一个院子,每天会随机(注意是完全随机)打开一间牢房的门,让那个囚犯到院子里来放风。院子里有一盏路灯,放风的囚犯可以控制它的开关,将它打开或是关闭。除囚犯之外,其他人都不会去碰开关。这盏灯会永远有充足的能源供应,如果灯泡坏了或是电路出了故障会马上修好,当然修理人员不会改变灯的状态(开或关)。

除了开关这盏灯,放风的囚犯放风时留下的任何其它痕迹都会在夜晚被清除干净(包括在灯上作的任何记号)。

牢房是完全封闭的,院子里的灯光在牢房里看不到。只有放风出到院子里的人才能看到。

好了现在我向你们提出一个要求,只要你们做到了,就可以全部获得释放: 若干天以后,你们中只要有任何一个人能够向我证明所有的人都曾到院子里去过,你们就全体释放。当然要有证据!因为我只会给你们一次机会,如果向我证明的那个人无法自圆其说,你们就全部砍头。所以,要珍惜这次机会。如果你们永远做不到我的要求,你们就全部关到死。

现在给你们15分钟商量你们的方案。15分钟以后,你们将被关进我刚才说的那个监狱,永远无法再交流。

-------------------------------------------------------------------------------------------------------------

第一天出来的人作为“计数者”(第一个出来的人确定自己是“计数者”,其他人确定自己不是“计数者”)

如果是“计数者”就把灯打开(关闭的情况下打开),计数+1,若灯开着的话就什么也不做

如果不是“计数者”,如果是第一次出来放风而且灯开着就关闭它,否则什么也不做

当“计数者”的 counter=100的时候就可以想国王申请走人了。

-------------------------------------------------------------------------------------------------------------

这种算法需要多长的时间才可以获得释放呢,写代码验证之。答案是10000天左右,也就是20-30年的时间,够漫长的。不知道还有没有其他更好的方法。

#include<iostream>
#include<vector>
#include<ctime>
using namespace std;

int   getDays(void);
bool not_selected(vector<int> v,int key);

int main(void)
{
cout<<getDays()<<endl;
return 0;
}

int getDays(void)
{
int observer=-1;
int rd=-1;
int counter=0;
int days=0;
vector<int> prison;
volatile bool b_light=false;

srand(time(NULL));
observer=rand()%100;
b_light=true;
days++;

while(1)
{
   days++;
   if((rd=rand()%100)==observer)
   {
    if(b_light==false)
    {
     counter++;
     b_light=true;
    }
    if(counter==99)
     break;
   }
   else
   {
    if(b_light&&not_selected(prison,rd))
    {
     prison.push_back(rd);
     b_light=false;
    }
   } //else
} //while

return days;
}

bool not_selected(vector<int> v, int key)
{
for(vector<int>::iterator iter=v.begin();iter!=v.end();++iter)
{
   if(*iter==key)
    return false;
}

return true;
}

阅读全文
类别:算法 查看评论
文章来源:http://hi.baidu.com/janqii/blog/item/3756d81afc73f04943a9adae.html
posted @ 2010-04-27 23:48 janqii 阅读(252) | 评论 (0)编辑 收藏

C++ Primer中建议delete一个指针之后,执行ptr=NULL,来让指针指向0,以后再使用ptr,系统就会报错。

--------------------------------------C++ Primer----------------------------------------------------------------

执行语句 delete p; 后,p变成没有定义。

在很多机器上,尽管 p 没有定义,但仍然存放了它之前所指向对象的地址,然而 p 所指向的内存已经被释放,因此 p 不再有效。

删除指针后,该指针变成悬垂指针。

悬垂指针指向曾经存放对象的内存,但该对象已经不再存在了。悬垂指针往往导致程序错误,而且很难检测出来。

一旦删除了指针所指向的对象,立即将指针置为 0,这样就非常清楚地表明指针不再指向任何对象。

阅读全文
类别:c/c++ 查看评论
文章来源:http://hi.baidu.com/janqii/blog/item/e430a396d1dfe047d1135eca.html
posted @ 2010-04-27 23:48 janqii 阅读(355) | 评论 (0)编辑 收藏

堆排序的时间复杂度和合并排序时间复杂度一样是O(n*lgn)。

堆排序可以原地排序,这一点上优于合并排序(需要一个辅助数组);插入排序也是原地排序,可是时间复杂度是O(n^2)

1、保持堆(大顶堆)的性质的算法(A是输入堆,从i开始保持大顶堆的性质):

max_heapify(A,i)
    l=LEFT(i)
    r=RIGHT(i)
    if(l<=heap_size(A)&&A[l]>A[i])
            then largest=l
    else largest=i
    if(r<=heap_size(A)&&A[r]>A[largest])
           largest=r
    if(largest!=i)
           then exchange A[i]<->A[largest]
          max_heapify(A,largest)

2、建堆(从最后一个非叶子节点开始使其保持堆的性质):

共有n个元素,则最后一个非叶子节点位置是n/2。

不妨设最后一个非叶子节点为(n+1)/2,则其左孩子是n+1>n,矛盾,所以是n/2,则算法描述为

build_maxHeap(A)
    for i=heap_size(A)/2 downto 1
           do max_heapify(A,i)

3、堆排序

首先建立大顶堆,然后把根元素(最大元素)与最后一个叶子节点交换位置,heap-size--,然后从根元素开始调整堆,使其保持大顶堆的性质。

算法描述为

   heap_sort(A)
           build_maxHeap(A)
          for i=heap_size(A) downto 2
               do exchange A[1]<->A[i]
                    heap_size(A)=heap_size(A)-1
                    max_heapify(A,1)

-------------------------------------------------示例演示---------------------------------------------------------------------

示例输入:9                 /*堆大小*/

                  5                 /*元素个数*/

                  1 5 2 4 3     /*输入元素值*/

输出:5 4 3 2 1

-------------------------------------------------C代码实现---------------------------------------------------------------------

#include<stdio.h>
#include<stdlib.h>

#define LEFT(i)   2*i
#define RIGHT(i) 2*i+1
#define PARENT(i) i/2

struct HeapType{
int *base;   /*base[0]存放heap_size,因此heap_size字段也可以去掉*/
int length;
int heap_size; /*可去掉,用base[0]来代替*/
};

void max_heapify(struct HeapType heap,int i);
void build_maxHeap(struct HeapType heap);
void heap_sort(struct HeapType heap);
void swap(int *val1,int *val2);

int main(void)
{
int i=-1;
int n=-1;
int val=-1;
struct HeapType heap;

heap.length=0;
heap.heap_size=0;

scanf("%d",&n);

heap.length=n;
heap.base=(int*)malloc((heap.length+1)*sizeof(int));

scanf("%d",&heap.heap_size);

if(heap.heap_size>heap.length)
   return -1;

for(i=1;i<=heap.heap_size;i++)
{
   scanf("%d",&val);
   heap.base[i]=val;
   /*heap.heap_size +=1;*/
}

heap.base[0]=heap.heap_size;
i=heap.heap_size;

heap_sort(heap);
for( ;i>0;i--)
   printf("%d ",heap.base[i]);

return 0;
}

void max_heapify(struct HeapType heap,int i)
{
int largest=-1;
int l=LEFT(i);
int r=RIGHT(i);

if(l<=heap.heap_size && heap.base[l]>heap.base[i])
   largest=l;
else
   largest=i;

if(r<=heap.heap_size && heap.base[r]>heap.base[largest])
   largest=r;

if(largest!=i)
{
   swap(&heap.base[largest],&heap.base[i]);
   max_heapify(heap,largest);
}   
}

void build_maxHeap(struct HeapType heap)
{
int i=-1;

for(i=(heap.heap_size)>>1;i>0;i--)
   max_heapify(heap,i);
}

void heap_sort(struct HeapType heap)
{
int i=-1;

build_maxHeap(heap);

for(i=heap.heap_size;i>1;i--)
{
   swap(&heap.base[1],&heap.base[i]);
   heap.heap_size -=1;
   max_heapify(heap,1);
}
}

void swap(int *val1,int *val2)
{
int tmp=*val1;
*val1=*val2;
*val2=tmp;
}

阅读全文
类别:算法 查看评论
文章来源:http://hi.baidu.com/janqii/blog/item/f318f6155f74e05df3de32c5.html
posted @ 2010-04-27 23:48 janqii 阅读(223) | 评论 (0)编辑 收藏

C++ Primer 7.9节

-----------------------------------------------------------------------------------------------------------------------------------

函数可以返回指向函数的指针,但是,正确写出这种返回类型相当不容易:

// ff is a function taking an int and returning a function pointer

// the function pointed to returns an int and takes an int* and an int

int (*ff(int))(int*, int);

阅读函数指针声明的最佳方法是从声明的名字开始由里而外理解

要理解该声明的含义,首先观察:

ff(int)

将 ff 声明为一个函数,它带有一个 int 型的形参。该函数返回

int (*)(int*, int);

它是一个指向函数的指针,所指向的函数返回 int 型并带有两个分别是int* 型和 int 型的形参。

使用 typedef 可使该定义更简明易懂:

// PF is a pointer to a function returning an int, taking an int* and an int

typedef int (*PF)(int*, int);

PF ff(int);

// ff returns a pointer to function

允许将形参定义为函数类型,但函数的返回类型则必须是指向

函数的指针,而不能是函数。

具有函数类型的形参所对应的实参将被自动转换为指向相应函数类型的指针。但是,当返回的
是函数时,同样的转换操作则无法实现:

// func is a function type, not a pointer to function!

typedef int func(int*, int);

void f1(func);    // ok: f1 has a parameter of function type

func f2(int);        // error: f2 has a return type of function type

func *f3(int);       // ok: f3 returns a pointer to function type

------------------------------------------------------------------简单例子---------------------------------------------------------------------------------

#include<iostream>
using namespace std;

int (*ff(int f))(int val1,int val2);
int (*fun)(int val1,int val2);
int foo(int a,int b);

int main()
{
   fun=ff(0);
   cout<<fun(1,2)<<endl;
   return 0;
}

int foo(int a,int b)
{
   cout<<a<<" "<<b<<" foo is calling..."<<endl;
   return b+1;
}

int (*ff(int f))(int val1,int val2)
{
   cout<<f<<" ff is calling..."<<endl;
   return foo;
}

-------------------------------------------------------------------------------输出------------------------------------------------------------------------------

0 ff is calling...
1 2 foo is calling...
3

----------------------------------------------------------------------------使用typedef-----------------------------------------------------------------------

#include<iostream>
using namespace std;


typedef int (*fun)(int val1,int val2);
fun ff(int);
int foo(int a,int b);

int main()
{
   cout<<ff(0)(1,2)<<endl;
   return 0;
}

int foo(int a,int b)
{
    cout<<a<<" "<<b<<" foo is calling..."<<endl;
    return b+1;
}

fun ff(int f)
{
   cout<<f<<" ff is calling..."<<endl;
   return foo;
}

阅读全文
类别:c/c++ 查看评论
文章来源:http://hi.baidu.com/janqii/blog/item/32b06427b807893fc89559d7.html
posted @ 2010-04-27 23:48 janqii 阅读(397) | 评论 (0)编辑 收藏

看linux内核链表实现的时候看到typeof关键字,在网上找到一些材料。

摘自http://blog.chinaunix.net/u3/101356/showart_2081601.html

typeof关键字是C语言中的一个新扩展。只要可以接受typedef名称,Sun Studio C 编译器就可以接受带有typeof的结构,包括以下语法类别:

·声明
·函数声明符中的参数类型链表和返回类型
·类型定义
·类型操作符s
·sizeof操作符
·复合文字
·typeof实参
编译器接受带双下划线的关键字:__typeof和__typeof__。本文中的例子并没有遵循使用双下划线的惯例。从语句构成上看,typeof关键字后带圆括号,其中包含类型或表达式的名称。这类似于sizeof关键字接受的操作数(与sizeof不同的是,位字段允许作为typeof实参,并被解释为相应的整数类型)。从语义上看,typeof 关键字将用做类型名(typedef名称)并指定类型。

使用typeof的声明示例
下面是两个等效声明,用于声明int类型的变量a。

typeof(int) a; /* Specifies variable a which is of the type int */ typeof('b') a; /* The same. typeof argument is an expression consisting of                     character constant which has the type int */
以下示例用于声明指针和数组。为了进行对比,还给出了不带typeof的等效声明。

typeof(int *) p1, p2; /* Declares two int pointers p1, p2 */int *p1, *p2;typeof(int) * p3, p4;/* Declares int pointer p3 and int p4 */int * p3, p4;typeof(int [10]) a1, a2;/* Declares two arrays of integers */int a1[10], a2[10];
如果将typeof用于表达式,则该表达式不会执行。只会得到该表达式的类型。以下示例声明了int类型的var变量,因为表达式foo()是int类型的。由于表达式不会被执行,所以不会调用foo函数。

extern int foo();typeof(foo()) var;
使用typeof的声明限制请注意,typeof构造中的类型名不能包含存储类说明符,如extern或static。不过允许包含类型限定符,如const或volatile。例如,下列代码是无效的,因为它在typeof构造中声明了extern:typeof(extern int) a;
下列代码使用外部链接来声明标识符b是有效的,表示一个int类型的对象。下一个声明也是有效的,它声明了一个使用const限定符的char类型指针,表示指针p不能被修改。
extern typeof(int) b;typeof(char * const) p = "a";
在宏声明中使用typeof
typeof构造的主要应用是用在宏定义中。可以使用typeof关键字来引用宏参数的类型。因此,在没有将类型名明确指定为宏实参的情况下,构造带有所需类型的对象是可能的。

阅读全文
类别:c/c++ 查看评论
文章来源:http://hi.baidu.com/janqii/blog/item/e7b721ee3381ded8b21cb161.html
posted @ 2010-04-27 23:48 janqii 阅读(496) | 评论 (0)编辑 收藏
仅列出标题  下一页

导航

统计

常用链接

留言簿

随笔档案(15)

搜索

最新评论

阅读排行榜

评论排行榜