栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++笔记(三)【指针】

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++笔记(三)【指针】

C++笔记(三)【指针】

文章目录
  • C++笔记(三)【指针】
    • 一、基础知识
      • 1.1 定义
      • 1.2 关于定义时int* p 和 int *p的写法
      • 1.3 使用方式
      • 1.4 特殊注意点
    • 二、 指针类型
      • 2.1 空指针
      • 2.2 void* 指针
    • 三、引用
      • 3.1 什么是引用
      • 3.2 引用与指针的关系
    • 四、指针与数组
      • 4.1 联系
      • 4.2 区别
    • 五、指针运算
      • 5.1 指针的递增递减
      • 5.2 指针的直接加减
      • 5.3 取数组的元素
    • 六、动态分配内存
    • 七、关于程序的内存分配
      • 7.1 类型
      • 7.2 示例
    • 八、指针与二维数组

一、基础知识 1.1 定义

指针:一个值为内存地址的变量(或数据对象)

内存中:

int 变量a(内存地址+内容)

int 指针变量b(内存地址+内容(变量a的地址))*

叫做b指向a

1.2 关于定义时int* p 和 int *p的写法

1.int* p的写法偏向于地址,即p就是一个地址变量

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

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

推荐:采用第一种方法用int*来声明一个整型指针变量

1.3 使用方式
int num=1000;
int* ptr_num=#    //但不能直接给一个常量地址
*ptr_num=90;
//num=90
1.4 特殊注意点
#include 
using namespace std;

int main()
{
	char ch='a';
	char* ptr_ch=&ch;
	cout << ptr_ch << "t" << *ptr_ch << endl;   //a     a  会与想象的不同
	//原因
	char* str="唐柳健is"; //在c语言时代char*就默认后面跟的是字符串的地址,而不是字符的地址,因此上面打印的时候按照字符串的地址方式打印,肯定会出错
	//解决方法强转成char型指针
	cout << (char*)ptr_ch << endl;   //此方法有时候编译器不让转
	//改成这个方法
	cout << (void*)ptr_ch << endl; 
	return 0;
}
二、 指针类型 2.1 空指针

一定要给指针初始值,要不然采用默认值很危险,为此可以用空指针,强烈建议初始化所有指针

int* kjk;//野指针
//下面三个等价
int* mine=nullptr;
int* mine=0;
int* mine=NULL;  //要加上#include 
2.2 void* 指针

可以存放任意对象的地址

int nm = 10;
int* ptr_n = #
void* ptr_m = #
// ptr_m==ptr_n

注意点

1.无法修改指向的变量值,因为类型不清楚

如:*ptr_m=90;

2.void指针类型一般用来:

拿来和别的指针比较(当不知道函数输出的指针属于什么类型的时候)

或者作为函数的输入输出

数组中也可以来存指针来节省空间大小

三、引用 3.1 什么是引用

核心:为了使得代码写的更漂亮方便

定义:为对象起了别名

int int_value=2022;
int& reValue=int_value;

//错误,引用必须被初始化
int& reVla2;

注意:

  1. 引用并非对象,只是给一个已经存在的对象起了别名
  2. 引用只能绑定在对象上,不能与字面值或某个表达式的计算结果绑定在一起,如int& ref_value=10;
  3. 引用必须初始化,使用引用之前不需要测试其有效性,所以一定程度上比指针高效

指向常量的引用是非法的

可以改成

const double& ref=100;
3.2 引用与指针的关系
  • 引用对指针进行了简单的封装,底层仍然为指针
  • 获取引用地址时编译器会进行内部转换

如下,相当于把星号指针封装了:

int num=100;
int& rel_num=num;
rel_num=90;
cout << &num << "t" << &rel_num << endl;


//实际上
int num=100;
int* rel_num=#
*rel_num=90;
cout << &num << "t" << rel_num << endl;
四、指针与数组 4.1 联系

数组:

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

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

#include 
using namespace std;

int main()
{
	double scores[]={2,5,65,7,2};
	double* ptr=&scores[0];
	cout << scores << "t" << ptr << endl;
    //scores=ptr
    
    //指向数组的指针可以进行下标操作
    double* pt=scores;
	cout << pt[3] << endl;
    return 0;
}
4.2 区别

但是指针与数组不是一码事!

#include 
using namespace std;

int main()
{
	double scores[]={2,5,65,7,2};
	double* pt=scores;
	cout << sizeof(scores) << "t" << sizeof(pt) << endl;
	//40  8            40显然是8字节*5=40   相当于打回原形了虽然数组名指向的是首地址
	return 0;
}
五、指针运算

