我一直在阅读指针在C ++中是如何工作的,我试图稍微弄乱它,但程序停止工作。
#include <iostream>
using namespace std;
int main ()
{
char a[] = "Hello";
char * b = a;
char ** c = &b;
cout << *(b+1) << endl;
//cout << **(c+2) << endl;
return 0;
}
如果没有注释注释行,程序将停止使用错误代码:0xC0000005。我做错了什么或是某种错误?
答案 0 :(得分:3)
下面:
char a[] = "Hello";
char * b = a;
你利用数组来指针衰减。现在b
指向a[0]
。也就是说,b
保存a[0]
然后
char ** c = &b;
c
现在指向b
的地址,它本身就是一个指针。 c保存b
的地址,其中包含a
的地址(看看为什么人们现在讨厌指针?)
如果您想从a[0]
访问c
,首先需要取消引用它:
*c
提供b
,然后我们需要取消引用 以返回a[0]
:
*(*c)
如果您想使用指针算法来访问a[1]
,您希望增加b
,所以:
* C + 1
现在我们的地址为a[1]
,如果我们要打印,我们需要再次取消引用:
*(*c+1)
当你说:
时,你错误地增加了b
的地址而不是地址a[0]
**(c+2)
c
保留b
的地址,而不是a
,因此递增会导致未定义的行为。
答案 1 :(得分:3)
DEVICE SHELL COMMAND: pm install -r "/data/local/tmp/<package name>
指向当前堆栈帧上c
的地址。
b
指向堆栈帧上的某个位置。
c + 2
然后,您可以访问此位置,并将未指定的字节作为地址。
*(c + 2)
现在您尝试访问所说的未指定地址,幸运的是,它崩溃了。
答案 2 :(得分:0)
好的,让我们再试一次。
a是指向数组中第一个元素的指针,在本例中为&#34; H&#34;。 c是指向b的地址的指针,b也是指向第一个元素的指针。
当你将c递增2时,你将指针向前移动两个。所以内存地址前进了两个,但是c只是指向a而不是它自己的指针,因此你处于未知领域。相反,什么可能工作(未经测试):
cout<<*(*c+1)<<endl;
这取消引用c,所以你得到b(或者同样的东西),你将这个指针递增1,它保留在数组中,然后你再次取消引用来访问该值。!
答案 3 :(得分:0)
&b + 2
不是有效指针。
为简单起见,我们假设指针只有一个char
宽(我们的内存非常非常小)。
假设a
存储在地址10,b
存储在20,c
存储在21。
char* b = a;
与char* b = &a[0];
相同 - 它将数组的第一个元素(10)的位置存储在b
中。
char**c = &b
将b
(20)的位置存储在c
。
看起来像这样:
a b c
10 11 12 13 14 15 16 17 18 19 20 21 22...
| H | e | l | l | o | 0 | | | | | 10 | 20 |
从这张图片中可以清楚地看出c + 2
是22,这不是有效的地址
取消引用它是未定义的,任何事情都可能发生 - 你的崩溃只是好运。
如果您期待l
中的第一个"Hello"
,它位于a[2]
,即b[2]
(或*(b + 2)
),即{{} 1}}(或(*c)[2]
)。
答案 4 :(得分:0)
char a[] = "Hello";
char * b = a;
char ** c = &b;
a和b指向char数组的开头有&#34; Hello&#34;作为它的角色。
所以,让我们从内存位置开始0x100存储Hello。
a是指针,因此它存储一个地址。
a和b都存储此值0x100。但他们的地址是别的。假设a的地址是0x200,b的地址是0x300。
c也是指针。所以它存储了b的地址。 因此,c将地址0x300存储为其值。
c + 1 = 0x304
c + 2 = 0x308
* c:您想要访问存储在0x300的值,这是b的地址。
*(c + 1):您想访问地址0x304
*(c + 2):然后访问0x308,将未指定的字节作为地址。
**(c + 2):取消引用地址0x308。它可能是也可能不是指针变量的地址。因此,解除引用可能是未定义的操作。