注册 登录
编程论坛 C++教室

[求助]二级指针

wangxiang 发布于 2006-04-20 11:41, 4254 次点击

#include <iostream>
using namespace std;
void f(int ** p)
{
cout<<"*p = "<<(long)*p<<endl;
*p++;
cout<<"*p = "<<(long)*p<<endl;//这里为什么输出的是值49,而上面输出的是地址呢?

}
int main()
{
int i =49;
int * ip = &i;
cout<<"ip = "<<(long)ip<<endl;
f(&ip);
return 0;
}

52 回复
#2
踏魔狼2006-04-20 12:44

**p指向*p,*p指向&i.
void f(int ** p)
{
//这里的也就是*(**p),就相当于:
//void f(int *p)
//{
//cout<<"p = "<<(long)p<<endl;
//自然值就是地址了。

cout<<"*p = "<<(long)*p<<endl;
//*p++这个首先++后到*取指针值,p++就会从**p变为*p,就相当于:
//void f(int *p)
//{
//cout<<"*p ="<<(long)*p<<endl;
//自然就是49了。

*p++;
cout<<"*p = "<<(long)*p<<endl;

}

#3
wangxiang2006-04-20 12:59

very thank you

#4
wangxiang2006-04-20 15:07
//*p++这个首先++后到*取指针值,p++就会从**p变为*p,
这一句还是理解不了
#5
woodhead2006-04-20 18:30

我估计
int i
int * ip
是连续存储的,p指向ip,p++后指向i了。

#6
踏魔狼2006-04-20 20:39
我明明又发了一次说明,怎么不见了呢!!真是奇怪了。
#7
wangxiang2006-04-20 21:29
以下是引用Bjarne在2006-4-20 20:39:00的发言:
我明明又发了一次说明,怎么不见了呢!!真是奇怪了。

没有啊,你能说明一次吗?

#8
wangxiang2006-04-20 21:31
以下是引用woodhead在2006-4-20 18:30:00的发言:

我估计
int i
int * ip
是连续存储的,p指向ip,p++后指向i了。



我也不知道

#9
踏魔狼2006-04-20 22:19
No!No!
not is是连续存储的.
#10
gototheworld2006-04-20 22:28
以下是引用Bjarne在2006-4-20 20:39:00的发言:
我明明又发了一次说明,怎么不见了呢!!真是奇怪了。

[此贴子已经被作者于2006-4-20 22:33:04编辑过]

#11
gototheworld2006-04-20 22:35

在我看来LZ的这个程序只是特殊情况

#12
踏魔狼2006-04-20 22:56
听我一一道来:
首先这不是连续存储的,从理论上你可以把它理解为是连续存储的,但实际物理上它不是连续存储的。
*p是指向i的地址,也就是&i.(假设地址为11111111)
**p又是指向*p的地址。(假设地址为22222222)
void f(int ** p)
{
所以一句*p也就为&i.
cout<<"*p = "<<(long)*p<<endl;
最重要是这一句,
首先++,也就为得到**p所指向的地址,为*p.
然后再用指针取值符*,取得*p的值。也就为*(*P),也就等于49.

*p++;
cout<<"*p = "<<(long)*p<<endl;
}

楼上那位仁兄说这是特殊情况。也太不负责任了吧。
#13
woodhead2006-04-21 11:18

物理上不是,但在虚地址空间可能是连续的。
试试这个。

#include <iostream>
using namespace std;

void f(int ** p)
{
cout<<"*p = "<<(long)*p<<endl;
*p++;//这个解引用没用,去掉也可以。
cout<<"*p = "<<(long)*p<<endl;

}
int main()
{
int i =49;
int j =50;//加一句。
int * ip = &i;
cout<<"ip = "<<(long)ip<<endl;
f(&ip);

system("pause");
return 0;
}

