【C++】指针学习 知识点总结+代码记录

一.示例代码知识点总结

1. 基本指针操作

  • 指针声明和初始化int* ptr_a = a; 表示声明了一个指向整型的指针,并初始化为指向数组a的首地址。
  • 引用和指针的区别int& i2 = i; 声明了一个整型引用,绑定到变量i上,而int* ptr_i = &i; 声明了一个指向整型的指针,并初始化为指向变量i的地址。
  • 常量指针和指针常量const int* p1 = &c; 和 int* const p3 = &c; 分别表示指向常量的指针和指针类型的常量。

2. 特殊类型的指针

  • Void指针void* pv; 可以存储任何类型的指针,但需要显式类型转换才能访问。
  • 空指针int* p = 0; 或 int* p0 = NULL; 用于表示指针不指向任何有效地址。

3. 指针与数组

  • 数组名作为指针:数组名a实际上是指向其第一个元素的指针。
  • 指针数组int* pLine[3]; 是一个数组,每个元素是一个指针。
  • 数组指针int(*arrptr)[2] = &arr; 是指向数组的指针,指向一个具有两个整型元素的数组。

4. 指针作为函数参数

  • 函数参数传递split(float x, int *intpart, float *fracpart) 接收指针作为参数,用于输出参数。

5. 指向函数的指针

  • 函数指针声明typedef double (*Double_Int)(int); 定义了一个指向接受整型参数并返回双精度浮点型的函数的指针类型。
  • 函数指针初始化DoubleInt = &doubleint; 初始化函数指针为指向doubleint函数的地址。

6. 类的指针成员

  • 对象指针point* pointptr; 是指向point类实例的指针。
  • this指针:在类的成员函数中,this是一个隐含的指针,指向当前对象。
  • 指向类成员的指针int point::* numberptr; 和 void (point::*showptr)() const; 分别是用于指向类的数据成员和成员函数的指针。

7. 其他

  • 类型转换int* pint = static_cast<int*>(pv); 使用类型转换将void*转换为int*
  • 前向声明class Fred; 和 class Barney; 允许在类定义中引用尚未完全定义的其他类。

8. 标准库函数

  • std::begin 和 std::end 函数用于获取容器的开始和结束迭代器。

二.代码及详细注释

#include<iostream>
//字符串
#include<string>
//格式化输出
#include<iomanip>
//获取类型
#include<typeinfo>
//begin和end函数
#include<iterator>

using namespace std;

class point {
private:
	int number;
	string name;
public:
	point(int num, string nam) :number(num), name(nam) {  }
	void show() const;
	void test() const;
};

void point::show() const{
	cout << "number:" << number << endl;
	cout << "name:" << name << endl;
}

//当局部作用域中声明了与类成员同名的变量,对该标识符的直接引用代表局部中声明的,使用this指针可以访问类成员中的同名变量
void point::test() const {
	int number = 10;
	cout << "number:" << number << endl;
	cout << "this->number:" << this->number << endl;
}

//前向引用声明
class Fred;
class Barney {
	//Fred x;   //错误
	Fred* x;   //正确
};
class Fred {
	Barney y;
};


//将实数分成整数部分和小数部分
void split(float x, int *intpart, float *fracpart) {
	*intpart = static_cast<int>(x);
	*fracpart = x - *intpart;
}

double doubleint(int a) {
	cout << "This is double_int " << endl;
	return static_cast<double>(a);
}

int intdouble(double a) {
	cout << "This is int_double " << endl;
	return static_cast<int>(a);
}


