当前位置:   article > 正文

C++基础入门详细笔记(二)_c++:int i=1;int *ptr1,*ptr2

c++:int i=1;int *ptr1,*ptr2

C++基础入门详细笔记(一)

C++基础入门详细笔记(二)

C++基础入门详细笔记(三)

C++基础入门详细笔记(四)

C++基础入门详细笔记(五)

C++基础入门详细笔记(六)

 

目录

四、指针

1、空指针

2、void*指针

3、引用

4、指针和引用

5、指针和数组

6、指针的算数运算

6.1、指针的递增和递减(++、--)

6.2、指针加上或减去某个整数值

7、数组与指针小结

7.1、一维数组与指针

7.2、二维数值与指针

8、动态分配内存

8.1、使用new分配内存

8.2、使用delete释放内存

9、动态分配数组

9.1、使用new创建动态分配的数组

9.2、使用delete[]释放内存

9.3、程序的内存分配

10、总结


四、指针

  1. int *ptr_year;
  2. ptr_year=&year;    //&year表示取地址

注意:

1. int* p的写法偏向于地址,即p就是一个地址变量,表示一个十六进制地址

2. int *p的写法偏向于值,*p是一个整形变量,能够表示一个整型

3. 声明中的*号和使用中的*号含义完全不同

 

example:

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     char ch = 'a';
  6.     char * ptr_ch = &ch;
  7.     cout << (void *)ptr_ch << '\t' << *ptr_ch << endl;
  8.     return 0;
  9. }

> 结果输出:0x6dfeeb        a

(void *):任意类型指针

 

1、空指针

空指针不指向任何对象,在试图使用一个指针之前可以首先检查是否为空

用法

  1. int *ptr1 = nullptr;//等价于int *ptr1 = 0;
  2. int *ptr2 = 0;      //直接将ptr2初始化为字面常量0
  3. //需要包含#include <stdlib.h>头文件
  4. int *ptr3 = NULL;   //等价于int *ptr3=0;

 

2、void*指针

1. (void*)指针存放一个内存地址,地址指向的内容是什么类型不能确定

2. (void*)类型指针一般用来:拿来和别的指针比较、作为函数的函数的输入和输出;赋值给另一个(void*)指针

 

3、引用

  1. int int_value = 1024;
  2. //refValue指向int_value,是int_value的另一个名字
  3. int& refValue = int_value;
  4. //错误:引用必须被初始化
  5. int& refValue2;

 

 

注:

  • 指向常量的引用是非法的
  1. double & ref = 100;         //错误
  2. const double & ref = 100;   //正确

 引用并非对象,只是为一个已经存在的对象起的别名

  • 引用只能绑定在对象上,不能与字面值或某个表达式的计算结果绑定在一起
int &ref_value = 10;   //错误

 引用必须初始化,所以使用之前不需要测试其有效性,因此使用引用可能会比使用指针效率高

int * num = &abc;   //引用
  • 引用更接近const指针,一旦与某个变量关联起来,就将一直效忠于它

  • 将引用变量用作参数时,函数将使用原始数据,而非副本

  • 当数据所占内存比较大时,建议使用引用参数

4、指针和引用

1. 引用对指针进行了简单封装,底层仍然是指针

2. 获取引用地址时,编译器会进行内部转换

3.引用比指针效率高

  1. int num = 108;
  2. int& rel_num = num;
  3. rel_num = 118;
  4. cout << &num << '\t' <<&rel_num <<endl;

转换为:
 

  1. int num = 108;
  2. int* rel_num = &num;
  3. *rel_num = 118;
  4. cout << &num << '\t' <<rel_num <<endl;

 

 

5、指针和数组

数组:

1. 存储在一块连续的内存空间中

