C/C++指针介绍与使用详解

 更新时间:2022年08月26日 16:27:07   作者:露忆丶十二  
不知从何时起对你一眼万年,从此,每一天被赋予了特别的意义。时隔多年,依然挥之不去是你------指针!!!本篇中几乎数据类型只用了int,但是float、double等也是可以的

什么是指针

C/C++语言拥有在程序运行时获得变量的地址和操作地址的能力,这种用来操作地址的特殊类型变量被称作指针。

翻译翻译什么tmd叫tmd指针!

变量或常量的指针存储的数据是 :对应的变量或常量在内存中的地址。

图解:

此时 我们定义三个指针 p1, p2, p3 分别指向a, b, c ,那么p1中存储的数据是变量a所占用内存的首地址:0x00;

b和c中存储的数据是什么呢? 没错,就是0x02和0x04。

显然。若要知道变量a的值,首先读取指针p1中的数据0x00,然后读取内存0x00和0x01中的数据就可以了。这个时候,会出现一个问题:怎么才能确定究竟要读取几个单位内存中的数据呢?毕竟p1中只存储了0x00呀。这个时候 ,指针的类型就发挥了作用。举个例子:如果定义的指针是int类型的,那么读取的时候自动从指针中存储的初值向后读取4个字节;float类型的指针就是读取8个字节。这样就可以既完整又不多余的取出所需要的数据了。

总结一下一个指针的两个要素:指针类型和指针所指变量的初地址。

定义指针变量

指针在定义的时候最好直接初始化,否则可能出现意想不到的结果。

@定义一个指向变量的指针。

/*定义一个指向int类型变量a的指针p*/
int a = 3;
int * p;	
p = &a;	//把a的地址赋值给p;
/*下面的语句最好不要用!!!!*/
p = &28;	//这也是可以的,p指向的地址中存储的数据是28.
/*可以用下面的语句代替上面的语句*/
*p = 28;

间接引用指针

间接引用操作符也是 *

*p 取出p指向的内存空间中的值。

所以区分定义或是引用指针可能有些麻烦。

只有同类型的指针和变量才能通过 * 和 & 互相建立关系。

int a = 0;
int temp;
int * p = &a;
/*指针的间接引用*/
cout<< *p;	//输出结果是0
/*以下两种表达等价*/
*p = 3;	//把3赋值给a
a = 3;
/*以下两种表达效果相同。都是把变量a赋值给temp*/
temp = a;
temp = *p;	//temp被赋值为0
/* 以下表达是错误的*/
float f = 3.1;
int * p = &f;	//error,指针类型与变量类型不匹配 

常or常常

这个部分本来应该在定义指针变量里,但是因为需要指针的间接引用作为铺垫,所以把它单独拿出来了

我们先区分一组概念:常量、指向常量的指针、常指针以及指向常量的常指针。

1.常量:顾名思义不发生改变的量,想必大家是熟悉的。

2.指向常量的指针:只限制间接访问操作,不限制指针指向的值本身的操作规范。

3.常指针:指针中存储的地址一经初始化就不能改变了,也就是说常指针只能指向一个固定的地址,但是地址中存储的数据是可以改变的哦~

4.指向常量的常指针:根据上面三个概念大家应该可以理解了,就是指针中存储的地址和该地址中的数据皆不可更改。

例如:

int b = 4;
const int a = 5;	//定义一个常量a。
/*注意观察以下三个定义中const的位置*/
const int *p = &a;	//定义一个指向常量的指针p,指向常量a。
p = &b;	//这个也是没问题的哦
*p = 6;	//error,这个间接访问操作是不可以。 
int * const p2 = &b;//定义一个常指针p2
*p2 = 6;	//这个是可以的,注意区分和上面的区别
const int * const p3 = &a;	//指向常量的常指针p3
/* emm我也不知道该注释点什么,自行体会吧~*/
*p = 11;	//error,因为p指向的是常量,常量的值不可更改
*p2 = 2;	//true,p2是常指针,指向的地址不变,但地址中的值可以更改
*p3 = 4;	//error
p3 = &b;	//error

指向指针的指针

指针本质上也是一个变量或常量,那么指针也是有地址的,而指向这些地址的指针被称为指向指针的指针。

int a = 25;
int * p  = &a;
int pp = &p;	//true,pp指向的地址中存储的是指针p的地址。 

指针与数组

一个数组的数组名就是一个常指针。

int arr[] = {5,4,6,9,8,3};

arr就是一个指针,而且指向数组的第一个元素arr[0]。

指针数组:

char * arr[] ={"this is", "a", "C++ !"}; 

在此提及一下字符串常量:

char * a 
/*
双引号的作用:
	在字符串结尾加一个\0,并分配内存空间,返回首地址。
*/
a = "dshfw";	

指针的运算

指针只能支持 + 和 - 的运算,但这已经足够满足大多数指针操作的需求了。

/*接下来以数组为例,只介绍加法 ,减法同理*/
int arr[] = {5,4,6,9,8,3};
cout<< *p;	//输出结果为5
cout<< *(p+1);	//输出结果为4
/*打印整个数组*/
for(int *p = arr; p < arr+5; ++p)
{
	cout<< *p<<' ';
}
cout<<endl;

堆内存分配

C语言

/*函数原型*/
void * malloc(size_t size);
/*使用:开辟5个int类型变量的存储空间,返回首地址*/
/**/
int *arr;
if(arr = (int *) malloc(5 *sizeof(int)) == NULL)
{
	exit(1);
}
/*释放堆内存*/
free(arr);

C++语言

注意释放数组内存空间时,delete后有[] !!!

/*申请一个5个元素的数组空间*/
int * arr = new int[5];
delete[] arr;
/*申请一个变量的空间*/
int * arr = new int;
delete arr;

