指针

基本概念:指针(pointer)是一个值为内存地址的变量(或数据对象)


声明及初始化指针变量

基本用法:数据类型 * 指针变量名

int * ptr_num;
char * ptr_name;
float * money_ptr;

注:

  1. int* p的写法偏向于地址,即 p 就是一个地址变量,表示一个十六进制地址
  2. int *p的写法偏向于值, *p是一个类型变量,能够表示一个整型值
  3. 声明中的 * 号和使用中的 * 号含义完全不同

空指针(null poiniter)

空指针:空指针不指向任何对象,在试图使用任何一个指针之前可以先检查是否为空,空指针指向的内存是不可以访问的。

用法:

int *ptr1 = nullptr//如果不赋初值,就是野指针
注意初始化所有指针,并在可能的情况下,尽量等定义了对象之后再定义指向它的指针。

void *指针:
一种特殊的指针类型,可以存放任意对象的地址

 double num = 3.14;double * ptr_num1 = &num;void * ptr_num2 = &num;cout << (ptr_num1 == ptr_num2) << endl;

注:

  1. void *指针存放一个内存地址,地址指向的内容是什么类型不能确定
  2. void *类型指针一般用来:拿来和别的指针作比较、作为函数的输入和输出;赋值给另一个void *指针

小结:

  • 如果一个变量存储另一个对象的地址,则称该变量指向这个对象
  • 指针变量可以赋值,指针的指向在程序执行中可以改变

注:

  1. 指针可以是任何基本数据类型、数组和其他所有高级数据结构的地址
  2. 若指针已声明为指向某种类型数据的地址,则它不能用于存储其他类型数据的地址
  3. 应为指针指定一个地址后,才能在语句中使用指针
  4. 0~255之间的内存编号是系统占用的,因此不可以访问

野指针:指针变量指向非法的内存空间

int main()
{//指针变量p指向内存地址变量为0x1100的空间int * p = (int*)0x1100;//访问时报错:cout << *p << endl;
}

const修饰指针

const修饰指针有三种情况:

  1. const修饰指针——常量指针
  2. const修饰常量——指针常量
  3. const既修饰指针,又修饰常量
int a = 1, b = 2;
const int * p = &a;    //常量指针
特点:指针的指向可以修改,但是指针指向的值不能修改
*p = 2;    //false
p = &b;    //true
***********************************************
int * const p = &a;    //指针常量
特点:指针的指向不可以修改,指针指向的值可以修改
*P = 3;    //true
p = &b;    //false
**********************************************
const int * const p = &a;//const既修饰指针,又修饰常量,都不能修改

引用

引用:为对象起了另外一个名字(引用即别名)

语法:数据类型 &别名 = 原名;