2. 数组名就是这块连续内存空间的首地址

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     double score[] {11, 22, 33, 44, 55};//数组类型-->double[5]
  6.     double * ptr_score = score;
  7.     
  8.     //数组名就是这块连续内存空间的首地址
  9.     //cout << score << endl;    //输出为地址值
  10.     cout << sizeof(score) << ''\t' <<sizeof(ptr_score) <<endl
  11. }

结果:40   4

解答:ptr_score为double型的地址,所以只占4个字节;而score为数组,占40字节。

 

6、指针的算数运算

6.1、指针的递增和递减(++、--)

  1. int i;
  2. double score[5] {98, 87, 65, 43, 76};
  3. double * ptr_score;
  4. ptr_score = score;
  5. for(i=0;i<5; i++)
  6. {
  7.     cout << (void*)ptr_score++ << endl;
  8. }

输出:

0x6dfec0

0x6dfec8

0x6dfed0

0x6dfed8

0x6dfee0

注:一个类型为T的指针的移动,以sizeof(T)为移动单元。因为score是double类型,所以每次移动8个字节空间

 

6.2、指针加上或减去某个整数值

  1. int i;
  2. double score[5] {98, 87, 65, 43, 76};
  3. double * ptr_score;
  4. ptr_score = &score[1];    //取第一个数据的地址
  5. ptr_score +=2;            //取第三个数据的地址
  6. cout << (void*)ptr_score++ << endl;
  7. ptr_score -=3;            //取第一个数据的地址
  8. cout << (void*)ptr_score++ << endl;

结果:

0x6dfed8

0x6dfec8

 

7、数组与指针小结

7.1、一维数组与指针

  • int num[50]; //num是数组名,也可以理解成数组的首地址

  • num的值与&num[0]的值是相同的

  • 数组第i+1个元素可表示为:

第i+1个元素的地址:

  1. &num[i+1]
  2. num+i+1

第i+1个元素的值:

  1. num[i+1]
  2. *(num+i+1)
  3. *++ptr_num
  • 为指向数组的指针赋值:

  1. int * ptr_num = num; 
  2. int * ptr_num = &num[0];
  • 指针变量可以指向数组元素

  1. int * ptr_num = &num[4];
  2. int * ptr_num = num + 4;

7.2、二维数值与指针

  • 如5行3列的二维数组指针首地址为&a[0][0]

  • 使用指针访问二维数组元素中的元素

  1. *(a[1]+2);    //表示a[1][2]
  2. *(*(a+1)+2);    //表示a[1][2]

 

example1:

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     int * p = new int[10];
  6.     //用指针创建二维数组
  7.     int (*p2)[3] = new int[5][3];//降维操作//第一维已经降维,第二维3不变
  8.     p2[3][2] = 555;    //给其中一个赋值
  9.     for(int i = 0; i<5; i++)
  10.     {
  11.         for(int j=0; j<3; j++)
  12.         {
  13.             //两种输出模式
  14.             //cout << p2[i][j] << ',';    
  15.             cout << *(*(p2+i)+j) << ',';
  16.         }
  17.         cout << endl;
  18.     }
  19.     return 0;
  20. }

输出结果:

9966960,9992840,0,

0,0,0,

0,0,0,

0,0,555,

0,0,0,

 

example2:

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     int * p = new int[10];
  6.     //用指针创建二维数组
  7.     int arrays[5][3] ={
  8.     {1,2,3},
  9.     {4,5,6},
  10.     {7,8,9},
  11.     {10,11,12},
  12.     {13,14,15},
  13.     };
  14.     int (*p2)[3] = arrays;
  15.     for(int i = 0; i<5; i++)
  16.     {
  17.         for(int j=0; j<3; j++)
  18.         {
  19.             //两种输出模式
  20.             //cout << p2[i][j] << ',';    
  21.             cout << *(*(p2+i)+j) << ',';
  22.         }
  23.         cout << endl;
  24.     }
  25.     //输出每个元素的地址
  26.     cout << &arrays[1][0] << endl;
  27.     for(int i = 0; i<5; i++)
  28.     {
  29.         cout << p2 + i <<endl;
  30.     }    
  31.     return 0;
  32. }

