#
具体是这么说:“在Win 3.x中,WPARAM是16位的,而LPARAM是32位的,两者有明显的区别。因为地址通常是32位的,所以LPARAM 被用来传递地址,这个习惯在Win32 API中仍然能够看到。在Win32 API中,WPARAM和LPARAM都是32位,所以没有什么本质的区 别。Windows的消息必须参考帮助文件才能知道具体的含义。如果是你定义的消息,愿意怎么使这两个参数都行。但是习惯上,我们愿意使用LPARAM传 递地址,而WPARAM传递其他参数。”
看一个例子就明白了: 程序代码*在对话框中取出数据,并向其他窗口发送消息和数据,将数据指针作为一个参数发送*/
void CTestDlg2::OnCommBtn()
{
char szOut[30];
GetDlgItemText(IDC_OUT,szOut,30);
m_pParent->SendMessage(WM_DLG_NOTIFY,(WPARAM)szOut);
}
/*在消息接收窗口中*/
/*映射消息处理函数*/
ON_MESSAGE(WM_DLG_NOTIFY,OnDlgNotifyMsg)
/*在视图中绘制出字符串 m_szOut*/
void CMy53_s1View::OnDraw(CDC* pDC)
{
CMy53_s1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
pDC->TextOut(0,0,"Display String");
pDC->TextOut(0,20,m_szOut);
}
/*处理通知消息,保存信息并更新显示*/
LONG CMy53_s1View::OnDlgNotifyMsg(WPARAM wP,LPARAM lP)
{
m_szOut=(char*)wP;
Invalidate();
return 0;
}
一个字符串的地址通过WPARAM来标识,再通过Windows消息发送出去;之后在消息处理函数中WPARAM接受到的参数就是该地址,然后就可以对该地址进行操作了~~~
这是Windows消息机制中经常用到的两个data type,呵呵。
明年过年就要上班了,最近看了 effective c++ 和 more effective c++
今天有去图书馆借了3本书,准备回家过年看,
这3本书为 C++编程艺术 , exceptional c++ style , OOD启示录
都是传说的好书,但是对于每一个来说不一定是好书, 先看完在说。。
其中Wesley的effective c++ 和 more effective c++ 的确不错,加深了对c++的认识,以及OO的理解,项目中应该注意的问题!
加油咯,就要迈入社会了!
sohu被刷了。。
哎!
还是踏实点 好好学习吧!
现在的心情除了失落没有设么词形容了
首先 UDP 默认不能实现广播
要实现一个机子的广播,首先 应该明白2个函数
1.setsockopt 开启发送广播报文
2.getsockopt 确定广播选项是否关闭
setsockopt 的原型定义:
WINSOCK_API_LINKAGE int WSAAPI setsockopt( IN SOCKET s, IN int level, IN int optname, IN const char FAR * optval, IN int optlen )
开启报文代码
if (setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(char *)&bborad,oplen) == SOCKET_ERROR)
{
printf("setsockopt error!");
return 0;
}
作为server:
然后发送广播报文
sockaddr_in addr;
int nlen = sizeof(addr);
memset(&addr,0,nlen);
addr.sin_family = AF_INET;
addr.sin_port = htons(9999);
addr.sin_addr.s_addr =INADDR_BROADCAST;
const char *msg = "hello! This is a test!";
int len = strlen(msg);
if (sendto(sock,msg,len,0,(struct sockaddr *)&addr,sizeof(addr)) == SOCKET_ERROR)
{
printf("send error !!");
return 0;
}
然后客户端:
接受报文:
2008年12月8日
# include <WinSock2.h>
# include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
#define WSVERS MAKEWORD(2,0)
//CInitSock initSock;
int main()
{
WSADATA wsadata;
if(WSAStartup(WSVERS,&wsadata))
{
printf("WSAStartup failed!\n");
return 0;
}
SOCKET sLiten = ::socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(sLiten == INVALID_SOCKET)
{
printf("WSACleanup failed with error %d\n",WSAGetLastError());
//printf(" Failed socket()");
return 0;
}
sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(9999);
local.sin_addr.s_addr =INADDR_ANY;
if(::bind(sLiten,(LPSOCKADDR)&local,sizeof(local)) == SOCKET_ERROR)
{
printf(" failed bind()");
return 0;
}
char buf[1024];
sockaddr_in addr;
int nlen = sizeof(addr);
while(1)
{
int recv = ::recvfrom(sLiten,buf,1024,0,(sockaddr *)&addr,&nlen);
if(recv )
{
buf[recv] = '\0';
printf("接收到数据 (%s): (%s)",::inet_ntoa(addr.sin_addr),buf);
}
}
::closesocket(sLiten);
return 0;
}
stl中:
MAP的节点是一对数据.
SET的节点是一个数据.
Map使用关键值Key来唯一标识每一个成员 map可以重复。
set是集合
都属于关联容器
只不过, map的形式 map<type1, type2> mymap;
set的形式 set<type> myset;
set(集合)——包含了经过排序了的数据,这些数据的值(value)必须是唯一的。
map(映射)——经过排序了的二元组的集
合,map中的每个元素都是由两个值组成,其中的key(键值,一个map中的键值必须是唯一的)是在排序或搜索时使用,它的值可以在容器中重新获取;而
另一个值是该元素关联的数值。比如,除了可以ar[43] = "overripe"这样找到一个数据,map还可以通过ar["banana"] =
"overripe"这样的方法找到一个数据。如果你想获得其中的元素信息,通过输入元素的全名就可以轻松实现。
map是映射集合中的元素不能重复,set可以进行集合的各种操作(交并补等),当然你也可以用list或vector实现set,但是效率会很低。set一般是用平衡树或哈西表实现的。
映射是一种一一对应的关系,哈西表也可以看作是映射的一种。映射通常可用来实现字典结构(dictionary)
1.指针运算
注意 ,每个例子不只是一个题目,可能有多个,用
//....................................来分开的
# include <iostream>
# include <stdio.h>
using namespace std;
enum string
{
x1,x2,x3=10,x4,x5,
}X;
int main()
{
//测试1
cout << x1 << x5<<endl;
unsigned char *p1;
unsigned long *p2;
p1 = (unsigned char *)0x801000;
p2 = (unsigned long *)0x801000;
printf("%p\n",p1+5);
printf("%p\n",p2+5);
char * t [] = { "abccc","daa","caa"};
char **bb = t;
cout << t[1] <<endl;
cout << sizeof(t)<<endl;
//....................................
int a[5] = {1,2,3,4,5};
cout << *( (int *)(&a+1)-2) <<endl;
int i=0;
int j=1;
long *p = NULL;
char *c = NULL;
if(j++ && i++)
p++,c++;
if(i++ || j++)
p++,c++;
cout << i <<" " << j << " " << *p << " " << (long *)c <<endl;
//....................................
int i =1;
int c = (i++) + (i++) + (i++);
cout << c <<" "<< i<<endl;
return 0;
}
2.
# include <iostream>
# include <stdio.h>
using namespace std;
void foo(int k)
{
char tmp[100];
//sprintf(tmp,"%d",k);
printf("%d\n",tmp);
foo(k-1);
}
int main()
{
int i= 0;
int x= 0;
int y= 0;
printf("%d %d %d %d\n",x--,++y,i++,i++);
char tmp[20]="hello\0\t\\\\world";
cout<<tmp<<endl;
cout << sizeof(tmp) << " " <<strlen(tmp)<<" "<< tmp<<endl;
//....................................
char arr[100] = "hello world";
int *v = (int *)arr;
v[0] = 0X61626364;
v[1] = 0X41424344;
v[2] = 0X31323334;
v[3] = 0;
cout<<arr<<endl;
//....................................
foo(3);
return 0;
}
KMP算法是查询子串比较快的一种算法!
我们先看普通的模式匹配算法。。
int Index(String S,String T,int pos)//参考《数据结构》中的程序
{
i=pos;j=1;//这里的串的第1个元素下标是1
while(i<=S.Length && j<=T.Length)
{
if(S[i]==T[j]){++i;++j;}
else{i=i-j+2;j=1;}//**************(1)
}
if(j>T.Length) return i-T.Length;//匹配成功
else return 0;
}
匹配的过程非常清晰,关键是当‘失配’的时候进行回溯!
看下面的例子:
S:aaaaabababcaaa T:ababc
aaaaabababcaaa
ababc.(.表示前一个已经失配)
回溯的结果就是
aaaaabababcaaa
a.(babc)
如果不回溯就是
aaaaabababcaaa
aba.bc
这样就漏了一个可能匹配成功的情况
aaaaabababcaaa
ababc
为什么会发生这样的情况?这是由T串本身的性质决定的,是因为T串本身有前后'部分匹配'的性质。如果T为abcdef这样的,大没有回溯的必要。
改进的地方也就是这里,我们从T串本身出发,事先就找准了T自身前后部分匹配的位置,那就可以改进算法。
如果不用回溯,那T串下一个位置从哪里开始呢?
还是上面那个例子,T为ababc,如果c失配,那就可以往前移到aba最后一个a的位置,像这样:
...ababd...
ababc
->ababc
这样i不用回溯,j跳到前2个位置,继续匹配的过程,这就是KMP算法所在。这个当T[j]失配后,j应该往前跳的值就是j的next值,它是由T串本身固有决定的,与S串无关。
《数据结构》上给了next值的定义:
0 如果j=1
next[j]={Max{k|1<k<j且'p1pk-1'='pj-k+1pj-1'
1 其它情况
我当初看到这个头就晕了,其实它就是描述的我前面表述的情况,关于next[1]=0是规定的,这样规定可以使程序简单一些,如果非要定为其它的值只要不和后面的值冲突也是可以的;而那个Max是什么意思,举个例子:
T:aaab
...aaaab...
aaab
->aaab
->aaab
->aaab
像这样的T,前面自身部分匹配的部分不止两个,那应该往前跳到第几个呢?最近的一个,也就是说尽可能的向右滑移最短的长度。
OK,了解到这里,就看清了KMP的大部分内容,然后关键的问题是如何求next值?先不管它,先看如何用它来进行匹配操作,也就是说先假设已经有了next值。
将最前面的程序改写成:
int Index_KMP(String S,String T,int pos)
{
i=pos;j=1;//这里的串的第1个元素下标是1
while(i<=S.Length && j<=T.Length)
{
if(j==0 || S[i]==T[j]){++i;++j;} //注意到这里的j==0,和++j的作用就知道为什么规定next[1]=0的好处了
else j=next[j];//i不变(不回溯),j跳动
}
if(j>T.Length) return i-T.Length;//匹配成功
else return 0;
}
OK,是不是非常简单?还有更简单的,求next值,这也是整个算法成功的关键,从next值的定义来求太恐怖了,怎么求?前面说过了,next值
表达的就是T串的自身部分匹配的性质,那么,我只要将T串和T串自身来一次匹配就可以求出来了,这里的匹配过程不是从头一个一个匹配,而是从T[1]和T
[2]开始匹配,给出算法如下:
void get_next(String T,int &next[])
{
i=1;j=0;next[1]=0;
while(i<=T.Length)
{
if(j==0 || T[i]==T[j]){++i;++j; next[i]=j;/**********(2)*/}
else j=next[j];
}
}
注意到(2)语句逻辑覆盖的时候是T[i]==T[j]以及i前面的、j前面的都匹配的情况下,于是先自增,然后记下来next[i]=j,这样每当i有
自增就会求得一个next[i],而j一定会小于等于i,于是对于已经求出来的next,可以继续求后面的next,而next[1]=0是已知,所以整
个就这样递推的求出来了,方法非常巧妙。