#14
踏魔狼2006-04-21 11:21
我说的不是连续存储是指指针的存储。
#15
柳儿2006-04-21 11:35
以下是引用Bjarne在2006-4-20 22:56:00的发言:
听我一一道来:
首先这不是连续存储的,从理论上你可以把它理解为是连续存储的,但实际物理上它不是连续存储的。
*p是指向i的地址,也就是&i.(假设地址为11111111)
**p又是指向*p的地址。(假设地址为22222222)
void f(int ** p)
{
所以一句*p也就为&i.
cout<<"*p = "<<(long)*p<<endl;
最重要是这一句,
首先++,也就为得到**p所指向的地址,为*p.
然后再用指针取值符*,取得*p的值。也就为*(*P),也就等于49.

*p++;
cout<<"*p = "<<(long)*p<<endl;
}

楼上那位仁兄说这是特殊情况。也太不负责任了吧。

我无法理解这一句“最重要是这一句,首先++,也就为得到**p所指向的地址,为*p.”
确实是先++,但是结果是p向后移动了一个int类型的大小。
这个程序确实特殊。因为内存分配连在一起了。如果在int i的定义后插入其他类型的变量定义,这个程序的执行结果就会不同了吧。

#16
踏魔狼2006-04-21 13:09
天啊。。。怎么个个都对指针理解这么。。。。。!!!!
#17
wangxiang2006-04-21 13:13

我无法理解这一句“最重要是这一句,首先++,也就为得到**p所指向的地址,为*p.”

#18
柳儿2006-04-21 13:14
确实没看到书上像你那样解释的阿。
要不,你给个例子,在int i定义后面再定义一个其他变量,让*p还打印49出来。
#19
gototheworld2006-04-21 13:17

#include <iostream>
using namespace std;
void f(int ** p)
{
cout<<"*p = "<<(long)*p<<endl;
(*p)++;//加个扣号后,就能输出地址
cout<<"*p = "<<(long)*p<<endl;

}
int main()
{
int i =49;
int * ip = &i;
cout<<"ip = "<<(long)ip<<endl;
f(&ip);
return 0;
}

#20
静思2006-04-21 13:41
指针对一个学习C++的人来说是非常重要的。感觉指针这玩意挺难学的,大家有没有好的办法来学习它?
#21
踏魔狼2006-04-21 14:36

好!
不把你们弄明白,我今儿就不吃饭。
一个*表示另一个指针,再加一个*符表示另一个指针。
也就是两个**的指针指向一个*的指针。(请确定你已经了解。)
**p它是指向*p的。(了解!)
*p是指向&i的。(明白!)
为了更好区分,两个**的指针用B来代替,一个*的指针用A来代替。
*B++;//B原是指向A的地址,++了后就指向A所指向的地址&i.(B->A->&i).
那么再*B也就是取i的值,也就是49了。

#22
柳儿2006-04-21 14:43

#include <iostream>
using namespace std;
void f(int ** p)
{
cout<<"*p = "<<(long)*p<<endl;
cout <<"p=" <<(long)p<<endl;
*p++;
cout <<"p=" <<(long)p<<endl;
cout<<"*p = "<<(long)*p<<endl;//?里?什??出的是?49,而上面?出的是地址??

}
int main()
{
int i =49;
double j = 50;
int * ip = &i;
cout<<"ip = "<<(long)ip<<endl;
f(&ip);
return 0;
}
那问一下,这个为啥没打出来49呢?

#23
踏魔狼2006-04-21 15:13

#include <iostream>
using namespace std;
void f(int ** p)
{
cout<<"*p = "<<(long)*p<<endl;
cout <<"p=" <<(long)p<<endl;
*p++;
cout <<"p=" <<(long)p<<endl;
cout<<"*p = "<<(long)*p<<endl;//?里?什??出的是?49,而上面?出的是地址??

}
int main()
{
int i =49;
//楼上的姐姐这里可是多了一句呖,double j = 50;
//已经不是原来的那个程序了。

double j = 50;
int * ip = &i;
cout<<"ip = "<<(long)ip<<endl;
f(&ip);
return 0;
}

