Chinaunix首页 | 论坛 | 博客
  • 博客访问: 42897
  • 博文数量: 13
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 145
  • 用 户 组: 普通用户
  • 注册时间: 2014-05-19 10:39
文章分类

全部博文(13)

文章存档

2016年(3)

2015年(5)

2014年(5)

我的朋友

分类: C/C++

2016-11-18 17:32:22

指针 :

首先,强调一下, 指针概念中的一个重点:


点击(此处)折叠或打开

  1.     int num = 123;
  2.     int* p_num = #
  3.     cout << "*p_num = " << *p_num << endl;    // output : *p_num = 123
  4.     cout << "*(p_num+0) = " << *(p_num+0) << endl;    // output : *(p_num+0) = 123
  5.     cout << "p_num[0] = " << p_num[0] << endl;    // output : p_num[0] = 123
  6.     // *p_num+1 = (*p_num) + 1 , 表示取值p_num 后,将取出来的值+1, 因为优先级顺序 , * 高于 +
  7.     cout << "*p_num+1 = " << *p_num+1 << endl;    // output : *p_num+1 = 124


  8.     // 这2个表达式的值 *(p_num+1) , p_num[1] 一定相等 , 但是每次运行程序后, 打印的值,大概率是2次运行后,打印的值是不同的 ,也是不可预期的
  9.     // 在Debug模式下,可能会运行成功,
  10.     // 在Release模式下,可能会Run-Time Error
  11.     cout << "*(p_num+1) = " << *(p_num+1) << endl; // output : *(p_num+1) = 128691328
  12.     cout << "p_num[1] = " << p_num[1] << endl; // output : p_num[1] = 128691328
  13.     cout << "*(++p_num) = " << *(++p_num) << endl; // output : *(++p_num) = 128691328
  14.     cout << "*(--p_num) = " << *(--p_num) << endl; // output : *(--p_num) = 123

  15.     // 1. p_num+1
  16.     // 2. p_num[1]
  17.     // 3. ++p_num
  18.     // 4. --p_num
  19.     // 从C++能正确解析,计算这4个表达式来看,
  20.     // Notes :
  21.     //         指针(内存地址)是可以偏移的,也可以自增自减, 而每1步的偏移量就是指针所指向的数据类型的内存长度 , 可以用 sizeof(*p_num) 来求出它的值 , 这里的example中是偏移1个int的内存长度 , 4个字节
  22.     //    以下2行代码的输出值之差一定是4 , 因为一个int是4个字节  ==>  0x80-0x7c = 4
  23.     cout << "p_num = " << p_num << endl; // output : p_num = 0x7fff53ef367c
  24.     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个字节, 如果没有长度信息,程序在读取指针内容时,就是莫名的,无助的,没有明确目标的。

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

数组:

一维数组:


点击(此处)折叠或打开

  1.     / 这里为什么用16进制表示一个数字,而不用10进制表示,稍后为您解释我的良苦用心
  2.     //    dec :             2 , 4
  3.     //    hex :            0x2 ,0x4
  4.     int ary1[2] = { 0x2, 0x4 };
  5.     cout << " ary1 = " << ary1 << endl;        // output : ary1     = 0x7fff53ef37f0
  6.     cout << "&ary1[0] = " << &ary1[0] << endl; // output : &ary1[0] = 0x7fff53ef37f0
  7.     cout << "(ary1+0) = " << (ary1+0) << endl; // output : (ary1+0) = 0x7fff53ef37f0
  8.     cout << "&ary1[1] = " << &ary1[1] << endl; // output : &ary1[1] = 0x7fff53ef37f4
  9.     cout << "(ary1+1) = " << (ary1+1) << endl; // output : (ary1+1) = 0x7fff53ef37f4

  10.     cout << "--------------------------------------------------" << endl;

  11.     //
  12.     // p_ary1_ele_1 是一个指向数组中元素的指针 , 长度=4个字节
  13.     // 更简洁一点地说 , p_ary1_ele_1 只是一个指向int数据类型的指针 , 只不过,这里凑巧地是这个int数据的数据是存储在一个1维数组中的
  14.     int* p_ary1_ele_1 = ary1;
  15.     int* p_ary1_ele_2 = &ary1[0];
  16.     cout << "int* p_ary1_ele_1 = " << p_ary1_ele_1 << endl; // output : int* p_ary1_ele_1 = 0x7fff53ef37f0
  17.     cout << "int* p_ary1_ele_2 = " << p_ary1_ele_2 << endl; // output : int* p_ary1_ele_2 = 0x7fff53ef37f0
  18.     cout << "sizeof(*p_ary1_ele_1) = " << sizeof(*p_ary1_ele_1) << endl; // output : sizeof(*p_ary1_ele_1) = 4
  19.     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的内存空间,具体几个,需要视数组的元素个数而定

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

