c and pointer care

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是为指针访问基类对象而设置的;

对于非虚的成员函数来说,调用哪个成员函数是在编译时,根据"->"操作符左边指针表达式
的类型静态决定的;
如果类中有虚函数,则单继承只有一个虚函数表

逗号运算符的优先级最低,算术运算符的优先级比移位运算符的优先级高; 

C语言中的指针运算是用来对指针进行加减操作的。指针在C语言中被用来表示变量的地址。通过指针运算,我们可以对指针进行数学运算,以便在内存中移动或定位数据。指针运算主要包括两种类型:指针的自增运算和指针的自减运算。 指针的自增运算是通过将指针的值增加一个特定的偏移量来实现的。例如,如果一个指针p指向一个整型数组的第一个元素,那么p++将使p指向数组的下一个元素。同样,指针的自减运算将指针的值减少一个特定的偏移量,即p--将使p指向数组的前一个元素。 除了自增和自减运算之外,指针还可以进行加法运算和减法运算。例如,p + n将使指针p增加n个偏移量,指向数组中的第n个元素。同样,p - n将使指针p减去n个偏移量,指向数组中的第n个元素。需要注意的是,指针只能与整数进行加减运算,而不能进行乘法和除法运算。 指针运算在编程中非常有用,例如在处理数组和字符串时。通过使用指针运算,可以更方便地访问数组或字符串中的元素,从而提高程序的效率和性能。指针运算还可以用于遍历和操作复杂的数据结构,如链表和树。但是需要注意的是,在进行指针运算时,要确保指针指向的内存是有效的,否则可能会导致程序崩溃或产生其他错误。因此,在进行指针运算之前,应该先检查指针的有效性,以避免潜在的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值