理解:指针的平移

5.1 指针的递增递减
#include 
using namespace std;

int main()
{
	double scores[]={2,5,65,7,2};
	double* pt=scores;
	for(int i=0;i<5;i++){
		cout << *pt++ << endl;    //平移的是一个double类型大小的字节,这里为8,即使sizeof(double) 
	}
	return 0;
}
5.2 指针的直接加减

但是注意越界问题很危险

#include 
using namespace std;

int main()
{
	double scores[]={2,5,65,7,2};
	double* pt=scores;
	pt+=2;
	cout << *pt << endl;
	pt-=2;
	cout << *pt << endl;
    cout << *(pt+3) << endl;
    cout << *(pt+i) << endl;
	return 0;
}
5.3 取数组的元素

第i个元素的地址:&num[i] 或 num+i

第i个元素的值:num[i] 或 *(num+i)

int* ptr=&num[4];
int* ptr=num+4;
//等价的

很重要的一点!!

数组名不能加加,只有自由的指针才可以

不管是指针,尽量不要贸然的移动指针,尽量少在自身上++,可以+i

double scores[]={2,5,65,7,2};
double* pt=scores;
cout << *++scores << endl; //会报错的,因为++就相当于scores=scores+1 改变了,*(scores+2)则没有改变scores本身所以是可以的
六、动态分配内存

1.使用new分配内存

  • 指针真正用武之地:在运行阶段分配未命名的内存以存储值
  • 在此情况下只能通过指针来访问内存
#include 
using namespace std;

int main()
{
	//运行阶段为一个int值分配未命名的内存,使用指针来访问这个值 
    // ptr在栈区,  在堆区分配了一块int型空间
	int* ptr=new int;
    *ptr=90;
    ptr++;//这个行为很危险,因为一旦++后上面的内存空间就变成内存泄漏,尽量避免这种操作
	delete ptr;  //一定要和new成对出现
    
    //数组也可以这样
    int* nums = new int[7];
    int numss[7];
    delete []nums;
    //sizeof(nums)  得到结果4字节,运行时候才会动态给空间
    //sizeof(numss) 得到28
    
	return 0;
}

2.使用delete释放内存

不能释放声明变量分配的内存

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

七、关于程序的内存分配 7.1 类型

1.栈区

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

2.堆区(heap)

一般由程序猿分配释放,若没释放,程序结束时可能由操作系统回收,注意与数据结构中的堆概念不同,分配方式类似链表

3.全局区(静态区-static)

全局变量和静态变量存储在一起,程序结束后由系统释放

4.文字常量区

常量字符串就放在这里,程序结束时由系统释放

5.程序代码区

存放函数体的二进制代码

7.2 示例
#include 
using namespace std;

int num1=0; //全局初始化区
int* ptr1; //全局未初始化区 
int main()
{
	//栈区
	int num2;
	char str[] = "tlj is coder";
	char* ptr2;
	//赋值的右边的字符串及数字都是在常量区的,左边在栈区
	char* ptr3="tlj";
    double nums[23]={2,3,4,5};
	//全局(静态)初始化区
	static int num3=1024;
	//右边,即分配的内存在堆区,左边的指针本身在栈区 
	ptr1 = new int[10];
	ptr2 = new char[30]; 
	return 0;
}
八、指针与二维数组

直接看代码理解

#include 

using namespace std;


int main()
{
	//二维数组的一维作为了行,这个指针相当于五个一维数组组成的 
	int (*p2)[3]= new int[5][3];
	p2[2][3]=90;
	for(int i=0;i<5;i++){
		for(int j=0;j<3;j++){
			cout << p2[i][j] << 't';
			cout << *(*(p2+i)+j) << ',';
		}
		cout << endl;
	}
	
	cout << "另一种" << endl;
	int arrays[5][3] = {{1,2,3},{3,4,5},{7,8,9},{1,5,6},{4,7,8}};
	int (*p1)[3] = arrays;
	//第二行第一列的地址,可以与下面结合观察,他们每个行的地址是相邻的
	cout << &p1[1][0] << endl; 
	for(int i=0;i<5;i++){
		for(int j=0;j<3;j++){
            //指的是每行数组的第一个元素的地址 
			cout << p1+i << 't';
		}
		cout << endl;
	}
	return 0;
}

指针还能用于,如结构体中不能有函数,则可以用指针指向一个函数。这样结构体里就有方法了,这也是实现面向对象的一个方式。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1012839.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号