一点看法,也不知道对不对!来讨论一下,无论对错都给分!

zwjchina 2002-10-16 03:42:31
PChar的修改问题:

在使用StrMove和Move等过程中经常会产生问题。例如以下代码
var
Ps1,Ps2:PChar;
begin
Ps1 := 'ABCDEF';
Ps2 := 'GHIJKL';
Move(Ps1[0], Ps2[0], 3); //Error
//Ps1[0] := 'Z'
end;

以上代码初看没有什么问题,然而实际运行发现在Move句出错了!而且对于//Ps1[0] := 'Z' 这句也会出错。

考察String的使用
var
Ps1,Ps2:String;
begin
Ps1 := 'ABCDEF';
Ps2 := 'GHIJKL';
Move(Ps1[1], Ps2[1], 3);
//Ps1[1] := 'Z'
end;
这里却表现十分正常。

那么原因在哪里呢?

分析: 在第一段代码中,Ps1 := 'ABCDEF'此句的赋植操作是个单纯的指针操作。即将存放'ABCDEF'的地址赋值给Ps1,但是'ABCDEF'的地址空间是在进程的地址空间,通俗的说就是和执行代码在同一空间。而不是在进程分配的堆的地址空间。由于进程的地址空间是受系统保护的,可读不可写。因此,对这个地址进行写就会出错。因此,考虑改成以下代码,运行正常:
var
Ps1,Ps2:PChar;
begin
Ps1 := 'ABCDEF';
GetMem(Ps2,6)
Move(Ps1[0], Ps2[0], 3);
end;
原因很简单,因为GetMem为Ps2在堆中开辟了空间
而第二段代码中,Ps1 := 'ABCDEF'由于Ps1是String类型,它的赋值操作其实是先开辟一段空间,然后把串复制到该地址空间。因此,在后面的Move操作就完全没问题。


以上分析提到了进程代码运行修改问题,可参看ReadProcessMemory WriteProcessMemory以及VirtualProtect等API函数,特别是VirtualProtect

2002.6.28 周文杰
...全文
81 67 打赏 收藏 转发到动态 举报
写回复
用AI写文章
67 条回复
切换为时间正序
请发表友善的回复…
发表回复
lizongqi 2003-05-05
  • 打赏
  • 举报
回复
failer 2003-01-16
  • 打赏
  • 举报
回复
gz
角落的青苔 2002-10-18
  • 打赏
  • 举报
回复
学习……
ruihuahan 2002-10-18
  • 打赏
  • 举报
回复
UP
日总是我哥 2002-10-18
  • 打赏
  • 举报
回复
我有了新的想法!

可以另找空间讨论!!!
是这样的`~~`~
type
PChar = ^Char
kbm1422 2002-10-18
  • 打赏
  • 举报
回复
收益非浅
zwjchina 2002-10-18
  • 打赏
  • 举报
回复
结了!
kkong2000 2002-10-18
  • 打赏
  • 举报
回复
还没有结吗?快结吧。
有谁去帮忙看看我的提问啊,在EXECL中插入文字图片的那个,谢谢。

zwjchina 2002-10-18
  • 打赏
  • 举报
回复
to copy_paste(木石三)

对于
const
Temp1: array[0..12] of Char = 'Hello world!'#0;
Temp2: array[0..12] of Char = 'aaaaaaaaaaaa'#0;
我的看法是;
Temp1, Temp2是常量,它在堆栈中,但是'Hello world!'是值常量,它在程序代码的空间中
对于
var
p: pchar;
begin
p := 'ABCD';这句中'ABCD'在程序代码中,p被赋值是程序代码中的某个地址,所以我认为我最上面的看法应该是对的!
copy_paste 2002-10-18
  • 打赏
  • 举报
回复
老兄,说了半天,其实我对:
P := 'abcd';
这种情况是比较同意CoolSlob 的说法,就是“迷茫指针”,也就是你所说受进程空间保护,ReadOnly = True,只不过CoolSlob说出这种操作概念是“迷茫指针”,而我是没有看太书,所以有些东西知道不行,但却说不出来,明白了吧(你不是要我把老底给露出来了),哈哈。


另荐篇文章:
http://www.csdn.net/Develop/read_article.asp?id=10124

这里的评论非常精彩,虽然和你所说的情况不一样,但很有意思。各位不妨一看
jxd_2001 2002-10-16
  • 打赏
  • 举报
回复
Move procedure's help is very good
atuchina 2002-10-16
  • 打赏
  • 举报
回复
好历害!
gaoem 2002-10-16
  • 打赏
  • 举报
回复
up
日总是我哥 2002-10-16
  • 打赏
  • 举报
回复
全剧终
copy_paste 2002-10-16
  • 打赏
  • 举报
回复
CoolSlob()
不能是堆栈??
常量是不是堆栈?
为什么这样的代码可以。
const
Temp1: array[0..12] of Char = 'Hello world!'#0;
Temp2: array[0..12] of Char = 'aaaaaaaaaaaa'#0;

var
P1, P2: PChar;
begin
P1 := @Temp1;
P2 := @Temp2;
Move(P1^, P2^, Sizeof(Temp1));
ShowMessage(P1);
Showmessage(P2);
end;
copy_paste 2002-10-16
  • 打赏
  • 举报
回复
wjlsmail(计算机质子)

PChar类型能直接转成string,但string转成PChar要进行强制转,即:
P := PChar(S);
or
P := @S[1]; //必须Length(S)>0

string我们其它可以理解一个特殊的类,或结构也行,它里面一个字符数组,S[1]取得就是数组的第一位。
当我们用PChar或Pointer转一个string时,它其实是将字符数组的头字符指针给拿过来了。而不是@S的值,

我说明白没(我挠了挠头)
wjlsmail 2002-10-16
  • 打赏
  • 举报
回复
就连
label1.Caption:=Format('%p',[Pointer(s)]);
label2.Caption:=Format('%p',[p]);
都不同,真不知道是怎么回事

日总是我哥 2002-10-16
  • 打赏
  • 举报
回复
[From Kingron:]

  Move的第二个参数必须是变量,也就是说,不能是堆栈,必须要有一块内存!因此ps2必须申请内存快,而ps1:='abcd'这种方式是不会分配内存的,使用Pchar都必须显式分配内存,虽然Delphi可以在作为常量使用的时候,可以不必要分配,但是可能出现潜在的问题。另外说一句,Move这样的函数,没有进行内存检查,可能造成覆盖或者缓冲区溢出。
wjlsmail 2002-10-16
  • 打赏
  • 举报
回复
p:Pchar;
s:String;

s:='1234';
P:='1234' //都可以

但是:
s:='1234'
p:=s; //就不行

真不知道Delphi中的指针是怎样约定的 您给分析分析好吗?
copy_paste 2002-10-16
  • 打赏
  • 举报
回复
move(ps1, ps2, 3),做什么用,
这样的做法,就是将ps1地址的值(共4字节)的前三个字节copy给ps2,ps2的第四个字节的值不变,变成什么了,什么也不是

应该是:
move(ps1, ps2, sizeof(ps1));
但这句话,做的是什么?相当于: ps2 := ps1;这种操作。

所以如果用Move的操作指针时,只是操作指针所指的内容,而不是指针本身(一点用都没)
加载更多回复(47)

5,386

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