【C++/C】C++与C指针使用方法及差异(一):基础

指针基础

引用

为对象另起一个名字,引用类型引用另外一种类型。

int a = 10;
int &b = a;    //b指向a,是a的另一个名字
int &c;    //错误:引用必须被初始化
  1. 引用只是和它的初始值绑定了,并不是被拷贝给引用了,一旦初始化完成,则无法重新绑定另一个对象;
  2. 引用只是别名,不是对象,所以不能定义引用的引用。

指针

是指向另一类型的复合类型,与引用类似,也实现了对其他对象的间接访问。

指针和引用的区别

  1. 指针本身就是一个对象,允许对指针赋值和拷贝;
  2. 在指针的生命周期内可以先后指向几个不同的对象;
  3. 指针无需在定义时就赋值(此时拥有一个不确定的值);
  4. 指针可以有多级,但是引用只有一级;
  5. 指针可以指向NULL,引用不可以;
  6. 指针++是指向指针后面的内存,引用++是引用对象自增;
  7. 指针在作为函数参数时需要检查是否为空,引用不需要。
//指针变量定义
int* p1, p2;
//p1是指向int对象的指针,但是p2是int对象
//不推荐同时定义多个指针变量

//获取对象地址:使用取值符&
int ival = 42;
int* p = &ival;

//指针类型必须要和它所指对象严格匹配
double dval;
double* pd = &dval;
int* pi = pd;	//错误,指针pi的类型和pd不匹配
pi = &dval;		//错误,试图把double对象的地址赋给int指针

指针的值应属于下列4种状态之一:

  1. 指向一个对象;
  2. 指向紧邻对象所占空间的下一个位置;
  3. 空指针,没有指向任何对象;
  4. 无效指针,上述情况之外。
//利用指针访问对象,使用解引用符*
int i = 42;
int* p = &i;
cout << *p << endl;		//输出42
//给解引用赋值就是给指针所指对象赋值
*p = 3;
cout << *p << endl;		//输出3
cout << *p << endl;		//输出3

空指针

不指向任何对象。

//C++11标准引用,nullptr是一种特殊类型的字面值,可以被转换成任意其他指针类型
int* p = nullptr;

使用建议:

  1. 尽量定义了对象后再定义指向它的指针;
  2. 访问指针前先判空;
  3. 记得delete指针,且delete后将指针设置为空。

void指针

void*是一种特殊的指针类型,可用于存放任意对象的地址。

  1. 任何类型指针都可以直接赋值给void指针;
  2. 如果void类型指针赋值给其他类型指针,需要显式转换;
double boj = 3.14;
void* pv = &obj;
double* pd1 = pv;	//错误,不可以直接赋值
double* pd2 = (double*)pv;	//必须显式转换
  1. void指针可以直接和其他类型的指针比较指针存放的地址是否相同;
  2. void指针也可以用nullptr来初始化,表示一个空指针;
  3. void指针作为函数的输入和输出时,可以接受任意类型的输入指针和输出任意类型的指针(增加了泛编程的能力)。

直接delete void指针会导致内存泄露
delete voidP; //只是清空了一个指针 delete (FrameInfo*)voidP; //正确析构了voidP指向的变量

指针常量

不能修改指针所指向的地址,在定义时必须初始化。

char* const a = &p;
*a = 'a';	//可以
a = &b;		//错误,指针指向的地址不能改变

常量指针

不能修改指针所指向地址的内容,但可以改变指针所指向的地址。

const char* a;
*a = 'a';	//错误,指针所指的值不能改变
a = &b;		//可以

指针和数组

对数组的元素使用取地址符就能得到指向该元素的指针。

string nums[] = {"one", "two", "three"};
string* p1 = &nums[0];	//p1指向nums的第一个元素
string* p2 = nums;		//等价于p2 = &nums[0]

指针与迭代器

vector和string迭代器支持的运算,数组的指针全部支持。

int arr[] = {0, 1, 2, 3, 4};
int* p = arr;		//p指向arr[0]
++p;				//p指向arr[1]

//使用指针遍历数组
int* e = &arr[5];	//此时e指向arr尾元素的下一个位置
for(int* b = arr; b != e; ++b)
	cout << *b << endl;

//标准库函数begin和end
//上面的用法其实很容易出错,所以C++新标准引入了两个函数
int* beg = begin(arr);	//指向a首元素的指针
inr* last = end(arr);	//指向a尾元素的下一个位置的指针
//注意:尾后指针不能执行解引用和递增操作

指针运算

指针的位置改变或者计算指针与指针之间的距离。

函数指针

函数指针指向函数而非对象,函数的类型由它的返回类型和形参类型共同决定,与函数名无关。

int test1(int a){
	return a;
}
int main(int argc, const char* argv[]){
	int (*fp)(int a);
	fp = test;
	cout << fp(2) << endl;
	return 0;
}
//函数指针可以作为参数传递给函数
int test2(int (*fun)(int), int b){
	int c = fun(10) + b;
	return c;
}
int main(int argc, const char* argv[]){
	typedef int (*fp)(int a);
	fp f = test;
	cout << test2(f, 1) << endl;
	return 0;
}

类中的指针

指向类对象的指针

可以使用指向类对象的指针,访问类对象的public方法和成员变量。

this指针

系统在创建对象时,默认生成的指向当前对象的指针。
基于this指针的自身引用还被广泛应用于那些智齿多重串联调用的函数中。比如连续赋值。

多态

总结来说,就是“一个接口,多种方法”。

  • 静态多态:编译期间的多态,编译阶段决定运行哪个函数。
  • 动态多态:运行时的多态,在程序执行期间判断所引用对象的实际类型,调用相应的方法。
  • 虚函数:在基类中使用关键字virtual声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。
  • 纯虚函数:在基类中声明的虚函数,在基类中没有定义,但要求任何派生类都要定义自己的实现方法。用法是在虚函数后面加=0。可以使用纯虚函数定义接口类。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

随处可见的打字员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值