欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C/C++—指针基础小结

程序员文章站 2022-03-05 08:08:11
...

C/C++—指针基础小结


想必大多数正在学、学过C语言的人都有个体会:指针确实不好学。不仅是因为其本身奇怪的定义,也因为对于许多开发者(例如我)来说,如果不从事硬件开发、操作系统开发、C/C++方面的开发的话,指针的用处确实不大。且指针属于C/C++独有的内容,如果习惯使用其他语言进行工作,哪怕曾经学了指针,也会“用进废退”。
近来由于备战一些考试和竞赛,加之时不时被学弟学妹们问的一些问题哽住,便痛下决心,重新梳理一遍指针。也许内容不是太全,主要适用于为本科阶段计算机的学习打基础。

1.为什么要提出指针/什么是指针

前面提及,指针是C/C++的独有内容,指针的产生也与这两门语言本身的特性有关——偏底层。相比起如Java、Python、C#等其他语言,C/C++更多地支持对硬件、操作系统的控制。
从本质上来说,指针是用于操作内存的。关于内存、数据存储等概念,在此不作概述。现在我们要明白的一个核心概念就是,指针的作用是访问程序中的变量存在电脑中的地址

2.指针的相关定义及性质

2.1指针的运算

指针独有的两个运算符如下:

*
&

其中第一个“*“用于定义指针变量,“&”用于取地址;两个符号互为逆运算。

2.2指针变量的定义及使用

指针变量的定义方法:
数据类型 *变量名;
例如如下代码:

int *a;//定义变量a为一个nt类型的指针变量

那么如何体现指针对地址的操作呢?我们看如下代码:

#include<iostream>
using namespace std;
int main() {
	int *a; 
	cout<<a<<endl;
	return 0;
	}

程序输出为0x191380。很明显,这是计算机中的一个地址值,由于已经定义了a为指针变量,直接输出便是读取了其地址值。
以上为“*”操作符的一个运行示例,那么“&”取地址符又是怎么用呢?
指针变量名 =&被取地址的变量名;
我们来看一下两段代码:

#include<iostream>
using namespace std;
int main() {
	int a=20; 
	int *b;
	b=&a;
	cout<<b<<endl;
	return 0;//输出为地址值
}

#include<iostream>
using namespace std;
int main() {
	int a=20; 
	int *b;
	b=&a;
	cout<<*b<<endl;
	return 0;//输出20
}

由于定义了b是一个指针变量,其便具有了指针的功能;之后取地址符&变起到了将a的地址值赋给b的作用。
那么为什么前一段代码输出为地址值,后一段为int数据类型呢?这只因为:前一段代码,由于b已经是一个指针变量了,与前文一样,作为指针,输出的是地址;后一段代码,加上了星号,等于又强调了“b毕竟还是个变量”,因次输出为替换了新地址后该内存空间内存储数据的值。
特别强调:未先定义指针变量,无法使用“&”运算符;或者说,即使敲出了“&”并成功运行,那也并非为指针范围的运算。
由此便也体现出指针的作用之一:我不直接赋值,但我可以通过改变地址值来访问这个变量。
这就好比,虽然很多人没出生在北京,不能生下来就直接获得北京户口;但通过买了北京的房,取得了北京的住所(地址),获得了北京户口。
(此处只是一个比喻,本蒟蒻未曾有过北漂梦,也不是在北京上大学或工作,比喻如有不当还望谅解嘿嘿)
到此,指针的核心概念算是结束了。但如果仅仅如此,那指针岂不是很简单?所以接下来,难度加大~

2.3指针的指针

没错,前面说的是变量的指针,可指针本身也是有指针的。
指针的指针的定义格式如下:
数据类型 **指针的指针变量名;
确实,就是在定义好得出指针变量前再加上一个星号,那么指针的指针怎么用?我们通过下面一段代码便可以看出:

#include<iostream>
using namespace std;
int main() {
	int a=24; 
	int *b;
	b=&a;
	int **c;
	c=&b;
	cout<<**c<<endl;
	return 0;//输出为24
}

很明显,b取了a的地址,可c作为一个能对b“下手”的指针,又取了b的地址,输出了a的值。
这就好比:纽约原本是印第安人的地盘(a的地址),被荷兰人用水晶球骗到了(b取了a 的地址),最后又被美国人用24美元买到手(c取了b的地址)。于是乎,印第安小帐篷和荷兰人都不见了,取而代之的是繁(e)华(chou )的大都会。

2.4指针表达式

本部分内容主要是讲一些指针在写入表达式里的“骚操作”。来吧,翻过这座山~
(你会看到更多的山hhh)
前面我们已经掌握了*和&,这两个磨人的小妖精了,可运算符并不止他俩鸭~
先来看一个很正常的代码片段:

char ch='x';
char *cp=&ch;

这里很好理解,char类型的变量初始化赋值为“x”,指针变量cp取了它的地址
可如果是这么一个玩意儿呢?

*cp+1

是不是觉得很神奇?指针居然都还可以作加减?别慌,让我们冷静下来:
我们都知道,char类型字母+1,即代表字典序加一;而这里的*cp是一个指针变量,且取了地址,即这个地址存储的char类型数据字典序加一。
运行下面代码,果不其然:

```cpp
#include<iostream>
using namespace std;
int main() {
	char ch='a';
    char *cp=&ch;
    char ck=*cp+1;
    cout<<ck<<endl;
	return 0;//输出为b,即a的字典序加一
}

再来看一个例子:

#include<iostream>
using namespace std;
int main() {
	char ch='a';
    char *cp=&ch;
    char ck=*(cp+1);
    cout<<ck<<endl;
	return 0;//什么都没有输出
}

为什么会这样?因为这里的*(cp+1)访问的不再是变量值了,而是访问了之后的一个内存地址。可问题是,我们并不知道这后面地址是什么。这样,这个指针指向了一个未知域,即这是一个野指针
由此,我们可以看出,指针可做加减运算,也会有自己本身的物理意义。但这样的操作能否有效,还需视具体情况而定。对于这一类表达式,我们只用保持冷静,心中装着一件事:
弄清楚这里究竟是要描述一个变量值还是内存地址?
类似的,还有++*++cp,(*cp)++等诡异的式子,在此不作赘述。

总结

指针作为C/C++中基础部分比较难的部分,常令初学者痛苦不已。指针的学习首先需要对内存的概念有相对清晰的认识,然后紧抓“*”和“&”互为逆运算、“是变量or地址”这两个重要概念。
当然,指针的应用还有很多,具体地与函数、数组、结构体、数据结构的结合使用,我们以后再聊~
感谢阅读,希望对你有用:)

相关标签: 经验总结