热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Delphi指针的认识

大家都认为,C语言之所以强大,以及其自由性,很大部分体现在其灵活的指针运用上。因此,说指针是C语言的灵魂,一点都不为过。同时,这种说法也让很多人产生误解,似乎只有C语言的指针才能算指针。Basic不

大家都认为,C语言之所以强大,以及其自由性,很大部分体现在其灵活的指针运用上。因此,说指针是C语言的灵魂,一点都不为过。同时,这种说法也让很多人 产生误解,似乎只有C语言的指针才能算指针。Basic不支持指针,在此不论。其实,Pascal语言本身也是支持指针的。从最初的Pascal发展至今 Object Pascal,可以说在指针运用上,丝毫不会逊色于C语言的指针。

以下内容分为八个部分,分别是

一、类型指针的定义

二、无类型指针的定义

三、指针的解除引用

四、取地址(指针赋值)

五、指针运算

六、动态内存分配

七、字符数组的运算

八、函数指针

 

一、类型指针的定义。对于指向特定类型的指针,在C中是这样定义的:

int *ptr;

char *ptr;

与之等价的Object Pascal是如何定义的呢? 

Var

ptr : ^Integer;

ptr : ^char; 

其实也就是符号的差别而已。

二、无类型指针的定义。C中有void *类型,也就是可以指向任何类型数据的指针。Object Pascal为其定义了一个专门的类型:Pointer。于是,

ptr : Pointer;

就与C中的

void *ptr;

等价了。

三、指针的解除引用。要解除指针引用(即取出指针所指区域的值),的语法是 (*ptr)Object Pascal则是 ptr^

四、取地址(指针赋值)。取某对象的地址并将其赋值给指针变量,的语法是

ptr = &Object;

Object Pascal 则是

ptr := @Object;

也只是符号的差别而已。

五、指针运算。在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;

ptr : PChar; //PChar 可以看作 ^Char

begin

ptr := @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;

for (i=0; i<20; i++)

{

*ptr = i;

ptr++;

}

free(ptr2);

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);

end;

对于以上这个例子(无论是C版本的,还是Object Pascal版本的),都要注意一个问题,就是分配内存的单位是字节(BYTE),因此在使用GetMem时,其第二个参数如果想当然的写成 20,那么就会出问题了(内存访问越界)。因为GetMem(ptr, 20);实际只分配了20个字节的内存空间,而一个整形的大小是四个字节,那么访问第五个之后的所有元素都是非法的了(对于malloc()的参数同 样)。

七、字符数组的运算。C语言中,是没有字符串类型的,因此,字符串都是用字符数组来实现,于是也有一套str打头的库函数以进行字符数组的运算,如以下代码:

char str[15];

char *pstr;

strcpy(str, "teststr");

strcat(str, "_testok");

pstr = (char*) malloc(sizeof(char) * 15);

strcpy(pstr, str);

printf(pstr);

free(pstr);

而在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;

pstr : PChar; //Pchar 也就是 ^Char

begin

StrCopy(@str, ’teststr’); //C中,数组的名称可以直接作为数组首地址指针来用

//Pascal不是这样的,因此 str前要加上取地址的运算符

StrCat(@str, ’_testok’);

GetMem(pstr, sizeof(char) * 15);

StrCopy(pstr, @str);

Write(pstr);

FreeMem(pstr);

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;

var

fn : PVFN; 

//也可以直接在此处定义,如:fn : function (para:Integer):Integer;

hm : HMODULE;

begin

hm := LoadLibrary(’test.dll’);

fn := GetProcAddress(hm, ’Function1’);

fn(2);

FreeLibrary(hm);

end;

附: 

Delphi中指针功能非常强大,所有c中能实现的指针Delphi中都能实现上面认为Delphi指针不是强项的只是一种误解(或者对指针的机制一知半解). 由于Pascal语言的限制Delphi的指针时很多情况下需要强制类型转换. Delphi中提供了很多指针类型而且非常方便的是你可以自定义自己的指针类型.

一个经验要掌握一种数据类型并且能够灵活应用,一个比较好的办法是别考虑什么类型是什么名字而只需要考虑这种类型的变量将占用多少字节凡是字节数相同的类型都可以认为是同一类型 :-), 提供不同类型只是为了编译器能够更方便的查找错误而已比如: Integer, Pointer, PChar, TSmallPoint甚至 array [0..4] of Char你都可以把他们当成是同一类型加以使用(有了这种思路可以实现很大的程序灵活性和代码高效性). 所以我很不理解的是JAVA中不支持指针(因此我也认为用JAVA绝对不可能写出很高效的程序而且会有很多C/C++/DELPHI中用一句话可以完成的工作在JAVA中需要用一个复杂过程消耗很多额外内存才能达到相同目的). 就事论事根据你的问题在Delphi中和C中的解决方案没什么两样.

Var

a: Pointer;   // 或者任何其他指针类型

begin

GetMem(a, 10); // 分配10字节

PInteger(a)^ := Integer(Form1);  // form1(其实Delphi中所有的类都可以认为是指针)

// 保存到a[0..3]

// 这里是和C的区别, Delphi中需要进行指针类型转换

// 主要是为了"欺骗"编译器免得程序无法编译通过.

(PChar(a)+SizeOf(Integer))^ := ’B’; // a[4]中保存一个字符’B’

....

end; 

:

VAR  

P:^char;  

i:integer;  

s:string;  

begin  

p:=@listview.selected.data;  

for   i:=0   to   200   do  

begin  

s:=s+^p;   //出错  

inc(p);  

end;  

showmessage(s);  

end;

 