深入理解指针 : 内存地址 + 内存长度


点击(此处)折叠或打开

  1.     //
  2.     // Compile Error 1 : cannot initialize a variable of type 'long *' with an lvalue of type 'int [2]'
  3.     // long* p_long = ary1;
  4.     
  5.     //
  6.     // Compile Error 2 : static_cast from 'int *' to 'long *' is not allowed
  7.     // long* p_long = static_cast<long*>(ary1);
  8.     
  9.     // Compile OK : Version 1 , 保存着ary1的内存地址 , 而且内存长度是8个字节 , sizeof(long) = 8
  10.     long* p_long_1 = reinterpret_cast<long*>(ary1);
  11.     // Compile OK : Version 2 , 保存着ary1的内存地址 , 而且内存长度是8个字节 , sizeof(long) = 8
  12.     long* p_long_2 = (long*)ary1;

  13.     // My MacOSX is <Little Endian Memory Model> , so the number is not 0x0000000200000004L
  14.     // 0x00000004 => ary1[1] , 4个字节的int (1位16进制数表示4位(4 bits)2进位的数)
  15.     // 0x00000002 => ary1[0] , 4个字节的int (1位16进制数表示4位(4 bits)2进位的数)
  16.     // long 8个字节 , 内存长度为2个int占据的长度 , 8个字节
  17.     //
  18.     // int ary1[2] = { 0x2, 0x4 }; maybe long l_num = 0x0000000200000004L;
  19.     long l_num = 0x0000000400000002L;
  20.     cout << "l_num = " << l_num << endl;
  21.     cout << "(*p_long_1) = " << (*p_long_1) << endl;
  22.     cout << "(*p_long_2) = " << (*p_long_2) << endl;

现在知道我为什么要用16进制表示这2个数组中的整数了吧  见上面的代码第20行   :)

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

强化理解变量的内存地址,内存长度