指针与函数

函数名和数组名一样都是一个指针,有时我们需要把函数名作为参数传入其他函数中。

数组名作为函数的入口参数

arr[] = {4,6,9,8,5,3,2,7,5};
/*两种不同的写法均可以*/
void Sort_Shell(int arr[], int n)
{
/*code*/
}
void Sort_Shell(int * arr, int n)
{
/*code*/
}
/*下面这种是不可以的!!!*/
void Sort_Shell(int * arr[], int n)
{
/*code*/
}

举个小小的例子

/*来个小小的希尔排序算法*/
void Sort_Shell(int arr[], int n)
{
	int gap = n / 2;
	for(; gap > 0; gap /= 2)
	{
		for(int i = gap; i <n; ++i)
		{
			int temp = a[i];
			int j = i;
			while(j >= gap&& temp < arr[j -  gap])
			{
				a[j] = a[j - gap];
				j -=gap;
			}
			a[j] = temp;
		}
	}
}

开了个小差,接下来回归正题,我们的指针。

函数名作为参数传入其他函数

static bool cmp(int a, int b)
{
	return a < b;
}
void show(bool * b)
{
	if( &b)
	{
		cout<< true;
	}
	else
	{
		cout<<false;
	}
}

使用指针修改函数参数

首先来看个例子:

void swip(int a, int b)
{
	int c = a;
	a = b;
	b = c;	
}
int main()
{
	int a = 5, b = 6;
	swip(a, b);
	cout<<a<<' '<<b;
}

输出结果:5 6

并未达到交换的效果,因为函数内部对形参的修改并不能反映到上层的main函数中。

此时我们可以通过指针作为函数的入口参数来实现预期的功能。

void swip(int * a, int* b)
{
	int c = *a;
	*a = *b;
	*b = c;	
}
int main()
{
	int a = 5, b = 6;
	swip(&a, &b);
	cout<<a<<' '<<b;
}

输出结果:6 5

传递函数的指针虽然能达到预期效果,但是确实以破坏函数的黑盒为代价,可读性差,调试困难。

有没有什么更好的办法呢?接下来 引用登场了。

变量的引用作为函数的参数

void swip(int &a, int &b)
{
	int c = a;
	a = b;
	b = c;	
}
int main()
{
	int a = 5, b = 6;
	swip(a, b);
	cout<<a<<' '<<b;
}

输出结果:6 5

克服了指针作为参数的弊端。话又有点多了,哈哈,这和指针有什么关系呢······

两个常用的字符串函数

  • strcmp() :用于比较字符串的大小。
  • strcpy() :复制字符串。
//函数原型
int strcmp(const char * arr1, const char * arr2);
//使用举例:
char arr1[] = "dfetf";
char arr2[] = "cfefef";
int b = strcmp(arr1, arr2);

输出b的值是大于0 的。

总结

指针强大而又危险,却也是C和C++的灵魂,由于其可以直接操作内存地址的特殊性,使得理解指针是如何工作的在C和C++中必不可少,若想成为一名优秀的C++工作者,必须要掌握指针。

到此这篇关于C/C++指针介绍与使用详解的文章就介绍到这了,更多相关C++指针内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • c++中queue用法超详细讲解(入门必看!)

    c++中queue用法超详细讲解(入门必看!)

    queue是一种容器转换器模板,调用#include< queue>即可使用队列类,下面这篇文章主要给大家介绍了关于c++中queue用法超详细讲解的相关资料,需要的朋友可以参考下
    2022-10-10
  • 基于openCV实现人脸检测

    基于openCV实现人脸检测

    这篇文章主要为大家详细介绍了基于openCV实现人脸检测的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • OpenCV相机标定的全过程记录

    OpenCV相机标定的全过程记录

    这篇文章主要给大家介绍了关于OpenCV相机标定的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-03-03
  • C语言项目爬楼梯的两种实现方法参考

    C语言项目爬楼梯的两种实现方法参考

    今天小编就为大家分享一篇关于C语言项目爬楼梯的两种实现方法参考,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-02-02
  • C语言实现学生选修课程系统设计

    C语言实现学生选修课程系统设计

    这篇文章主要为大家详细介绍了C语言实现学生选修课程系统设计,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-02-02
  • Qt GUI图形图像开发之Qt表格控件QTableView简单使用方法及QTableView与QTableWidget区别

    Qt GUI图形图像开发之Qt表格控件QTableView简单使用方法及QTableView与QTableWidget区

    这篇文章主要介绍了Qt GUI图形图像开发之Qt表格控件QTableView简单使用方法,需要的朋友可以参考下
    2020-03-03
  • C语言实现二值图像模拟灰值图像显示效果

    C语言实现二值图像模拟灰值图像显示效果

    这篇文章主要为大家详细介绍了C语言实现二值图像模拟灰值图像显示效果,分为图案法、抖动法两个方法实现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • C语言实现逆序输出详细

    C语言实现逆序输出详细

    这篇文章主要介绍了C语言实现逆序输出。主要实现C语言实现对数组元素依次赋值然后按照逆序输出,下面文章小编将详细解说,需要的朋友可以参考一下
    2021-10-10
  • C语言函数指针数组实现计算器功能

    C语言函数指针数组实现计算器功能

    这篇文章主要通过C语言函数指针数组实现了计算器的功能,是一个很好而且流程详细的小例子,感兴趣的新手朋友们可以自己动手也写一遍
    2022-04-04
  • 零基础学习C/C++需要注意的地方

    零基础学习C/C++需要注意的地方

    这篇文章主要介绍了零基础学习C/C++需要注意的地方,文中讲解非常细致,供大家参考和学习,想要学习C/C++的可以阅读此文
    2020-06-06

最新评论