作者zlw (www.eJob.gov.tw)
看板Programming
标题Re: [问题][C语言] pointer的问题
时间Sun Jun 14 17:31:28 2009
※ 引述《hansi (Jamie)》之铭言:
: 请问以下程式的问题是那边呢?
: 1.
: #include <stdio.h>
: void main(void)
: {
: char *pt;
: *pt = 'a';
: getchar();
: }
: 用了Devcpp 跟visual studio express 2008 compile都会过
: 不过run的时候就crash了
: 後来改成
但是应该有 warning,比如 VC 应该是会给:
warning C4700: 使用了未初始化的区域变数 'pt'
就跟你写
int i;
prinitf("i = %d", i);
一样,还没给过任何值就在取值。
: 2.
: Char *pt,ch;
: ch = 'a';
: pt = &a;
: getchar();
: 这样才可以
: 想请教一下为何不能像1这样使用呢?
: 因为手边有两本c的书(蛮老的)里面都有1这样的例子,
: eg: int *pt = 0; 不过我run这个也是会crash
: 一开始我以为是电脑有问题,後来试了其他两台也一样
也许是因为你用的电脑上面,刚好有个作业系统,刚好有在管理记忆体,刚好把记忆体
位址划分成 某段位址(假设是0~127) 唯读,除此之外其他位址可读取及写入。
然後你的 pt 因为你没有给任何值,所以编译器让 pt 随便得到某个值,假设是0。
因为 0 属於唯读的区域
然後你 *pt = 'a'; 代表把 'a' 这个 byte 写入到0去,但这段程式码在程式执行时
才会跑到,所以你通过了编译,但执行时才被抓包。
但是你用的书,刚好他们那个时代根本没有在管记忆体位址哪些只能唯读、哪些能读写
(DOS真实模式时代?)
--
补充一下流程,没全部查证,可能有误
假设你有个程式档 1.c 里写
char *pt;
pt = 'a'; //如果你编译成C语言,只会有警告,但是编译成C++,就会直接给编译错误
pt = "a"; //电脑会夸奖你...其实不会
'a' 编译器会把他转成一个整数数值,也就是 ASCII code 对应 a 的整数 0x61。
所以 pt = 'a'; 跟 pt = 0x61; 是一样的语意
"a" 编译器会把他当作一个常数字串,总共有 2 bytes 这麽大,数值是 0x6100
因为这两个 byte 彼此是独立的个体,所以不需要考虑什麽 endian 的议题。
然後编译器会把 0x6100 存在他生成的档案 1.obj 里面,在里面会分成好个区域
会有其中一个被叫 .rdata 的区域 (section),里面的内容就拿来放这个常数字串
的值也就是放 0x6100
(0x61 会在记忆体位址比较低的那一边,0x00会紧邻在高位址的旁边)
然後会有连结器,把1.obj跟其他目的档连结在一起,产生出 1.exe 这个执行档
当你点两下执行 1.exe 时,作业系统就把1.exe的内容搬到主记忆体去。
也就是说现在常数字串"a"也存到主记忆体去了,你想要找他就要透过主记忆体的
位址去找,而不是打开磁碟里的档案1.obj去找。
而为了让这个字串不是光放着没人用,在 pt = "a"; 这里时,就会传回这个常数字串
的记忆体位址 (rvalue) 给变数 pt 去存放。
那这是在编译时就要决定的位址,所以这里给的是虚拟的位址假设就是「0跟1」,
按照惯例都是用比较低的记忆体位址当代表,也就是用0当地址代表。
(可以用IDE下中断点来观察pt存放了什麽位址)
当作业系统执行1.exe时,才再做记忆体位址重定位的功能。
比如OS把你载入到位址200以後的一段空间,则pt的位址就会被重定位为200。
以後只要执行 cout << pt; 就能透过 pt 里面存的记忆体位址读出这个常数字串来。
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 124.8.131.6
※ 编辑: zlw 来自: 124.8.131.6 (06/14 17:33)
1F:推 chrisdar:\0 123.195.88.23 06/14 19:29