点击(此处)折叠或打开

  1.     int ary1[3] = { 11, 22, 33 };
  2.     // 虽然 ary1 是数组名 , 等价于 &ary1[0] ,
  3.     // 但是 : 不能作以下这种等价代换 , &ary1 <==> &(&ary1[0])
  4.     // 这是因为 &ary1[0] 已经是一个内存地址 , 而这个内存地址也并没有存储在一个变量中,已经是一个表达式的值了 , 所以无法再用取地址符号&
  5.     // Compile Error : cannot take the address of an rvalue of type 'int *' ,
  6.     // int (*p_ary1)[3] = &(&ary1[0]);
  7.     // ==>&ary1 就有所不同 , ary1 是一个变量,那么就存储在内存中的某一个位置 , 可以用取地址符号&
  8.     // p_ary 是一个指针, 指向1个1维数组, 此数组的长度=12个字节(1个int是4个字节, 4*3=12 bytes )
  9.     // ***************************************************************
  10.     // 4者的值是一致的 , 但是内存长度不一致 , 解引用取内容后的内存长度也不一致
  11.     // ***************************************************************
  12.     int (*p_ary)[3] = &ary1;
  13.     cout << " ary1 = " << (ary1) << endl; // ary1 = 0x7fff5a5327ec
  14.     // &ary1[0] -> int
  15.     cout << "&ary1[0] = " << (&ary1[0]) << endl; // &ary1[0] = 0x7fff5a5327ec
  16.     // &ary1 -> int[3] , 指向一个1维数组, 此1维数组, 包含3个int元素的1维数组
  17.     cout << "&ary1 = " << (&ary1) << endl; // &ary1 = 0x7fff5a5327ec
  18.     cout << "p_ary = " << (p_ary) << endl; // p_ary = 0x7fff5a5327ec

  19.     cout << "--------------------------------------------------" << endl;

  20.     // 求 ary1整个数组的长度 = 4 * 3 = 12
  21.     cout << "sizeof(ary1) = " << sizeof(ary1) << endl; // sizeof(ary1) = 12
  22.     // 求 指向 ary1[0] 的指针变量的内存长度 , 64位机,取址长度统一为8
  23.     cout << "sizeof(&ary1[0]) = " << sizeof(&ary1[0])<< endl; // sizeof(&ary1[0]) = 8
  24.     // p_ary = &ary1 , 是通过赋值运算得来的,所以2者的sizeof的结果是一致 , 无论如何, 任何指针的 sizeof(...) ,在64位机器上,都是8
  25.     cout << "sizeof(&ary1) = " << sizeof(&ary1) << endl; // sizeof(&ary1) = 8
  26.     cout << "sizeof(p_ary) = " << sizeof(p_ary) << endl; // sizeof(p_ary) = 8

  27.     cout << "--------------------------------------------------" << endl;

  28.     // 注意到了吗?*符号,解引用
  29.     // *ary1, 最后得到的内存长度是 4
  30.     // *(&ary1[0]), 最后得到的内存长度是 4
  31.     // *p_ary, 最后得到的内存长度是 12 , 所以这里又回到了之前强调的指针还包含内存的长度
  32.     // ********** 所以又回到了本文章最初的强调的指针包含的2部分信息 ,1.地址+2.内存长度 **********

  33.     cout << "sizeof(*ary1) = " << sizeof(*ary1) << endl; // sizeof(*ary1) = 4
  34.     cout << "sizeof(*(&ary1[0])) = " << sizeof(*(&ary1[0])) << endl; // sizeof(*(&ary1[0])) = 4
  35.     cout << "sizeof(*p_ary) = " << sizeof(*p_ary) << endl; // sizeof(*p_ary) = 12
  36.     
  37.     cout << "--------------------------------------------------" << endl;
  38.     cout << "p_ary = " << p_ary << endl;     // p_ary = 0x7fff5a5327ec
  39.     cout << "p_ary + 1 = " << (p_ary + 1) << endl; // (p_ary + 1) = 0x7fff5a5327f8 // delta = 0x7fff5a5327f8 - 0x7fff5a5327ec = 4*3 (12 bytes)
  40.     cout << "++p_ary = " << ++p_ary << endl;        // (++p_ary) = 0x7fff5a5327f8 // delta = 4*3 =12

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



指向1维数组的指针,如何通过这一指针获取 数组中的元素

点击(此处)折叠或打开

  1.     int ary1[3] = { 11, 22, 33 };
  2.     int (*p_ary)[3] = &ary1;
  3.     // *p_ary 求值后得到整个数组的信息,包含数组首地址与数组长度 , 而求得的值又原始成一个数组名 , 即是一个数组首个元素的地址 , so ...
  4.     // *p_ary = *(&ary1) = ary1 = &ary1[0]
  5.     // ==> *p_ary = &ary1[0]
  6.     // ==> *(*p_ary) = *(&ary1[0]) = ary1[0]
  7.     // ==> *(*p_ary + 1) = *(&ary1[0]+1) = ary1[1]
  8.     cout << "ary1[0] = *(*p_ary + 0) = " << *(*p_ary + 0) << endl; // 11
  9.     cout << "ary1[1] = *(*p_ary + 1) = " << *(*p_ary + 1) << endl; // 22
  10.     cout << "ary1[2] = *(*p_ary + 2) = " << *(*p_ary + 2) << endl; // 33
  11.     cout << "--------------------------------------------------" << endl;