推荐阅读
  • Objective-C 中的委托模式详解与应用 ... [详细]
  • 如何在Java中使用DButils类
    这期内容当中小编将会给大家带来有关如何在Java中使用DButils类,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。D ... [详细]
  • 在尝试对 QQmlPropertyMap 类进行测试驱动开发时,发现其派生类中无法正常调用槽函数或 Q_INVOKABLE 方法。这可能是由于 QQmlPropertyMap 的内部实现机制导致的,需要进一步研究以找到解决方案。 ... [详细]
  • 本文详细介绍了MySQL数据库的基础语法与核心操作,涵盖从基础概念到具体应用的多个方面。首先,文章从基础知识入手,逐步深入到创建和修改数据表的操作。接着,详细讲解了如何进行数据的插入、更新与删除。在查询部分,不仅介绍了DISTINCT和LIMIT的使用方法,还探讨了排序、过滤和通配符的应用。此外,文章还涵盖了计算字段以及多种函数的使用,包括文本处理、日期和时间处理及数值处理等。通过这些内容,读者可以全面掌握MySQL数据库的核心操作技巧。 ... [详细]
  • 在处理数据库中所有用户表的彻底清除时,目前尚未发现单一命令能够实现这一目标。因此,需要采用一种较为繁琐的方法来逐个删除相关表及其结构。具体操作可以通过编写PL/SQL脚本来实现,该脚本将动态生成并执行删除表的SQL语句。尽管这种方法相对复杂,但在缺乏更简便手段的情况下,仍是一种有效的解决方案。未来或许可以通过数据库管理工具或更高版本的数据库系统提供更简洁的处理方式。 ... [详细]
  • 在软件开发过程中,经常需要将多个项目或模块进行集成和调试,尤其是当项目依赖于第三方开源库(如Cordova、CocoaPods)时。本文介绍了如何在Xcode中高效地进行多项目联合调试,分享了一些实用的技巧和最佳实践,帮助开发者解决常见的调试难题,提高开发效率。 ... [详细]
  • 开发技巧:在Interface Builder中实现UIButton文本居中对齐的方法与步骤
    开发技巧:在Interface Builder中实现UIButton文本居中对齐的方法与步骤 ... [详细]
  • 本文介绍了如何利用 Delphi 中的 IdTCPServer 和 IdTCPClient 控件实现高效的文件传输。这些控件在默认情况下采用阻塞模式,并且服务器端已经集成了多线程处理,能够支持任意大小的文件传输,无需担心数据包大小的限制。与传统的 ClientSocket 相比,Indy 控件提供了更为简洁和可靠的解决方案,特别适用于开发高性能的网络文件传输应用程序。 ... [详细]
  • 本文深入探讨了Java多线程环境下的同步机制及其应用,重点介绍了`synchronized`关键字的使用方法和原理。`synchronized`关键字主要用于确保多个线程在访问共享资源时的互斥性和原子性。通过具体示例,如在一个类中使用`synchronized`修饰方法,展示了如何实现线程安全的代码块。此外,文章还讨论了`ReentrantLock`等其他同步工具的优缺点,并提供了实际应用场景中的最佳实践。 ... [详细]
  • 在当前的软件开发领域,Lua 作为一种轻量级脚本语言,在 .NET 生态系统中的应用逐渐受到关注。本文探讨了 Lua 在 .NET 环境下的集成方法及其面临的挑战,包括性能优化、互操作性和生态支持等方面。尽管存在一定的技术障碍,但通过不断的学习和实践,开发者能够克服这些困难,拓展 Lua 在 .NET 中的应用场景。 ... [详细]
  • 本文详细介绍了在CodeUp平台中实现大数进制转换的技术方法。具体而言,该问题要求将一个最多包含30位数字的十进制非负整数转换为二进制表示。输入数据包含多行,每行包含一个不超过30位的十进制非负整数。通过高效的算法设计,确保了大数转换的准确性和性能。 ... [详细]
  • 在 Linux 环境下,多线程编程是实现高效并发处理的重要技术。本文通过具体的实战案例,详细分析了多线程编程的关键技术和常见问题。文章首先介绍了多线程的基本概念和创建方法,然后通过实例代码展示了如何使用 pthreads 库进行线程同步和通信。此外,还探讨了多线程程序中的性能优化技巧和调试方法,为开发者提供了宝贵的实践经验。 ... [详细]
  • 具备括号和分数功能的高级四则运算计算器
    本研究基于C语言开发了一款支持括号和分数运算的高级四则运算计算器。该计算器通过模拟手算过程,对每个运算符进行优先级标记,并按优先级从高到低依次执行计算。其中,加减运算的优先级最低,为0。此外,该计算器还支持复杂的分数运算,能够处理包含括号的表达式,提高了计算的准确性和灵活性。 ... [详细]
  • 无论是计算机专业学生还是非计算机专业的学习者,在掌握C语言的过程中可能会遇到诸多挑战,不清楚从何入手。为此,本文系统地梳理了2019年福建省C语言的核心知识点,并结合最新的技术进展进行了详细总结,旨在为初学者提供全面的学习指导。文章不仅涵盖了基础语法和数据结构,还深入探讨了指针、内存管理和算法优化等高级主题,帮助读者快速提升编程能力。 ... [详细]
  • 2012年9月12日优酷土豆校园招聘笔试题目解析与备考指南
    2012年9月12日,优酷土豆校园招聘笔试题目解析与备考指南。在选择题部分,有一道题目涉及中国人的血型分布情况,具体为A型30%、B型20%、O型40%、AB型10%。若需确保在随机选取的样本中,至少有一人为B型血的概率不低于90%,则需要选取的最少人数是多少?该问题不仅考察了概率统计的基本知识,还要求考生具备一定的逻辑推理能力。 ... [详细]
author-avatar
阿悅11
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有