int main() {
	//数组名实际上是一个不能被赋值的指针(指针常量)
	int a[10];
	int* ptr_a = a;
	int i;
	//引号在右边是取地址赋值,在左边表示引用
	int& i2 = i;
	int* ptr_i = &i;
	i = 10;
	cout << "i = " << i << endl;
	cout << "*ptr_i = " << *ptr_i << endl;
	//指向常量的指针(不能通过指针来改变对象的值,但是指针本身可以改变,可以指向另外的对象)
	int c = 10;
	const int* p1 = &c;
	int b = 20;
	p1 = &b;
	//*p1 = 10;		编译错误
	//可以确保指针指向的变量值不通过指针发生改变
	//指针类型的常量(指针指向不能改变)
	int* const p3 = &c;
	//p3 = &b;		编译错误
	//void类型指针(可以储存任何类型的对象地址)
	//注:没有viod类型的变量
	void* pv;
	int j = 5;
	pv = &j;
	cout << "The type of pv : " << typeid(pv).name() << endl;
	// cout << "*pv = " << *pv;		报错
	//显示类型转换后才能间接访问
	int* pint = static_cast<int*>(pv);
	cout << "The type of pint : " << typeid(pint).name() << endl;
	cout << "*pint = " << *pint << endl;
	//空指针(避免指向不确定地址)
	int* p;
	p = 0; //表示将p设为空指针,不指向任何地址
	int* p0 = NULL; //也代表空指针
	//用指针处理数组元素
	for (int i = 0; i < 10; i++) {
		a[i] = i;
	}
	//使用数组名和指针运算
	for (int i = 0; i < 10; i++) {
		cout << *(a + i) << " ";
	}
	cout << endl;
	//使用指针变量
	for (int* p = a; p < (a + 10); p++) {
		cout << *p << " ";
	}
	//标准库函数begin和end获取首位元素地址
	int* beg = begin(a);
	int* last = end(a);
	while (beg != last) {
		cout << *beg << " ";
		beg++;
	}
	cout << endl;
	//指针数组(本质是一个数组,其中每个数组元素都是一个指针)
	//利用指针数组输出单位矩阵.cpp
	int line1[] = { 1,0,0 };
	int line2[] = { 0,1,0 };
	int line3[] = { 0,0,1 };
	int* pLine[3] = { line1,line2,line3 };		//定义整型指针数组并为其初始化
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			cout << pLine[i][j] << " ";
		}
		cout << endl;
	}
	cout << "1---------" << endl;
	//把二元数组当作指针数组来访问
	int array[3][3];
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			array[i][j] = i + 2 + j;
		}
	}
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			cout << *((*array + i) + j) << " ";
		}
		cout << endl;
	}
	cout << "2---------" << endl;
	//数组指针(本质是指针,指向一个数组)
	int arr[2] = { 10,20 };
	int(*arrptr)[2] = &arr;
	cout << *arrptr << endl;	//输出数组名地址
	for (int i = 0; i < 2; i++) {
		cout << (*arrptr)[i] << " ";
	}
	cout << endl;
	//用指针作为函数参数
	//使用引用作为形参传递也能做到相同作用
	cout << "3---------" << endl;
	float split_x, fracpart;
	int intpart;
	split_x = 3.1425926;
	split(split_x, &intpart, &fracpart);
	cout << "X : " << split_x << " intpart:" << intpart << " fracpart:" << fracpart << endl;
	//指向函数的指针
	// 函数名表示函数的代码在内存中的起始地址,调用函数的实质就是函数代码首地址,函数指针是来存放函数代码首地址的变量,在程序中可以像使用函数名一样使用指向函数的指针来调用函数
	//声明了一个有double形参,返回类型为Int的指针
	typedef double (*Double_Int)(int);
	//使用yype可以很方便的为复杂类型起别名,把要声明的类型别名放到声明这种类型的变量时书写变量名的位置即可
	//声明这一类型的变量
	Double_Int DoubleInt;
	//直接声明
	int (*IntDouble)(double);
	//初始化即直接赋值
	DoubleInt = &doubleint;   //函数返回值与传参类型必须相同(否则编译错误)
	IntDouble = intdouble;    //可以取地址也可以不取
	double dint;
	dint = doubleint(3);   //函数调用
	dint = DoubleInt(5);   //指针调用
	cout << "4---------" << endl;
	//对象指针
	point* pointptr;
	point point1(1,"zhang");
	pointptr = &point1;
	pointptr->show();	//使用指针访问对象成员
	point1.show();	   //使用对象自己访问
	cout << "5---------" << endl;
	//this指针
	point1.test();
	cout << "6---------" << endl;
	//指向类的非静态成员的指针
	int point::* numberptr;		//声明指向数据成员的指针
	void (point:: * showptr)() const;	  //声明指向函数成员的指针
	//赋值
	// numberptr = &point::number;  //不能在外部访问私有成员
	showptr = &point::show;
	//通过对象使用指针访问类的非静态成员
	//point1.*numberptr;
	//pointptr->*numberptr;
	(point1.*showptr)();  //必须有括号
	//通过对象指针访问
	(pointptr->*showptr)();
	cout << "7---------" << endl;
	//指向类的静态成员函数的指针
	//6_14.cpp
	return 0;
}

三.输出结果

不给出参数列表
调用Point给出的默认构造函数
10  10
调用Point析构函数
调用Point给出的默认构造函数
10  10
调用Point析构函数
给出参数列表
调用Point含参构造函数
1  4
调用Point析构函数
-842150451  -842150451
调用Point2析构函数
0  0
调用Point2析构函数
------1------
调用Point给出的默认构造函数
调用Point给出的默认构造函数
10  10
10  10
调用Point析构函数
调用Point析构函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值