------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------

二维数组: 

点击(此处)折叠或打开

  1. int ary2[3][5] = {
  2.         { 2, 4, 6, 8,10 }, // ary2[0]
  3.         { 12,14,16,18,20 }, // ary2[1]
  4.         { 22,24,26,28,30 } // ary3[2]
  5.     };
  6.     
  7.     // Version 1 :
  8.     for(int i = 0; i < 3; ++i) {
  9.         for(int j = 0; j < 5; ++j) {
  10.             cout << *(*(ary2 +i) + j) << "\t";    // Core Code
  11.         }
  12.         cout << endl;
  13.     }

  14.     cout << "--------------------------------------------------" << endl;

  15.     // Version 2 :
  16.     for(int i = 0; i < 3; ++i) {
  17.         int (*p_ary)[5] = (ary2 + i);    // Core Code
  18.         for(int j = 0; j < 5; ++j) {
  19.             // 理解困难的,请先看此段代码的 __LINE__ 10,19 , Core Code
  20.             // 然后请向前阅读 <<强化理解变量的内存地址,内存长度>> 这一章的代码 __LINE__ 44
  21.             // p_ary = (ary2+i)
  22.             // cout << *(*(ary2 +i) + j) << "\t";
  23.             cout << *(*p_ary + j) << "\t";
  24.         }
  25.         cout << endl;
  26.     }


  27.     // Version 3 : !!! Error expression !!!
  28.     cout << "--------------------------------------------------" << endl;
  29.     for(int i = 0; i < 3; ++i) {
  30.         for(int j = 0; j < 5; ++j) {
  31.             // *(*ary2 +i + j) ==> *(*ary2 + (i + j))
  32.             // 因为2维数组中各个元素的地址 也是连续的
  33.             // loop 0 : (0+0) , (0+1) , (0+2) , (0+3) , (0+4) , 0,1,2,3,4 => 2,4,6,8,10
  34.             // loop 1 : (1+0) , (1+1) , (1+2) , (1+3) , (1+4) , 1,2,3,4,5 => 4,6,8,10,12
  35.             // loop 2 : (2+0) , (2+1) , (2+2) , (2+3) , (2+4) , 2,3,4,5,6 => 6,8,10,12,14
  36.             cout << *(*ary2 +i + j) << "\t";
  37.         }
  38.         cout << endl;
  39.     }

补充说明:

只有变量才能进行取地址操作  , 已经取址后的表达式无法再进行取址操作

点击(此处)折叠或打开

  1.     // OK Version
  2.     int a = 1;
  3.     int* p_a = &a;
  4.     int** pp_a = &p_a;
  5.     
  6.     // 具体请回看 :强化理解变量的内存地址,内存长度 , 这章的代码
  7.     // 虽然 ary1 是数组名 , 等价于 &ary1[0] ,
  8.     // 但是 : 不能作以下这种等价代换 , &ary1 <==> &(&ary1[0])
  9.     // 这是因为 &ary1[0] 已经是一个内存地址 , 而这个内存地址也并没有存储在一个变量中,已经是一个表达式的值了 , 所以无法再用取地址符号&
  10.     // 只有变量才能进行取地址操作 , 已经取址后的表达式无法再进行取址操作
  11.     int        b = 1;
  12.     // Compile Error : cannot take the address of an rvalue of type 'int *'
  13.     int** pp_b = &(&b);



阅读(1939) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~