注:

  1. 引用并非对象,只是为一个已经存在的对象起的别名
  2. 引用只能绑定在对象上,不能与字面值或某个表达式的计算结果绑定在一起(int& ref_value = 10 ;//错误)
  3. 引用必须初始化,所以使用引用之前不需要测试其有效性,因此使用引用可能会比使用指针效率高。引用一旦初始化,就不可以在修改(例:a是b的别名,就不能再改成c的别名了)
  4. 将引用变量用作参数时,函数将使用原始数据,而非副本
  5. 当数据所占内存比较大时,建议使用引用参数
  6. 不可以直接引用常量,但是指向常量的引用是合法的:
double& d = 2;// d = 2 ,不合法,违背了常量的基本概念
//指向常量的引用--合法
const double& d = 2;

引用做函数参数

作用:函数传参时,可以利用引用的技术让形参修饰实参;
优点:可以简化指针修改实参

使用引用参数:

void Swap1(int, int);
void Swap2(int*, int*);
void Swap3(int&, int&);
int main()
{int num1 = 10, num2 = 5;Swap1(num1, num2);cout << "执行Swap1后:" << num1 << '\t' << num2 << endl;Swap2(&num1, &num2);cout << "执行Swap2后:" << num1 << '\t' << num2 << endl;Swap3(num1, num2);cout << "执行Swap3后:" << num1 << '\t' << num2 << endl;return 0;
}
void Swap1(int num1, int num2)
{int temp;temp = num1;num1 = num2;num2 = temp;
}
void Swap2(int* p1, int* p2)
{int temp;temp = *p1;*p1 = *p2;*p2 = temp;
}
void Swap3(int& ref1, int& ref2)//使用引用
{//使用引用的理由:1.可以更加简便的书写代码//2.可以直接传递某个对象,而不只是把对象复制一份int temp;temp = ref1;ref1 = ref2;ref2 = temp;
}

注:

  1. 引用参数中使用const可以避免参数被无意修改
  2. 引用参数建议尽可能的使用const

返回引用

函数返回引用类型;用法:函数调用作为左值

  1. 不要返回局部变量的引用
#include <iostream>
using namespace std;
int& sum();//返回引用类型的函数
int main()
{int& Num = sum();cout << Num << endl;//打印结果正确,因为编译器做了保留cout << Num << endl;//结果错误,因为num的内存已经释放return 0;
}
int& sum()
{int num = 10;//函数中的局部变量会被内存回收return num;
}
  1. 函数调用作为左值
int& test()
{static int a = 10;//静态变量数据存放在全局区,在程序结束后系统释放return a;
}
int main()
{int& ref = test();cout << ref << endl;cout << ref << endl;test() = 100;//如果函数的返回值是引用,这个函数调用可以作为左值//test返回的是a这个变量,相当于a=100,ref是a的别名cout << ref << endl;
}
  1. 函数可以不返回值,默认返回传入的引用对象本身
int& sum(int& num1, int& num2)
{num1++;num2++;//默认返回最后一个更新的引用参数
}
int main()
{int num1 = 10, num2 = 15;int& result = sum(num1, num2);cout << result << endl;return 0;
}
  1. 返回引用时,要求函数参数中包含被返回的引用对象

小结:使用引用参数的一些指导原则

  1. 能够修改调用函数中的数据对象
  2. 数据对象较大时传递引用可以提高程序的运行效率
    函数中不需要修改传递的参数:
    ①如果数据对象很小,建议按值传递
    ②传递数组只能使用指针,并使用const关键字
    ③较大的对象则使用const指针或引用,以提高程序效率
    函数中需要修改传递的参数:
    ①数据对象是基本类型或结构时,可以使用指针或引用
    ②数据对象是数组时只能使用指针
    ③数据对象是类对象时,要求使用引用

引用的本质

引用过的本质在c++内部实现是一个指针常量

指针和引用:

  • 引用对指针进行了简单的封装,底层仍然是指针
  • 获取引用地址时,编译器会进行内部转换
int num = 100;
int& rel_num = num;
rel_num = 100;
cout << &num << '\t' << &rel_num  << '\t' << rel_num << endl;

常量引用

使用场景:用来修饰形参,防止误操作
·

·

·

·

·

·

动态分配内存

使用new分配内存,使用delete释放内存,与new配对使用(不能释放声明变量分配的内存)

//1.在运行阶段为一个int值分配未命名的内存
//2.使用指针来访问(指向)这个值(右->左)
int * ptr_int = new int;
delete ptr_int; //释放由new分配的内存

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

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

int * intArray = new int [10];

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

使用delete[]释放内存

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

关于new和delete使用的规则:

  1. 不要使用delete释放不是new分配的内存
  2. 不要使用delete释放同一内存两次
  3. 如果使用new[]c为数组分配内存,则对应delete[]c释放内存
  4. 对空指针使用delete是安全的

栈区(stack)

由编译器自动分配释放,一般存放函数的参数值、局部变量的值等;
操作方式类似数据结构中的栈— —先进后出

堆区(heap)

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

全局区(静态区-static)

存放全局变量和静态变量以及常量,程序结束后由系统释放

文字常量区

存放常量字符串的地方,程序结束由系统释放

程序代码区

存放函数体的二进制代码,由操作系统进行管理的

#include <iostream>using namespace std;int main()
{//栈区int num2;//栈区char str[] = "空你急哇";//栈区char * ptr2;//“空你急哇”以及'\0'在常量区,ptr3在栈区char * ptr3 = "空你急哇";//全局(静态)初始化区static int num3 = 2048;//分配的内存在堆区ptr1 = new int[10];ptr2 = new char[20];//注:ptr1和ptr2本身是在栈区中的return 0;
}

·

·

·
数组与指针案例:

#include <iostream>
using namespace std;int main()
{//定义数组实现,实现逆序int num[]{12, 43, 10, 389, 8, 67};int numCount = sizeof(num) / sizeof(num[0]);int* p_num = num;int* temp = new int;for(int j = 0; j < numCount / 2; j++){*temp = *(p_num + j);*(p_num + j) = *(p_num + numCount - j - 1);*(p_num + numCount - j - 1) = *temp;}cout << "逆序后:" << '\n';for(int i = 0; i < numCount; i++){cout << *(p_num + i) << endl;}return 0;
}

老九学堂 学习 C++ 第五天相关推荐

  1. 老九学堂 学习 C++ 第七、八天

    7.1 内联函数 内联(inline)函数:是C++为提高程序运行速度所做的一项改进:与常规函数的区别不在于编写方式,而在于被调用时的运行机制不同:编译使用函数代码替换 函数调用. 使用建议:如果执行 ...

  2. 老九学堂 学习C++ 第十天

    10继承 10.1 概念: 所谓 "继承(inheritance)" 就是在一个已经存在的类基础上,再建立一个新类 从已有的类派生出新的类,派生类就继承了原有类(基类)的特征,包括 ...

  3. 老九学堂 学习C++ 第六天

    函数 自定义函数的完整写法: 注: 函数原型与函数定义的头部类似,最后以分号结尾 函数原型中的参数名称可以省略,只写参数类型 C++中返回值类型不能是数组,但可以是其他任何类型(可以将数组作为结构或对 ...

  4. 老九学堂之分布式设计教材

    老九学堂之分布式设计教材 作者:老九-技术大黍 原文:分布式系统设计教材 社交:知乎 公众号:老九学堂(新人有惊喜) 特别声明:原创不易,未经授权不得转载或抄袭,如需转载可联系笔者授权 前言 本文由老 ...

  5. 【老九学堂】【初识C语言】C语言中的运算符

    1运算符和表达式 C语言运算符是说明特定操作的符号,它是构造C语言表达式的工具.C语言的运算异常丰富,除了控制语句和输入输出以外的几乎所有的基本操作都作为运算符处理.除了常见的三大类,算术运算符.关系 ...

  6. 【老九学堂】【初识C语言】二维数组

    一维数组只有一个下标,称为一维数组,其数组元素也称为单下标变量.在实际问题中有很多量是二维的或多维的,因此C语言允许构造多维数组.多维数组元素有多个下标,以标识它在数组中的位置,所以也称为多下标变量. ...

  7. 【老九学堂】【C++】数组与指针

    不知道在通过前面的内容学习后,是否有很多小伙伴都会认为数组和指针是等价的,数组名表示数组的首地址呢?不幸的是,这是一种非常危险的想法,并不完全正确,前面我们将数组和指针等价起来是为了方便大家理解(在大 ...

  8. 【老九学堂】【C++】位运算符

    位运算是指按二进制进行的运算.在系统软件中,常常需要处理二进制位的问题.C语言提供了6个位操作运算符.这些运算符只能用于整型操作数,即只能用于带符号或无符号的char,short,int与long类型 ...

  9. 【老九学堂】【C++】C++的发展史

    为了让小伙伴们在学习过程中,能收获更多的知识,达到真正的零基础入门和深入了解C++,老九君特地收集了有关C++发展相关的一些资料供大家查阅和学习: C++语言发展大概可以分为三个阶段: 第一阶段从80 ...

  10. 【老九学堂】【初识C语言】C语言保留字(关键字)详解

    保留字(reserved word) 保留字又称关键字. 指在高级语言中已经定义过的字,使用者不能再将这些字作为变量名或过程名使用. 每种程序设计语言都规定了自己的一套保留字. 例如:BASIC语言规 ...

最新文章

  1. linux小红帽实验心得,格林童话小红帽读书心得体会5篇
  2. 基于Angularjs实现分页
  3. 【强化学习】一文带你理清强化学习
  4. win7的开机启动项怎么管理 win7管理开启启动项的方法
  5. 韩顺平mysql优化笔记_韩顺平 mysql优化笔记.doc
  6. 服务器显示灰色怎么办,服务器远程桌面显示灰色
  7. 单片机炫彩灯实训报告_单片机实验报告一-流水灯实验
  8. AS常用指令,常用功能,以及常见问题
  9. 360 无法显示网速
  10. 成都蚂蚁金服java_成都蚂蚁金服暑期实习Java后台开发面经(已收到OC)
  11. 程序员有多喜欢树莓派?这7个开发套件让他们爱不释手!
  12. [Unity][C#]Regex正则表达式判断字符串
  13. Elasticsearch查询时还在百度DSL语句吗?你可能需要这份总结
  14. 我该如何向我的朋友解释“01背包”问题?
  15. mac 无法打开22端口 无法远程连接ssh 的解决办法
  16. 软件离散数学复习笔记资料
  17. 邮件营销 | 精准投放,独立站可提升6倍转化率
  18. 照片损坏了无法显示还能修复么?
  19. CE5 vs CE6
  20. 混合硬盘计算机,混合固态硬盘

热门文章

  1. Windows_XP SP3 Profession 正版密钥
  2. C盘Temp文件夹的内容可以删掉
  3. Spring Cloud Netflix之为上一个damo添加Ribbon(负载均衡优化)
  4. 个人账号转企业账号及邓白氏编码申请经验分享
  5. 嵌入式学习——c的复习
  6. 运动蓝牙耳机什么牌子好,骑行运动耳机
  7. WinDjView对AfxMessageBox的定制
  8. hdu4415 Assassin’s Creed (贪心)
  9. channel.QueueDeclare各个参数详解
  10. python 随手写的堆排序