#24
踏魔狼2006-04-21 15:28
Very Sorry.
指针++是指向它的下一个地址,虽然很不想认,但的确是这样。
但存储不是连接的,和以前的观点还是支持的。
#25
柳儿2006-04-21 15:30
当然不是,就为了验证你说的最重要的那句“最重要是这一句,首先++,也就为得到**p所指向的地址,为*p.”

如果后面加入其他的代码,为啥++后不一样了呢?我觉得楼主的程序能出49,只不过是因为内存分配连着罢了,如果不是连着的,是不会出现49的。至于是谁和谁连着,我还没太确定。

[此贴子已经被作者于2006-4-21 15:34:28编辑过]

#26
踏魔狼2006-04-21 15:36
指针的分配不是连着的。出现连着的情况是为了效率。
#27
柳儿2006-04-21 15:47
在VC里跟了一下,进入f()里的*p++,先执行p++,移动到的地址正好等于i的地址,所以打印出来就是49。进函数的那些汇编,不好意思,我还看不懂为什么是那个样子。
#28
踏魔狼2006-04-21 16:06
这个问题已经白到不能再白了,还要讨论吗?
#29
柳儿2006-04-21 16:08
因为你说存储不是连着的啊。我想验证一下。
#30
踏魔狼2006-04-21 16:12
但请注意一点:指针与变量的分配是两个不同。
请验证吧!
#31
踏魔狼2006-04-21 16:15

还有一点:请注意时机与效率的问题。

#32
柳儿2006-04-21 16:22
或者你告诉我那本书上讲过吧。我看反汇编上就是连着的。
怀疑反汇编的存储器里的地址是真实的还是虚拟的。而且不是随机,一个int型挪4个字节。[ebp-4]是i,[ebp-8]是指针ip,如果接着再定义一个int型的指针是[ebp-0Ch]也就是[ebp-12]。
Bjarne 你知道是咋回事不?
#33
踏魔狼2006-04-21 16:27
地址1==(int q=1);
地址2==(int *q2=&q);
地址3==(int p=2);
地址4==(int *p2=&p);
地址是连接的。但变量是连接的吗?指针是连接的吗?
#34
踏魔狼2006-04-21 16:29
你所说的地址连接只是排它连接。不是实际连接。
#35
柳儿2006-04-21 16:32
不明白你在说什么。你的脾气似乎很大,撤了。
#36
踏魔狼2006-04-21 16:36
小姐你可历害,能感到脾气似乎很大。看来我们还满来电的吗。
去看《程序编译原理》这本书。
#37
gototheworld2006-04-21 18:32

把楼主的源程序放到Visual studio 2005中编译得到将是地址!!!!!!!!!

#38
song42006-04-22 13:31
是连续的
我跟踪结果是
int i
int * ip
是连续存储的,p指向ip,p++后指向i了。
IP的地址比I小4个
当*p++
则指&I;既*P=49

平时总结:一般指针与它指向的地址相连
#39
踏魔狼2006-04-22 13:40

这是楼上的验证的程序。指针的分配就是不连接的。如果是边接的那么结果就不会是0了。

#include <iostream>
using namespace std;
void f(int ** p)
{
cout<<"*p = "<<(long)*p<<endl;
cout <<"p=" <<(long)p<<endl;
*p++;
cout <<"p=" <<(long)p<<endl;
cout<<"*p = "<<(long)*p<<endl;//?里?什??出的是?49,而上面?出的是地址??

}
int main()
{
int i =49;
double j = 50;
int * ip = &i;
cout<<"ip = "<<(long)ip<<endl;
f(&ip);
return 0;
}

#40
song42006-04-22 13:45

