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

目录
  • 什么是指针
  • 定义指针变量
  • 间接引用指针
  • 常or常常
  • 指向指针的指针
  • 指针与数组
    • 指针的运算
  • 堆内存分配
    • C语言
    • C++语言
  • 指针与函数
    • 数组名作为函数的入口参数
    • 函数名作为参数传入其他函数
    • 使用指针修改函数参数
    • 变量的引用作为函数的参数
  • 两个常用的字符串函数
  • 总结

什么是指针

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++指针内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++超详细讲解引用和指针

    目录 引用概念 定义步骤 引用必须初始化 引用初始化后不能更改 引用作为函数的参数可以替代指针变量 常引用 引用作为函数的返回值类型 引用的本质 指针的引用(了解) 指针和引用的区别 引用概念 引用的本质:给已有的变量名 取个别名 //给num取个别名为b int num =100; //&不是取b的地址 只是描述b是num的别名 编译器不会为b开辟新的空间 int &b = num;//num的别名 是b //操作b等价操作num 定义步骤 1.&修饰别名 2.给哪个变量取别名

  • c++智能指针的超详细讲解

    目录 1.什么是智能指针 2.原始指针的问题 3.unique_ptr 4.shared_ptr 5.shared_ptr使用需要注意的点 5.1 不能将一个原始指针初始化多个shared_ptr 5.2.循环引用问题 6.智能指针小结 总结 1.什么是智能指针 从比较简单的层面来看,智能指针是RAII(Resource Acquisition Is Initialization,资源获取即初始化)机制对普通指针进行的一层封装.这样使得智能指针的行为动作像一个指针,本质上却是一个对象,这样可以方

  • C++函数指针与指针函数有哪些关系和区别

    目录 1. 函数指针 1.1 概念定义 1.2 声明方法 1.3 调用方法 1.4 函数指针作为函数参数 1.5 函数指针数组 2. 指针函数 2.1 概念定义 2.2 调用方法 3. 总结 1. 函数指针 1.1 概念定义 函数指针是指向函数的指针变量. 因此函数指针本质上是一个指针变量,只不过该指针变量指向函数.指针变量也可以指向整型变量.字符型.数组,也可以指向函数. C语言中,每一个函数都有一个入口地址,函数指针就指向函数的入口地址,可以通过函数指针来调用函数. 例如 :int (*fu

  • 一起聊聊C++中的智能指针

    目录 一:背景 二:关键词解析 1. auto_ptr 2. auto_ptr 多引用问题 一:背景 我们知道 C++ 是手工管理内存的分配和释放,对应的操作符就是 new/delete 和 new[] / delete[], 这给了程序员极大的自由度也给了我们极高的门槛,弄不好就得内存泄露,比如下面的代码: void test() { int* i = new int(10); *i = 10; } int main() { test(); } 这段代码因为用了 new 而忘了 delete,

  • C++扫盲篇之指针详解

    目录 前言 指针为什么要有类型 指针和数组 二级指针 指针与多态绑定 函数指针 类成员指针 补充:用指针的指针指向指针数组 总结 前言 指针对于学习C/C++的人来说是一道必须迈过去的坎,就像学习九阳神功必须要打通任督二脉一样的道理.虽然说随着智能指针的普及,很少需要程序员再手动操作原始指针, 但是如果你连原始指针的都没学好,那你怎么可能用好智能指针呢? 无论是原始指针还是智能指针,要想用好它就一定要做到知其然,知其所以然. 因为本文阅读对象是有了一定指针基础的童鞋,所以如果你对指针如果是处于一

  • C/C++函数指针深入探究

    目录 函数指针 语法 函数地址 声明 使用函数指针调用函数 深入理解函数指针 使用typedef 简化 函数指针 为什么要使用函数指针? 调用的灵活性和通用性. 试想一下,我们在设计初期并不知道我们的函数的具体实现细节.例如,我们我们想要一个排序函数qsort,但是具体排序法则我们并不确定,是降序还是升序,采用什么算法都不清楚.这些问题是要在用户调用这个函数的时候才能够决定.于是调用者应该自己设计comparator函数,传给qsort函数. 便于面向对象编程. 例如我们设计一个结构体apple

  • C++超详细讲解智能指针

    目录 一.内存泄漏-永恒的话题 二.深度思考 三.智能指针分析 四.小结 一.内存泄漏-永恒的话题 动态申请堆空间,用完后不归还 C++ 语言中没有垃圾回收的机制 指针无法控制所指堆空间的生命周期 下面看一段内存泄漏的代码: #include <iostream> #include <string> using namespace std; class Test { int i; public: Test(int i) { this->i = i; } int value()

  • C++智能指针详解

    目录 一. unique_ptr独占指针 特点 创建方式 传递方式 简单使用 隐藏危险 二. shared_ptr 计数指针 特点 传递方式 隐藏危险 三. weak_ptr 优缺点: 智能指针由原始指针的封装,优点是可以自动分配内存,不用担心内存泄漏问题. 用于解决独占/共享所有权指针的释放,传输等问题. 但是没有原始指针方便. 一. unique_ptr独占指针 特点 都是围绕独占展开 特点一: 如其名,独占.也就是说同一个内存空间同时只能有一个指针来管理. int* pi = new in

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

    目录 什么是指针 定义指针变量 间接引用指针 常or常常 指向指针的指针 指针与数组 指针的运算 堆内存分配 C语言 C++语言 指针与函数 数组名作为函数的入口参数 函数名作为参数传入其他函数 使用指针修改函数参数 变量的引用作为函数的参数 两个常用的字符串函数 总结 什么是指针 C/C++语言拥有在程序运行时获得变量的地址和操作地址的能力,这种用来操作地址的特殊类型变量被称作指针. 翻译翻译什么tmd叫tmd指针! 变量或常量的指针存储的数据是 :对应的变量或常量在内存中的地址. 图解: 此

  • C++11 智能指针之shared_ptr代码详解

    C++中的智能指针首先出现在"准"标准库boost中. 随着使用的人越来越多,为了让开发人员更方便.更安全的使用动态内存,C++11也引入了智能指针来管理动态对象. 在新标准中,主要提供了shared_ptr.unique_ptr.weak_ptr三种不同类型的智能指针. 接下来的几篇文章,我们就来总结一下这些智能指针的使用. 今天,我们先来看看shared_ptr智能指针. shared_ptr 智能指针 shared_ptr是一个引用计数智能指针,用于共享对象的所有权也就是说它允许

  • C语言中指针和数组试题详解分析

    目录 数组题: 程序一(一维数组): 字符数组 程序二(字符数组): 程序三(字符数组): 程序四(字符数组): 程序五(字符数组): 二维数组 程序六( 二维数组): 指针题 程序七( 指针): 程序八( 指针): 程序九( 指针): 程序十( 指针): 程序十( 图): 程序十一( 指针): 程序十二( 指针): 程序十三( 指针): 指针 和 数组 试题解析 小编,在这里想说一下,c语言的最后一节 C预处理,可能还需要一些时间,因为小编,昨天才下载了虚拟机 和 linux 系统,还没开始安

  • C++ 中引用与指针的区别实例详解

    C++ 中引用与指针的区别实例详解 引用是从C++才引入的,在C中不存在.为了搞清楚引用的概念,得先搞明白变量的定义及引用与变量的区别,变量的要素一共有两个:名称与空间. 引用不是变量,它仅仅是变量的别名,没有自己独立的空间,它只符合变量的"名称"这个要素,而"空间"这个要素并不满足.换句话说,引用需要与它所引用的变量共享同一个内存空间,对引用所做的改变实际上是对所引用的变量做出修改.并且引用在定义的时候就必须被初始化.     参数传递的类型及相关要点: 1 按值

  • C++ 中引用和指针的关系实例详解

    C++ 中引用和指针的关系实例详解 1.引用在定义时必须初始化,指针没有要求 int &rNum; //未初始化不能通过编译 int *pNum; //可以 2. 一旦一个引用被初始化为指向一个对象,就不能再指向 其他对象,而指针可以在任何时候指向任何一个同类型对象 int iNum = 10; int iNum2 = 20; int &rNum = iNum; &rNum = iNum2; //不能通过 3. 没有NULL引用,但有NULL指针. int *pNum = NULL

  • C语言 指针与数组的详解及区别

    C语言 指针与数组的详解及对比 通俗理解数组指针和指针数组 数组指针: eg:int( *arr)[10]; 数组指针通俗理解就是这个数组作为指针,指向某一个变量. 指针数组: eg:int*arr[10]; 指针数组简言之就是存放指针的数组: --数组并非指针&&指针并非数组 (1)定义一个外部变量: eg:int value=10; int *p=&value; 举例:当需要在一个函数中用这个变量时:externa int*p;而非extern int p[]; 分析:当用:e

  • C++ 通过指针实现多态实例详解

     C++ 通过指针实现多态实例详解 1.父类(DBConnector) 1)DBConnector.h #include <string> using namespace std; class DBConnector { private: string name; public: DBConnector(); DBConnector(string _name); ~DBConnector(); void show(); }; 2)DBConnector.cpp #include "D

  • Maven build 命令介绍的使用详解

    常用命令: 打包:mvn package 编译:mvn compile 清空:mvn clean(清除编译后目录,默认是target目录) 运行测试:mvn test 安装jar包到本地仓库中:mvn install 跳过测试:mvn xxx -DskipTests 1.创建 Maven 工程 ①.在 src/main/java 新建包 com.ys.maven,然后在这个包中创建类 HelloMaven.java package com.ys.maven; public class Hello

  • Python JWT 介绍和使用详解

    1. JWT 介绍 ​jwt( JSON Web Tokens ),是一种开发的行业标准 RFC 7519 ,用于安全的表示双方之间的声明.目前,jwt广泛应用在系统的用户认证方面,特别是现在前后端分离项目 ​jwt认证流程: ​在项目开发中,一般会按照上图所示的过程进行认证,即:用户登录成功之后,服务端给用户浏览器返回一个 token,以后用户浏览器要携带 token 再去向服务端发送请求,服务端校验 token 的合法性,合法则给用户看数据,否则,返回一些错误信息 ​传统token方式和jw

  • React Fragment介绍与使用详解

    目录 前言 Fragments出现动机 React Fragment介绍与使用 <React.Fragment> 与 <>区别 前言 在向 DOM 树批量添加元素时,一个好的实践是创建一个document.createDocumentFragment,先将元素批量添加到 DocumentFragment 上,再把 DocumentFragment 添加到 DOM 树,减少了 DOM操作次数的同时也不会创建一个新元素. 和 DocumentFragment 类似,React 也存在

随机推荐