http://shuku.mofcom.gov.cn/book/index.html
http://www.baidu.com/search/guoxue/dir/fenlei.html
http://www.ishici.com/
http://blog.csdn.net/feixiaoxing/article/details/7185764//设计模式
http://blog.csdn.net/whf727/article/details/5965989
http://www.oneie.com/redirect.php?tid=52908&goto=lastpost
http://www.cnblogs.com/haibindev/archive/2011/12/29/2305712.html
http://www.cnblogs.com/haibindev/archive/2011/11/10/2244442.html
http://www.cnblogs.com/haibindev/
1.scanf函数返回正确读入的数据个数
2.要从逻辑上删除一段C代码,更好的办法是使用#if指令,只要像下面这样使用:
#if 0
statements
#endif
3.使用所有的格式码(除了%c之外)时,输入值之前的空白(空格,制表符,换行符等)会被跳过,值后面的空白表示该值的结束.
4.for语句包含3个表达式(3个表达式都是可选的),第一个表达式是初始部分,它只在循环开始前执行一次
第二个表达式是测试部分,它在循环每执行一次后都要执行一次,第三个表达式为调整部分,它在每次循环执行完毕后都要执行一次,
但它在测试部分之前执行.
5.putchar/getchar(输入/输出一个字符) strchr/strstr(搜索) strcat/strncpy/strcpy
6.空白字符:空格 制表符 垂直制表符 格式反馈字符 换行符,因为它们被打印出来时,在页面上出现的是空白而不是各种记号.
7.三字母词:
??( [ ??) ] ??< { ??> }
??! | ??' ^ ??- ~ ??/ \
??= #
8.你应该使用typedef而不是#define来创建新的类型名,因为后者无法正确地处理指针类型.例如:
#define d_ptr_to_char char *
d_ptr_to_char a,b;
正确地声明了a,但是b却被声明为一个字符.
9.两个代码块的变量不可能同时存在,所以编译器可以把它们存储于同一个内存地址.
10.标识符的作用域与它的链接属性有关,但这两个属性并不相同.
链接属性一共有3种:extern(外部)\internal(内部)\none(无).
11.一个变量具有存储类型(auto,static,register),作用域(代码块作用域,文件作用域,原型作用域,函数作用域),链接属性(extern/internal/none),
12.通过一个extern 引用一个具有external链接属性的变量时,这个变量的作用域为该代码块作用域.
13.为了保持最佳的可移植性,把字符的值限制在有符号和无符号字符范围的交集之内,或者不要在字符上执行算术运算.
14.只有具有external链接属性的变量才能用static将其链接属性修改为internal,否则只是定义了一个具有代码块作用域的静态变量 .
15.逻辑移位和算术移位:
逻辑移位:左边移入的位用0填充;
算术移位:左边移入的位由原先该值的符号位决定,符号位为1,则移入的位均为1,符号位为0,则移入的位均为0,这样能够保证原数的正负形式不变;
只有在右移时逻辑移位与算术移位才可能不同;这个取决于编译器,一个程序如果使用了有符号数的右移位操作,它就是不可移植的.
16.逗号操作符将两个或多个表达式分隔开来,这些表达式自左向右逐个进行求值,整个逗号表达式的值就是最后那个表达式的值.
17.有符号数与无符号数,有符号数要注意符号位,以及在进行位运算是,是否会越界,是否会修改符号位等一些细节的问题.
18.变量的值就是分配给该变量的内存位置所存储的数值,即使是指针变量也不例外.********
19.一级指针的*q++操作与二级指针的*p++操作比较:
char* ch = "abcdefghijk";
char* q = &ch;
q++;
一级指针*q++;===>先做*q指令,得到ch的值,再做q++将q指针向后移动1个字节,即指向ch变量内存地址的下一个字节;
二级指针*p++;===>先做*p指令,得到ch的内存地址,再做p++将p指针向后移动1个字节,即指向q指针变量内存地址的下一个字节;
而我们在用二级指针*p++的时候本是想将q指针向后移动1个字节,但往往由于不细心容易忽略二者的区别;
实际上我们应该这么做(*p)++;才能做到我们想要的;
如下也是一个二级指针,指针数组:
char* ch[4] = { "abcdefgchijk" , "fdsak" , "fdsaf" , NULL};
char* *str = ch;
printf( "%s\n" , *str);
*str++;
printf("%s\n" , *str);
20.当程序调用一个无法见到原型的函数时,编译器便认为该函数返回一个整形值,对于那些并不返回整形值的函数,这种认定可能会引志错误.
21.在声明数组参数时不指定它的长度是合法的,因为函数并不为数组元素分配内存.
22.只有在两种场合下,数组名并不用指针常量来表示,就是当数组名作为sizeof操作符或单目操作符&的操作数时.
sizeof返回整个数组的长度,而不是指向数组的指针的长度.取一个数组名的地址所产生的是一个指向数组的指针,而不是一个指向某个指针常量值的指针.
23.注意如下的情况:
char const *keyword[] = {
"do",
"for",
"if",
"register",
"return",
"switch",
"while",
NULL
};
在表的未尾增加了一个NULL指针.这个NULL指针使函数在搜索这个表时能够检测到表的结束,而无需预先知道表的长度.
24.如果如下strlen(x)返回一个无符号数,则:
if( strlen( x ) >= strlen( y ) ) ...
if( strlen( x ) - strlen( y ) >= 0 ) ...
第一条语句可以正常执行,但第二条不会正常执行,因为第二条语句左边的计算结果是一个
无符号数,所以永远不会为负,所以这个表达式永远为真;
25.strspn/strcspn:
strspn( char const *str , char const *group );
strspn返回str起始部分匹配group中任意字符的字符数.
int len1 , len2;
char buffer[] = "25,142,330,Smith,J,239-4123";
len1 = strspn( buffer , "0123456789" );==>2
len2 = strspn( buffer , ",0123456789" );==>11
26.char *strerror( int error_number );
通过errno传入错误号,调用该函数,返回一个指向错误描述字符串的指针;
27.iscntrl:任何控制字符
isspace:空白字符
isdigit:数字
islower:小写字母
isupper:大写字母
isalpha:字母
isalnum:字母或数字
isprint:可打印字符
28.memchr , memmove , memcpy , memcmp , memset
//memchr:查找一个字符在一片内存中第一次出现的位置
29.你可以在声明中对结构的成员列表重新排列,让那些对边界要求最严格的成呗首先出现,对边界要求最
弱的成员最后出现.这种做法可以最大限度地减少因边界对齐而带来的空间损失.
IUnknown *pUnk = NULL;
IObject *pObject = NULL;
CoInitialize(NULL);//COM组件初始化
CoCreateInstance(CLSID_Object , CLSCTX_INPROC_SERVER , NULL , IID_IUnknown , (void**)&pUnk);//创建接口
pUnk->QueryInterface(IID_IOjbect , (void**)&pObject);//创建类厂,再获取对象
pUnk->Release();
pObject->Func();
pObject->Release();
CoUninitialize();
CoCreateInstance()
{
IClassFactory *pClassFactory = NULL;
//先创建类厂,再创建接口实例
CoGetClassObject(CLSID_Object , CLSCTX_INPROC_SERVER , NULL , IID_IClassFactory , (void**)&pClassFactory);
pClassFactory->CreateInstance(NULL , IID_IUnknown , (void**)&pUnk);
pClassFactory->Release();
}
CoGetClassObject(){
//通过查注册表CLSID_Object,得知组件DLL的位置 , 文件名
//装入DLL库
//使用函数GetProcAddress()得到DLL库中函数DllGetClassObject的函数指针
//调用DIIGetClassObject
}
DllGetClassObject(){
CFactory* pFactory = new CFactory;//类厂对象
pFactory->QueryInterface(IID_IClassFactory , (void**)&pClassFactory);
//查询ClassFactory指针
pFactory->Release();
}
CFactory::CreateInstance(){
CObject *pObject = new CObject;//组件对象
pObject->QueryInterface(IID_IUnknow , (void**)&pUnk);
pObject->Release();
}
一个典型的自注册的COM DLL所必有的四个导出函数
DllGetClassObject:用于获得类厂指针
DllRegisterServer:注册一些必要的信息到注册表中
DllUnregisterServer:卸载注册信息
DllCanUnloadNow:系统空闲时会调用这个函数,以确定是否可以卸载DLL
DLL还有一个函数是DllMain,这个函数在COM在并不要求一定要实现它,但是在VC生成的组件中
自动都包含了它,它的作用主要是得到一个全局的实例对象.
注册表在COM中的重要作用
首先要知道GUID的概念,COM中所有的类,接口,类型库都用GUID来唯一标识,GUID是一个128位的字串,
根据特制算法生成的GUID可以保证是全世界唯一的.
COM组件的创建,查询接口都是通过注册表进行的.有了注册表,应用程序就不需要知道组件的DLL文件名,位置
只需要根据CLSID查就可以了.当版本升级的时候,只要改一下注册表信息就可以转到新版本的DLL.
在C++中,共享继承被称为"虚继承",虚继承的语法很简单,在指定基类时加上virtual关键字即可.
使用虚继承,比起单继承和多重继承有更大的实现开销,调用开销.
在虚继承时,在派生类中存在虚基类表指针.(VC++实现机制),该变量指向一个全类共享的偏移量表,表中项目
记录了对于该类而言,虚基类表指针与虚基类之间的偏移量.
struct A{
int a;
};
struct B : virtual A{
int b;
};
B对象的内在部局:
-----------------------------------------
.vbptr---->1.该指针与B对象指针的偏移 .
. 2.B对象的虚基类与该指针的偏移 .
.int b; .
.int a; .
-----------------------------------------
struct C : virtual A{
int c;
};
C对象的内存部局同B(略)
struct D : public B , C{
int d;
};
D对象的内存部局:
D*(B*)---> -----------------------------------------
.vbptr---->1.该指针与B对象指针的偏移 .
. 2.B对象的虚基类与该指针的偏移 .
.int b; .
C*---> .vbptr---->1.该指针与C对象指针的偏移 .
. 2.C对象的虚基类与该指针的偏移 .
.int c; .
.int d; .
A*---> .int a; .
-----------------------------------------
vbptr是为指针访问基类对象而设置的;
对于非虚的成员函数来说,调用哪个成员函数是在编译时,根据"->"操作符左边指针表达式
的类型静态决定的;
如果类中有虚函数,则单继承只有一个虚函数表
逗号运算符的优先级最低,算术运算符的优先级比移位运算符的优先级高;