排他连续是给人看的
不是给机器看的
而机器执行时只看排他排序之后的地址也就是人看的
中间有很多空间保存相关的内容
(我记得是
一般连续申请的变量占有连续空间(首先要这些变量在一个内存区域)
当一循环储存完成0-Z 或者不够用时改变储存的倒数第二位
再进行下一循环储存
系统分配空间也是有规则的
不知道说的对不,这是我的跟踪总结.

#41
song42006-04-22 14:01
Bjarne
你的程序之所以为0
是因为那些变量的储存地址中间加了DOUBLE
使&I与&IP地址不是差SIZEOF(INT)而差SIZEOF(INT+DOUBLE)
因此F()里面*P++(下衣SIZEOF(INT))指到了DOUBLE变量里面
因为很不安全
系统自动把P指向0X000000
其内容为0
但总体说变量的储存地址还是连续的
#42
song42006-04-22 14:03

不信
你把DOUBLE定义放下面
让I与IP连续定义
结果还是49

请解释的时候少用术语 我才大一有的不懂
谢谢

#43
song42006-04-22 15:15
我总结了大家的思路:
所谓2级指针**P=&iP;是*P这里表达的是IP的地址,而不是P的内容,因为2级指针加一个*是指向一级指针。*P++是把IP的地址向后移SIZEOF(INT)个单位(P的类型是INT,这就是为什么定义指针需要类型)。
/*int i
int * ip
是连续存储的,p指向ip,p++后指向i了。
IP的地址比I小4个
当*p++
则指&I;既*P=49

平时总结:一般指针与它指向的地址相连(凡是连续定义的,并且在一个内存区,地址都是连续的)
*/
由于IP的地址与I的地址连续,所以*P++之后就指向了I,输出I的数值。为什么不输出地址而输出数值呢?
大家别被2级指针弄晕 因为I是变量呀
INT X=8;COUT〈〈X; 输出的是X数值,不是地址。(系统自动向上面找X是什么类型,是指针才输出地址。或者这么记,输出的总是它储存的内容)
指针的分配就是不连接的。这句话虽然对,但是那是针对系统角度,而我们操作的都是排他之后的内存,因此在我们看来,I和IP是连续的
实际上在P与IP之间有一些不是给程序员看的内存,也就是不连续,里面可能包括其他各种操作或对这个地址类型用途的说明。我还没学。。。。
#44
song42006-04-22 15:52
我无法理解这一句最重要是这一句,首先++,也就为得到**p所指向的地址(此时P指向了变量),为*p
*p++;
cout<<*p<<endl;
此时相当于COUT<<I<<ENDL;
自然是数值。因为I是变量
COUT输出后面对象的地址表达的内容。(常量其实也有地址,内容是他本身)
而上面cout<<*p<<endl;为什么是地址。
因为此时*P指向(储存IP的地址,也就是*P内容)IP;相当于IP;
也就是cout<<IP<<endl;
理解不了的象这样做一下代换

我以前问过大家COUT的问题 没人理会我的意思 。。。
#45
吻舞双全2006-04-25 17:06
一到2级指针就用不好啊
怎么理解好呀
各位帮忙了
#46
song42006-04-26 08:45
以下是引用踏魔狼在2006-4-21 14:36:00的发言:

好!
不把你们弄明白,我今儿就不吃饭。
一个*表示另一个指针,再加一个*符表示另一个指针。
也就是两个**的指针指向一个*的指针。(请确定你已经了解。)
**p它是指向*p的。(了解!)
*p是指向&i的。(明白!)
为了更好区分,两个**的指针用B来代替,一个*的指针用A来代替。
*B++;//B原是指向A的地址,++了后就指向A所指向的地址&i.(B->A->&i).
那么再*B也就是取i的值,也就是49了。

这位姐姐解释的已经很详细了
多看看吧

#47
wfpb2006-04-27 15:26
我想问下,我对2级指针的看法:
一.int i;
int *p=&i;
int **fp=&p;
那么fp应该是一个保存指针p地址值的变量,p是一个保存i的地址值的变量。
fp++,是说fp向后指一位,那这个位置就是i的地址,是这样吗?

二.如果是数组
char val[]={1,2,3,4,5,6};
char *p=val;
char **fp=&p;
那么fp应该是一个保存指针p地址值的变量,p是一个保存数组val第一个地址值的变量。
fp++,是什么效果呢?如果是(*fp)++,可以说是相当于p++了,现在怎么解释?

也请帮我看看我哪里的理解出现误解。指出我改正。
#48
gototheworld2006-04-27 17:37
以下是引用wfpb在2006-4-27 15:26:00的发言:
我想问下,我对2级指针的看法:
一.int i;
int *p=&i;
int **fp=&p;
那么fp应该是一个保存指针p地址值的变量,p是一个保存i的地址值的变量。
fp++,是说fp向后指一位,那这个位置就是i的地址,是这样吗?
所先,
1。你要明白变量在内存中,是由高位向底位存储的。
2。指针的存储类型是整型。
好了,明白这点我们来看一下问题:fp++是什么意思呢?fp是整形(见2),fp++表示fp指向向后移动4(见2,因为他是整形吗,所以就是4)个字节的内容。那这个内容是什么呢?等一下再回答。int i;假设i的存储地址是0012FF7C,int *p=&i;后p的存储地址就是0012FF78(见1,还有他们是连系存储的),int **fp = &p;后,现在来回答刚才的内容是什么。fp的值是0012FF78,在fp++后,fp向后移动四个字节,即0012FF78加4个字节,那就是0012FF7C了,哈哈你可以发现正是变量i的地址,所以你这时cout<<*fp;就是变量i的值。注意:这里还有一个小的细节,fp移动后,你没有给他说明移动后指向的类型,所以上面的cout语句,最好要改成cout<<*(int*)fp;

二.如果是数组
char val[]={1,2,3,4,5,6};//这里错了,为什么不这么写呢:char val[]={'1','2','3','4','5','6'}
char *p=val;
char **fp=&p;
那么fp应该是一个保存指针p地址值的变量,p是一个保存数组val第一个地址值的变量。
fp++,是什么效果呢?如果是(*fp)++,可以说是相当于p++了,现在怎么解释?

你的第一个问题同上。

第二个问题:*fp的值是val吧,即数组第一个元素的地址。*fp是char类型变量的地址,那么(*fp)++就是*fp向后移动一个char单位,就是数组的第二个元素的地址了。
#49
song42006-04-27 20:39
以下是引用wfpb在2006-4-27 15:26:00的发言:
我想问下,我对2级指针的看法:
一.int i;
int *p=&i;
int **fp=&p;
那么fp应该是一个保存指针p地址值的变量,p是一个保存i的地址值的变量。
fp++,是说fp向后指一位,那这个位置就是i的地址,是这样吗?

二.如果是数组
char val[]={1,2,3,4,5,6};
char *p=val;
char **fp=&p;
那么fp应该是一个保存指针p地址值的变量,p是一个保存数组val第一个地址值的变量。
fp++,是什么效果呢?如果是(*fp)++,可以说是相当于p++了,现在怎么解释?

也请帮我看看我哪里的理解出现误解。指出我改正。

fp++ 那就向下移动4个储存单位 因为fp所储存的单位是指针,fp++就会移动sizeof(p);
移动多少看它储存单位是什么
不过你这么写会出现错误 因为fp下移sizeof(p)个单位 使fp与*fp所指向的地址相同
同样很不安全 系统就会把*fp中间这步省略.让fp直接指向*fp的内容.也就是数组的地址
而*fp被系统自动放到一个未名区域.
如果是(*fp)++;下移sizeof(p);就是p移到'2'那里
其他的不变
只要记住 &fp是2级指针地址 fp=&p一级指针的地址 *fp=&val一级指针地址内的内容也就是数组地址

#50
wfpb2006-04-28 14:04

这里的(long)有什么作用?强制类型转换?本来是地址0x31,转换以后49?

#51
song42006-04-28 21:27
你是说最前面的例题吗?

我都忘了
不过好像++之后*P里面就是49了
(网吧没有C++)
12