指针 :
首先,强调一下, 指针概念中的一个重点:
-
int num = 123;
-
int* p_num = #
-
cout << "*p_num = " << *p_num << endl; // output : *p_num = 123
-
cout << "*(p_num+0) = " << *(p_num+0) << endl; // output : *(p_num+0) = 123
-
cout << "p_num[0] = " << p_num[0] << endl; // output : p_num[0] = 123
-
// *p_num+1 = (*p_num) + 1 , 表示取值p_num 后,将取出来的值+1, 因为优先级顺序 , * 高于 +
-
cout << "*p_num+1 = " << *p_num+1 << endl; // output : *p_num+1 = 124
-
-
-
// 这2个表达式的值 *(p_num+1) , p_num[1] 一定相等 , 但是每次运行程序后, 打印的值,大概率是2次运行后,打印的值是不同的 ,也是不可预期的
-
// 在Debug模式下,可能会运行成功,
-
// 在Release模式下,可能会Run-Time Error
-
cout << "*(p_num+1) = " << *(p_num+1) << endl; // output : *(p_num+1) = 128691328
-
cout << "p_num[1] = " << p_num[1] << endl; // output : p_num[1] = 128691328
-
cout << "*(++p_num) = " << *(++p_num) << endl; // output : *(++p_num) = 128691328
-
cout << "*(--p_num) = " << *(--p_num) << endl; // output : *(--p_num) = 123
-
-
// 1. p_num+1
-
// 2. p_num[1]
-
// 3. ++p_num
-
// 4. --p_num
-
// 从C++能正确解析,计算这4个表达式来看,
-
// Notes :
-
// 指针(内存地址)是可以偏移的,也可以自增自减, 而每1步的偏移量就是指针所指向的数据类型的内存长度 , 可以用 sizeof(*p_num) 来求出它的值 , 这里的example中是偏移1个int的内存长度 , 4个字节
-
// 以下2行代码的输出值之差一定是4 , 因为一个int是4个字节 ==> 0x80-0x7c = 4
-
cout << "p_num = " << p_num << endl; // output : p_num = 0x7fff53ef367c
-
cout << "p_num + 1 = " << (p_num + 1) << endl; // output : p_num + 1 = 0x7fff53ef3680
指针中包含2部分的信息
1. 内存地址
2. 数据类型的长度 (用 *p_num 解引用时, 读取内存地址的值是 ,应该读取4个字节的长度)
其中第2部分,通常不被人重视,大多数人只会向你解释指针 就是内存地址 , 但是从内存地址处开始读取多少个字节,才能还原 原始的数据内容呢?这就是我这里所要强调的 : 这是一个指针(1. 地址),更加具体地是 一个指向XX数据类型的指针(2. 数据类型的长度), XX数据类型在内存中占据n个字节 , 指针在读取内容时,就读取n个字节, 如果没有长度信息,程序在读取指针内容时,就是莫名的,无助的,没有明确目标的。
------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------
数组:
一维数组:
-
/ 这里为什么用16进制表示一个数字,而不用10进制表示,稍后为您解释我的良苦用心
-
// dec : 2 , 4
-
// hex : 0x2 ,0x4
-
int ary1[2] = { 0x2, 0x4 };
-
cout << " ary1 = " << ary1 << endl; // output : ary1 = 0x7fff53ef37f0
-
cout << "&ary1[0] = " << &ary1[0] << endl; // output : &ary1[0] = 0x7fff53ef37f0
-
cout << "(ary1+0) = " << (ary1+0) << endl; // output : (ary1+0) = 0x7fff53ef37f0
-
cout << "&ary1[1] = " << &ary1[1] << endl; // output : &ary1[1] = 0x7fff53ef37f4
-
cout << "(ary1+1) = " << (ary1+1) << endl; // output : (ary1+1) = 0x7fff53ef37f4
-
-
cout << "--------------------------------------------------" << endl;
-
-
//
-
// p_ary1_ele_1 是一个指向数组中元素的指针 , 长度=4个字节
-
// 更简洁一点地说 , p_ary1_ele_1 只是一个指向int数据类型的指针 , 只不过,这里凑巧地是这个int数据的数据是存储在一个1维数组中的
-
int* p_ary1_ele_1 = ary1;
-
int* p_ary1_ele_2 = &ary1[0];
-
cout << "int* p_ary1_ele_1 = " << p_ary1_ele_1 << endl; // output : int* p_ary1_ele_1 = 0x7fff53ef37f0
-
cout << "int* p_ary1_ele_2 = " << p_ary1_ele_2 << endl; // output : int* p_ary1_ele_2 = 0x7fff53ef37f0
-
cout << "sizeof(*p_ary1_ele_1) = " << sizeof(*p_ary1_ele_1) << endl; // output : sizeof(*p_ary1_ele_1) = 4
-
cout << "sizeof(*p_ary1_ele_2) = " << sizeof(*p_ary1_ele_2) << endl; // output : sizeof(*p_ary1_ele_2) = 4
这段代码 说明 :
1. p_ary1_ele_1 ,
p_ary1_ele_2 只是普普通通的指向int变量的指针而已
2. 一维数组名 ary1 , 在C++中的表达式,就表示的是 :
其实就是一个普通的指向int型变量的指针, 只不过 ary1 的有效内存空间不单单只有一个孤立的4字节的int型内存长度,而是占据着连续的多个int的内存空间,具体几个,需要视数组的元素个数而定
------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------
深入理解指针 : 内存地址 + 内存长度
-
//
-
// Compile Error 1 : cannot initialize a variable of type 'long *' with an lvalue of type 'int [2]'
-
// long* p_long = ary1;
-
-
//
-
// Compile Error 2 : static_cast from 'int *' to 'long *' is not allowed
-
// long* p_long = static_cast<long*>(ary1);
-
-
// Compile OK : Version 1 , 保存着ary1的内存地址 , 而且内存长度是8个字节 , sizeof(long) = 8
-
long* p_long_1 = reinterpret_cast<long*>(ary1);
-
// Compile OK : Version 2 , 保存着ary1的内存地址 , 而且内存长度是8个字节 , sizeof(long) = 8
-
long* p_long_2 = (long*)ary1;
-
-
// My MacOSX is <Little Endian Memory Model> , so the number is not 0x0000000200000004L
-
// 0x00000004 => ary1[1] , 4个字节的int (1位16进制数表示4位(4 bits)2进位的数)
-
// 0x00000002 => ary1[0] , 4个字节的int (1位16进制数表示4位(4 bits)2进位的数)
-
// long 8个字节 , 内存长度为2个int占据的长度 , 8个字节
-
//
-
// int ary1[2] = { 0x2, 0x4 }; maybe long l_num = 0x0000000200000004L;
-
long l_num = 0x0000000400000002L;
-
cout << "l_num = " << l_num << endl;
-
cout << "(*p_long_1) = " << (*p_long_1) << endl;
-
cout << "(*p_long_2) = " << (*p_long_2) << endl;
现在知道我为什么要用16进制表示这2个数组中的整数了吧
见上面的代码第20行 :)
------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------
强化理解变量的内存地址,内存长度
-
int ary1[3] = { 11, 22, 33 };
-
// 虽然 ary1 是数组名 , 等价于 &ary1[0] ,
-
// 但是 : 不能作以下这种等价代换 , &ary1 <==> &(&ary1[0])
-
// 这是因为 &ary1[0] 已经是一个内存地址 , 而这个内存地址也并没有存储在一个变量中,已经是一个表达式的值了 , 所以无法再用取地址符号& 了
-
// Compile Error : cannot take the address of an rvalue of type 'int *' ,
-
// int (*p_ary1)[3] = &(&ary1[0]);
-
// ==> 而 &ary1 就有所不同 , ary1 是一个变量,那么就存储在内存中的某一个位置 , 可以用取地址符号&
-
// p_ary 是一个指针, 指向1个1维数组, 此数组的长度=12个字节(1个int是4个字节, 4*3=12 bytes )
-
// ***************************************************************
-
// 4者的值是一致的 , 但是内存长度不一致 , 解引用取内容后的内存长度也不一致
-
// ***************************************************************
-
int (*p_ary)[3] = &ary1;
-
cout << " ary1 = " << (ary1) << endl; // ary1 = 0x7fff5a5327ec
-
// &ary1[0] -> int
-
cout << "&ary1[0] = " << (&ary1[0]) << endl; // &ary1[0] = 0x7fff5a5327ec
-
// &ary1 -> int[3] , 指向一个1维数组, 此1维数组, 包含3个int元素的1维数组
-
cout << "&ary1 = " << (&ary1) << endl; // &ary1 = 0x7fff5a5327ec
-
cout << "p_ary = " << (p_ary) << endl; // p_ary = 0x7fff5a5327ec
-
-
cout << "--------------------------------------------------" << endl;
-
-
// 求 ary1整个数组的长度 = 4 * 3 = 12
-
cout << "sizeof(ary1) = " << sizeof(ary1) << endl; // sizeof(ary1) = 12
-
// 求 指向 ary1[0] 的指针变量的内存长度 , 64位机,取址长度统一为8
-
cout << "sizeof(&ary1[0]) = " << sizeof(&ary1[0])<< endl; // sizeof(&ary1[0]) = 8
-
// p_ary = &ary1 , 是通过赋值运算得来的,所以2者的sizeof的结果是一致 , 无论如何, 任何指针的 sizeof(...) ,在64位机器上,都是8
-
cout << "sizeof(&ary1) = " << sizeof(&ary1) << endl; // sizeof(&ary1) = 8
-
cout << "sizeof(p_ary) = " << sizeof(p_ary) << endl; // sizeof(p_ary) = 8
-
-
cout << "--------------------------------------------------" << endl;
-
-
// 注意到了吗? 用*符号,解引用
-
// *ary1, 最后得到的内存长度是 4
-
// *(&ary1[0]), 最后得到的内存长度是 4
-
// *p_ary, 最后得到的内存长度是 12 , 所以这里又回到了之前强调的指针还包含内存的长度
-
// ********** 所以又回到了本文章最初的强调的指针包含的2部分信息 ,1.地址+2.内存长度 **********
-
-
cout << "sizeof(*ary1) = " << sizeof(*ary1) << endl; // sizeof(*ary1) = 4
-
cout << "sizeof(*(&ary1[0])) = " << sizeof(*(&ary1[0])) << endl; // sizeof(*(&ary1[0])) = 4
-
cout << "sizeof(*p_ary) = " << sizeof(*p_ary) << endl; // sizeof(*p_ary) = 12
-
-
cout << "--------------------------------------------------" << endl;
-
cout << "p_ary = " << p_ary << endl; // p_ary = 0x7fff5a5327ec
-
cout << "p_ary + 1 = " << (p_ary + 1) << endl; // (p_ary + 1) = 0x7fff5a5327f8 // delta = 0x7fff5a5327f8 - 0x7fff5a5327ec = 4*3 (12 bytes)
-
cout << "++p_ary = " << ++p_ary << endl; // (++p_ary) = 0x7fff5a5327f8 // delta = 4*3 =12
------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------
指向1维数组的指针,如何通过这一指针获取 数组中的元素
-
int ary1[3] = { 11, 22, 33 };
-
int (*p_ary)[3] = &ary1;
-
// *p_ary 求值后得到整个数组的信息,包含数组首地址与数组长度 , 而求得的值又原始成一个数组名 , 即是一个数组首个元素的地址 , so ...
-
// *p_ary = *(&ary1) = ary1 = &ary1[0]
-
// ==> *p_ary = &ary1[0]
-
// ==> *(*p_ary) = *(&ary1[0]) = ary1[0]
-
// ==> *(*p_ary + 1) = *(&ary1[0]+1) = ary1[1]
-
cout << "ary1[0] = *(*p_ary + 0) = " << *(*p_ary + 0) << endl; // 11
-
cout << "ary1[1] = *(*p_ary + 1) = " << *(*p_ary + 1) << endl; // 22
-
cout << "ary1[2] = *(*p_ary + 2) = " << *(*p_ary + 2) << endl; // 33
-
cout << "--------------------------------------------------" << endl;
------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------
二维数组:
-
int ary2[3][5] = {
-
{ 2, 4, 6, 8,10 }, // ary2[0]
-
{ 12,14,16,18,20 }, // ary2[1]
-
{ 22,24,26,28,30 } // ary3[2]
-
};
-
-
// Version 1 :
-
for(int i = 0; i < 3; ++i) {
-
for(int j = 0; j < 5; ++j) {
-
cout << *(*(ary2 +i) + j) << "\t"; // Core Code
-
}
-
cout << endl;
-
}
-
-
cout << "--------------------------------------------------" << endl;
-
-
// Version 2 :
-
for(int i = 0; i < 3; ++i) {
-
int (*p_ary)[5] = (ary2 + i); // Core Code
-
for(int j = 0; j < 5; ++j) {
-
// 理解困难的,请先看此段代码的 __LINE__ 10,19 , Core Code
-
// 然后请向前阅读 <<强化理解变量的内存地址,内存长度>> 这一章的代码 __LINE__ 44
-
// p_ary = (ary2+i)
-
// cout << *(*(ary2 +i) + j) << "\t";
-
cout << *(*p_ary + j) << "\t";
-
}
-
cout << endl;
-
}
-
-
-
// Version 3 : !!! Error expression !!!
-
cout << "--------------------------------------------------" << endl;
-
for(int i = 0; i < 3; ++i) {
-
for(int j = 0; j < 5; ++j) {
-
// *(*ary2 +i + j) ==> *(*ary2 + (i + j))
-
// 因为2维数组中各个元素的地址 也是连续的
-
// loop 0 : (0+0) , (0+1) , (0+2) , (0+3) , (0+4) , 0,1,2,3,4 => 2,4,6,8,10
-
// loop 1 : (1+0) , (1+1) , (1+2) , (1+3) , (1+4) , 1,2,3,4,5 => 4,6,8,10,12
-
// loop 2 : (2+0) , (2+1) , (2+2) , (2+3) , (2+4) , 2,3,4,5,6 => 6,8,10,12,14
-
cout << *(*ary2 +i + j) << "\t";
-
}
-
cout << endl;
-
}
补充说明:
只有变量才能进行取地址操作 , 已经取址后的表达式无法再进行取址操作
-
// OK Version
-
int a = 1;
-
int* p_a = &a;
-
int** pp_a = &p_a;
-
-
// 具体请回看 :强化理解变量的内存地址,内存长度 , 这章的代码
-
// 虽然 ary1 是数组名 , 等价于 &ary1[0] ,
-
// 但是 : 不能作以下这种等价代换 , &ary1 <==> &(&ary1[0])
-
// 这是因为 &ary1[0] 已经是一个内存地址 , 而这个内存地址也并没有存储在一个变量中,已经是一个表达式的值了 , 所以无法再用取地址符号& 了
-
// 只有变量才能进行取地址操作 , 已经取址后的表达式无法再进行取址操作
-
int b = 1;
-
// Compile Error : cannot take the address of an rvalue of type 'int *'
-
int** pp_b = &(&b);
阅读(1939) | 评论(0) | 转发(0) |