在正式深入进行Windows程序编程之前,我们先来回顾一下Windows编程将会用到的一些C/C++初学者不太熟悉的特性可供回忆(如果你刚从c语言中出来而且自信熟悉c语言那么你可以跳过这一章的内容)
1.指针与地址
2.函数指针与回调函数
3.虚拟地址空间
1.指针与地址
在C语言当中,指针被广泛应用在需要进行内存数据管理或需要对内存进行直接读写的场合当中.
在这里我不去介绍C语言当中使用指针的最基本方法,而是介绍一个经典的函数swap(int,int)可以用于交换两个int的值.
//设定一个swap函数可以通过指针交换两个int类型的变量的值. void swap(int *a,int *b){ int tmp = *a; *a = *b; *b = tmp; } int main(){ int n = 10,m = 20; swap(&n,&m); // 可以将n,m互相交换. return n-m; }
我们观察上面的一个例子在使用&n,&m的操作将n,m的指针交给swap函数之后,swap函数并没有使用返回值而是在swap函数中直接修改了n,m的值,当然这样的函数只能应用于交换int的这种局限性场景当中,C语言对于复杂的情形(比如说非int类型)swap并没有太好的通用方法(可以使用复杂的宏),而在C++当中则可以使用模板与引用更为规范的解决这类问题.
事实上指针的应用在C语言当中比较广泛,不仅指针可以像数组一样通过指针下标进行访问,而且数组名也可以当做一个指针字面量来看待.
int main(){ char *p; char buf[32]; p=buf; //字符串,以及数组名也可以当成一种指针常量(字面量)来看待.可以直接赋值于一般指针上. p[16] = 'A';//通过指针访问数据 putchar(buf[16]);//显示被修改后的字符数组buf的第16个元素. }
指针的本质
指针占用内存的大小在某一特定的平台是固定的, 对于32位系统中就是32位,4个Byte, 而在64位系统中就是64位,则是8个Byte. (所以可以出现struct A当中包含 *pA 指针的情况,这跟结构体当中带了一个普通类型的变量没什么区别,但结构体不能直接的包含自身实体.)
struct A{ ... struct A *pA; }; //这种做法对,可以用pA指向同样类型的结构体. struct A{ ... strcut A a; }; //X错, 这种会导致循环包含自身,直接或间接包含自身会导致递归包含,编译错误. //注:指针提供了结构体访问同类型数据的一种方法.
指针的本质就是一个地址变量.不过为什么指针(Point) 并不直接叫做地址(address)呢,这一定是因为指针与地址两者概念上有一点点差别, 指针不仅包含了一个指向内存的整数地址,而且还隐含了所指向的对象的类型信息, 比如说int *pi; pi是一个指向int对象的地址值.对于编译器而讲,pi要指向的东西是什么类型是不可或缺的,而单纯的地址并没特别规定对象的类型的话可以用 void* 来表示. 故此 void* 与 各指针之间可以进行隐式转换而其他的不行. 指针的类型决定了编译器将用什么方式去对待*p读取得到的数据.
void *p = malloc(1024); //没有指定任何类型信息 int *a = p; //void* 与 int *互通. 但double*与int*之间要显式转换,否则可能警告或者错误
指针不仅功能强大(能做到一些没指针做不到的事情),而且使用的方法比较多.
如上所述指针可以像数组一样使用下标进行读写.
乃至直接对指针进行+ - , ++ -- 运算在c/c++语言当中是允许的,并且也是常见而且通用的.
int arr[16]; int *p = arr; p++; 向前移动了一个元素 即为&arr[1]; p--; 向后退 变成&arr[0]; p+10; &arr[10];
对一个指针进行加法运算(只能与整数类型进行运算),相当于下标运算的变种版,也就是说 p+n 相当于 &p[n].
p + n 的结果是p偏移了n个元素的指针(而不是地址值直接相加). 即是说int指针+1即为指针加上了4(偏移了一个int元素) ,
//在不常见的场景下,指针会被用于访问硬件读写硬件上的映射内存.
-----------
2.函数与指针与回调函数
指针不仅可以作为一个间接引用某一类型变量的地址来使用,乃至c语言提供了用指针访问函数,多维数组(这里不详谈)的方法.
...未完待续