zhangxun0712 发表于 2010-10-12 14:07:08

C语言灵魂的请教

char *p1;
char *p2;
p2 = *(char **)p1;

请问指针p1与p2是一样吗?

我的理解:首先(char **)p1 把p1转化为字符型的二级指针,再通过最前面的*转化为一级指针,也就可以付值给p2了。给感觉就好像是p2 = p1;可现实并不是这么简单。还请大侠指点迷津。先谢了!

Microchen2008 发表于 2010-10-12 14:12:42

不是p2=p1;
个人认为应该是将p1地址中的内容给p2

楼下继续

dr2001 发表于 2010-10-12 14:35:55

实质是p2 = * p1
(char **)是为了类型匹配,即char * = *(char **)。

takashiki 发表于 2010-10-12 14:39:08

当然不一样。

调试一下什么都明白了,主要注意一下p1、p2、*p1、&p2的值。
当然,p2 = *(char **)p1; 这句本身就是有问题的,调试不见得会通过(编译是没有问题的),可能非法访问内存。

liaowei 发表于 2010-10-12 16:33:34

p1本来是一个地址,他可以是8、16或32位(假设是16位,假设为0x1234),而指向的是8位,假设位0x56
(char **)p1,是把一个(char *)型的指针强制转换为(char **)p1,值还是0x1234,指向的就不是char了,而是一个指针,指针是16位的,就只能是指向0x56和后面一个未知的数了。
现在你硬要来个*(char **)p1,那没办法,给你取数了,只不过取的不是8位了(因(char **)p1的值是16位的),而是16位的,所以就取了0x56和后面一个数,0x56和后面一个数组成一个指针给p2

liaowei 发表于 2010-10-12 16:39:39

回复【2楼】dr2001
实质是p2 = * p1
(char **)是为了类型匹配,即char * = *(char **)。
-----------------------------------------------------------------------

谁说的char * = *(char **)?注意(char **)只不过是转换,而不是取址

zhangxun0712 发表于 2010-10-12 16:54:13

回复【3楼】takashiki 岚月影
当然不一样。
调试一下什么都明白了,主要注意一下p1、p2、*p1、&p2的值。
当然,p2 = *(char **)p1; 这句本身就是有问题的,调试不见得会通过(编译是没有问题的),可能非法访问内存。
-----------------------------------------------------------------------

我这里发帖请教的就是想搞清楚这个“当然”不一样了。肯定是主要注意一下p1、p2、*p1、&p2的值,但主要这个转换过程是怎么样的?还请takashiki 大侠能不能细说?
另外 p2 = *(char **)p1;这句话有没有问题不不知道,在VC++2010,Win-Tc ,MDK3.5,都试过没有编译问题,也没有警告的。

stm32w 发表于 2010-10-12 16:57:47

假设char * 与int占用存储空间大小一样

p2 = *(char **)p1;   
可理解为:

p2= (char *)(*(int *)p1)

dr2001 发表于 2010-10-12 17:05:37

回复【6楼】zhangxun0712
-----------------------------------------------------------------------

不严格的说,强制类型转换就是告诉编译器:把这个变量在这里临时看做这个类型,然后完成表达式计算。

研究代码执行的操作的时候,
可以首先忽略强制类型转换部分,去看代码执行什么样的操作,如直接赋值,取地址,取值,etc;
然后,依据强制类型转换后的类型,确定具体执行什么样的操作。

zhuhanliang 发表于 2010-10-12 17:09:45

mark

takashiki 发表于 2010-10-12 17:15:57

不管对p1、p2、*p1、&p2中哪一个指针来说,它们底层都是一个整型的数值。那么就有:

p2 = *(char **)p1;这种强制转换并没有改变数据,也就是(char**)p1和p1的底层是一样的,那么p2只不过是对p1取值而已。因此:
p2 = *p1
p1 = &p2

p2 = *(char **)p1;可能存在运行时问题的,编译可以通过,但运行就不见得了。
比如,在VC上,p1 = NULL;这句没有问题的语句,在经过*(char**)p1之后就变成对0地址取值了,就会因为内存非法访问而出错。一般来说,对于一级指针,我们总是尽量避免让它指向非法地址;而二级指针则应该避免它自身以及它指向的值指向非法地址,比较容易出错一些,将一级指针强制转换成二级指针时更容易出错。

VC++2010,Win-Tc ,MDK3.5,都很好软件调试的,设个断点,监视一下这些就行了。在PC上,至少0地址是被保护的,取它的值会出错;ARM上,访问不存在的内存应该会引起数据访问异常。

看一下VC下面出错的代码:
#include "stdafx.h"

int main(int argc, char* argv[])
{
        char *p1 = 0;                           //没有用的指针指向0地址,因为p1可能会随时改变,这里我就特意赋值0了
        char *p2;
        p2 = *(char **)p1;                        //非法访问p1地址了,调试时会产生异常的
        printf("Hello World!\n");
        return 0;
}

takashiki 发表于 2010-10-12 17:21:27

回复【8楼】dr2001
回复【6楼】zhangxun0712
-----------------------------------------------------------------------
不严格的说,强制类型转换就是告诉编译器:把这个变量在这里临时看做这个类型,然后完成表达式计算。
研究代码执行的操作的时候,
可以首先忽略强制类型转换部分,去看代码执行什么样的操作,如直接赋值,取地址,取值,etc;
然后,依据强制类型转换后的类型,确定具体执行什么样的操作。

-----------------------------------------------------------------------

这个确实太不严格了……不要这么理解。
double<->float,double<->int及所有int兼容类型,float<->int及所有int兼容类型都改变了变量本身的值。
“把这个变量在这里临时看做这个类型,然后完成表达式计算。”这个得用联合体完成。

hemjidn 发表于 2010-10-12 18:40:02

先看看
char��*p1;
char��*p2;
p2��=��*p1;
你说p1=p2么?当然不一样这个不用解释了吧
但这时编译器就告诉你类型不匹配了啥办?
于是就有了
char��*p1;
char��*p2;
p2��=��*(char��**)p1;
强制类型匹配,编译是通过了但由于乱用指针会导致运行时非法读取内存。

liangyurongde 发表于 2010-10-12 19:57:44

mark

zhangxun0712 发表于 2010-10-13 08:45:14

谢谢各位大侠的热心解答与指导,特别是takashiki。跟据你说的,我又回去看了看,指针,二级指针,指针数组,基本上是懂了。
我给的例子不全导制分析出现了一点点偏差。情况是当*p1指向一个指针型的数组的地址时,如char *str[]={"one","two","three"};时p1指向的是字符串"one"地址的地址,而p2则指向的是存取字符串"one"的首地址,输出printf("%s",p2)为one. 表达能力不好,不知说清楚了没有。

t2397362 发表于 2010-10-13 09:14:08

指针也是变量,自己也有地址

h85968099 发表于 2010-10-13 09:14:19

p2 = *(char **)p1;   
p1是什么,就是一个地址,一串数字,这个不关键,主要还是要把这串数字转化成什么的数据类型
页: [1]
查看完整版本: C语言灵魂的请教