在学习Delphi的时候,一个很好的建议是和C/C++去类比着学习,从指针,到内存管理,到数组,到面向对象……各个方面,都是有不少能够类似和或者也有不一样的方,类比着学习,一方面加深对Delphi的理解,一方面加深对C/C++的理解,一方面加深对计算机系统的理解,一方面加深对面向对象的理解……由1向多能够很方便的扩展,并且彻底不冲突,彻底是互相促进的过程。因此学习要有技巧!数组
你们都认为,C语言之因此强大,以及其自由性,很大部分体如今其灵活的指针运算上。所以,说指针是C语言的灵魂,一点都不为过。同时,这种说法也让不少人产生误解,彷佛只有C语言的指针才能算指针。Basic不支持指针,在此不论。其实Pascal语言自己也是支持指针的。从最初的Pascal发展至如今的Object Pascal,能够说在指针运算上,丝绝不会逊色于C语言的指针函数
对于指向特定类型的指针,在C中是这样定义的学习
int * iPtr; char *cPtr;
与之等价的Object Pascal是如何定义的呢?指针
var iPtr : ^Integer; cPtr : ^char; //注意 ^ 符号是放在类型的前面
其实也就是符号的差异而已code
C中有 void * 类型,也就是能够指向任何类型数据的指针。Object Pascal为其定义了一个专门的类型:Pointer。因而Delphi的对象
ptr : Pointer;
等价于C的内存
void *ptr;
要解除指针引用(即取出指针所指向区域的值),C的语法是字符串
*ptr
而Object Pascal的语法是编译器
ptr^ //注意 ^ 符号是放在指针变量的后面
取某对象的地址而且将其赋值给指针变量,C的语法是string
int i = 4; int *iPtr = &i;
而Object Pascal的语法是
i : Integer; iPtr : ^Integer; iPtr := @i;
也只是符号的差异而已
在C中,能够对指针进行移动的运算,如
char a[20]; char *ptr = a; ptr++; ptr +=2;
当执行ptr++时候,编译器会产生让ptr前进sizeof(char)步长的代码,以后,ptr将指向a[1]。ptr+=2;这句使得ptr前进两个sizeof(char)大小的步长。一样,咱们来看一下Object Pascal中如何实现
var a : array[1..20] of Char; //注意Delphi里面定义数组变量的这一种方法 ptr : ^char; begin ptr := @a; //此处不一样于C,C中数组名就是指针, //而在Delphi中还须要使用取数组名地址的语法:@a Inc(ptr); //这句等价于C的ptr++ Inc(ptr, 2); //这句等价于C的ptr+=2; end;
在C中,使用malloc()库函数分配内存,free()函数释放内存。如这样的代码:
int *ptr, *ptr2; int i; ptr = (int *)malloc(sizeof(int) * 20); ptr2 = ptr; //由于后来可能要对ptr指针进行操做,为了保存分配的内存空间的地址, //因此要用新的指针 ptr2来记录分配的内存地址,保证后面能够在使用完 //内存后进行free,而不会形成内存泄露 for(i=0; i<20; i++){ *ptr = 1; ptr++; } free(ptr2); ptr2 = NULL;
在Object pascal中,动态内存分配的函数是GetMem(),与之对应的释放函数是FreeMem(),(传统的Pascal中获取内存的函数是New()和Dispose(),可是New()只能获取对象的单个实体的内存大小,没法取得连续的存放多个对象的内存块)。所以,与上面那段的C代码等价的Object Pascal的代码是:
var ptr, ptr2 : ^Integer; i : Integer; begin GetMem(ptr, sizeof(Integer)*20); //这句话等价于C的ptr = (int *)malloc(sizeof(int) * 20); ptr2 := ptr; //保留原始指针的位置 for i:=0 to 19 do begin ptr^ :=i; //注意指针的解除引用的语法格式 Inc(ptr); end; FreeMem(ptr2); ptr2:= nil; end.
对于上面的例子(不管是C的仍是Object Pascal的),都须要注意一个问题,就是分配内存的单位是字节(BYTE),所以在使用GetMem时候,其第二个参数若是想写成20,那么就会出问题(内存访问越界)。由于GetMem(ptr, 20);实际上只分配了20个字节的内存空间,而一个整型的大小是4字节,那么访问第5个以后的全部元素都是非法的了(对于malloc()参数也是同样)
C语言中,是没有字符串类型的,所以,字符串都是用字符数组实现的,因而也就有了一套str 开头的库函数用于进行字符数组的运算,如如下的代码
char str[15]; char *ptr; strcpy(str, "teststr"); strcat(str, "_testok"); ptr = (char *)malloc(sizeof(char) * 15); strcpy(ptr, str); printf(ptr); free(ptr); ptr = NULL;
而在Object Pascal中,有了String类型,所以能够很方便的对字符串进行各类运算。可是,有时候咱们的Pascal代码须要与C进行交互(好比:用Object Pascal的代码调用C写的DLL或者用Object Pascal写的DLL准备容许用C写客户端的代码)的话,就不能使用string类型了,而必须使用两种语言通用的字符数组。其实,Object Pascal提供了彻底类似C的一整套字符数组的运算函数,以上的那段代码的Object Pascal的版本是
var str : array[1..15] of char; ptr : ^char; begin StrCopy(@str, 'teststr'); //在C中,数组的名称能够直接做为数组的首地址指针用, //可是在Delphi里面要注意,要在str前面加上取地址运算符 StrCat(@str, '_testok'; GetMem(ptr, sizeof(char) * 15); StrCopy(ptr, @str); Write(ptr); FreeMem(ptr); ptr:= nil; end;
在动态调用DLL的函数时候,就会用到函数指针。假设用C写一段代码以下:
typedef int (*PVFN)(int); //定义函数指针类型 int main(){ HMODULE hModule = LoadLibrary("test.dll"); PVFN pvfn = NULL; pvfn = (PVFN)GetProcAddress(hModule, "Function1"); pvfn(2); FreeLibrary(hModule); }
C语言中定义函数指针的类型typedef代码的语法有些晦涩,而一样的代码在Object Pascal中却很是易懂
type PVFN = Function(para : Integer) : Integer; //这里定义的PVFN是一个类型,而不是一个实例 var fn : PVFN; //要使用PVFN类型的函数指针,就须要生成一个实例 //或者能够直接定义 fn : function(para : Integer) : Integer; hm : HMOUDLE; begin hm := LoadLibrary("test.dll"); fn := GetProcAddress(hm, 'Function1'); fn(2); FreeLibaray(hm); end;
Delphi的指针功能很是强大,全部C中可以实现的指针Delphi都能实现,上面认为Delphi指针不是强项的只是一种误解(或者对指针的机制只知其一;不知其二)
因为Pascal语言的限制,用Delphi的指针不少状况下须要强制类型转换,Delphi中提供了不少指针类型,并且很是方便的是你能够自定义本身的指针类型
一个经验是:要掌握一种数据类型而且熟练灵活应用,一个比较好的办法是别考虑什么类型是什么名字,而只须要考虑这种类型的变量将占用多少字节。凡是字节数亩相同的数据类型均可以认为是同一种类型,提供不一样的类型只是为了编译器可以更方便的查找错误而已,好比:Integer、Pointer、PChar、TSmallPoint甚至是attay[0..3] of char你均可以把他们当成是同一类型加以使用(有了这种思路,能够实现很大的程序灵活性的代码高效性)