输出结果:

1,2,3,

4,5,6,

7,8,9,

10,11,12,

13,14,15,

0x6dfeac    //arrays[1][0]输出元素地址

0x6dfea0

0x6dfeac    arrays[1][0]输出元素地址

0x6dfeb8

0x6dfec4

0x6dfed0

 

 

8、动态分配内存

8.1、使用new分配内存

  1. int * p = new int;   //在运行此句话阶段分配未命名的内存
  2. int num;             //此为编译阶段分配内存;

解析:p在栈区,在堆区分配一块int型空间

注:在运行阶段分配未命名的内存以存储值

 

8.2、使用delete释放内存

delete ptr_int;    //释放由new释放的内存

注:

  • 与new配对使用;

  • 不要释放已经释放的内存;

  • 不能释放生命变量分配的内存;

  • 不要创建两个指向同一内存块的指针,有可能误删除两次。

example:

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     int num[5];//分配了20字节的空间,即使空间里面没有数值;
  6.     int* nums = new int[5]; //运行到这一步才在堆内存分配5个字节的整形空间,nums表明空间的地址大小
  7.     cout << sizeof(num) << ''\t' <<sizeof(nums) <<endl
  8. }

运行结果:20    4

 

9、动态分配数组

9.1、使用new创建动态分配的数组

int * intArray = new int[10];

注:new运算符返回第一个元素的地址

9.2、使用delete[]释放内存

delete [] intArray;//释放整个数组

example:

  1. int * ptr_int = new_int;
  2. short * ptr_short = new short[500];
  3. delete ptr_int;        //释放由new释放的内存
  4. delete [] ptr_short;//释放整个数组

注:关于new和delete使用的规则:

  • 不要使用delete释放不是new分配的内存

  • 不要使用delete释放统一内存两次

  • 如果使用new[]释放为数组分配内存,则对应delete[]释放内存

 

9.3、程序的内存分配

  • 栈区(stack):由编译器自动分配释放,一般存放函数的参数值,局部变量的值等。其操作方式类似数据结构中的栈-先进后出。

  • 堆区(heap):一般由程序员分配释放,若程序不释放,程序结束时可能由操作系统回收。其数据结构中的堆是两回事,分配方式类似链表。

  • 全局区(静态区-static):全局变量和静态变量是存储在一起的,程序结束后由系统回收。

  • 文字常量区:常量符号串就放在这里,程序结束由系统回收。

string a="hello,world!";
  • 程序代码区:存放函数体的二进制代码。

注:

  1. #include <iostream>
  2. using namespace std;
  3. int num1 = 0;
  4. int * ptr1;
  5. int main 
  6. {
  7.     int num2;        //栈区
  8.     char str[] = "hello,world!"//栈区
  9.     char * ptr2;            //栈区
  10.     char * ptr3 = "hello,world!"//hello,world!以及\0在常量区,ptr3在栈区
  11.     static int num3 = 1024;    //全局(静态)初始化区
  12.     ptr1 = new int[10];        //分配的内存在堆区
  13.     ptr2 = new char[20];
  14.     //注意:ptr1和ptr2本身在栈区
  15.     return 0;
  16. }

 

10、总结

1、指针是一个变量,存储另一个变量(对象)的内存地址

2、指针的声明由基本类型、星号(*)和变量名组成

3、为指针赋值,赋值运算符号右侧必须是一个地址

  • 如果是普通变量需要在前面加一个取地址运算符&

  • 如果是另一个指针变量或者是一个数组,不需要加&运算符

4、运算符*用于返回指针指向的内存地址中存储的值

5、使用指针访问一维数组和二维数组的元素

  1. int num = 4;
  2. int* p_num = &num;//取num所在的地址值
  3. *p_num = 112;    //指向num的值变为112
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/42229
推荐阅读
相关标签
  

闽ICP备14008679号