详解C++中的指针、数组指针与函数指针_C 语言

C++中一个重要的特性就是指针,指针不仅具有获得地址的能力,还具有操作地址的能力。指针可以用于数组、或作为函数的参数,用来访问内存和对内存的操作,指针的使用使得C++很高效,但是指针也非常危险,使用不当会带来比较严重的问题。

1、指针

程序中所有的变量和常量都存在一个内存地址中,当然,函数也有对应的内存地址,内存地址的不同会导致程序执行时有所不同。

指针就是用来控制和存储内存地址的变量,它指向单个对象的地址,除了void之外,指针的数据类型与所指向地址的变量数据类型保持一致。

2、如何定义指针、数组指针、函数指针

常见的指针定义有3种:变量指针、数组指针和函数指针的定义。

(1)、变量指针的定义

复制代码 代码如下:

int* p=0;   //定义指针p,并初始化指针为0,即指向的地址为0000 0000 
或 
int a=0;    //定义初始化常量a 
int* p; //定义指针p 
p=&a;   //指针p指向a的地址,即指针获取地址 

(2)、数组指针的定义

复制代码 代码如下:

int a[]={0,1,2,3,4,5,6,7,8,9};  //定义数组 
int* p=a;   //定义并赋值数组指针,即获得数组的首地址 

(3)、函数指针的定义

复制代码 代码如下:

int f();    //定义函数 
int (*p)(); //定义函数指针 
p=f;    //赋值函数指针,即获得函数代码的首地址 

 

区别变量指针、数组指针和函数指针的定义,示例代码如下。

#include<iostream>
using namespace std; 

int f() //定义一个函数
{
  cout<<"测试函数指针的使用"<<endl<<endl;
  return 0;
} 

void main()
{
  cout<<"==========变量指针的使用=========="<<endl;
  int a=5;
  int* p=0;  //初始化指针为0
  int* q;   //定义指针
  q=&a;    //赋值指针
  cout<<"a = "<<a<<endl;    //变量a的值
  cout<<"a = "<<*q<<endl;    //变量a的值
  cout<<"p = "<<p<<endl;    //指针p的地址为0000 0000
  cout<<"&a = "<<&a<<endl; //获取a的地址
  cout<<"&a = "<<q<<endl;    //获取a的地址 

  cout<<"==========数组指针的使用=========="<<endl;
  int b[]={0,1,2,3,4,5,6,7,8,9};
  int* pb=b;   //直接指向第一个元素的地址
  cout<<pb<<endl //第1个元素的地址,即数组的首地址
    <<b<<endl  //第1个元素的地址,即数组的首地址
    <<*pb<<endl //第1个元素的值
    <<(*pb+2)<<endl;  //第3个元素的值 

  cout<<"==========函数指针的使用=========="<<endl;
  int f();    //定义函数
  int (*pf)();  //定义函数指针
  pf=f;      //赋值函数指针,即将函数的首地址赋值给指针pf
  (*pf)();    //通过函数指针调用函数
}

 结果如下图:

3、数组指针与指针数组

数组指针是一个指针变量,它指向一个数组,即指向一个数组的指针就是数组指针;而指针数组是一个只包含指针元素的数组,它的元素可以指向相同类型的不同对象。

4、函数指针与指针函数

函数指针就是指向函数的存储空间地址的指针,可以对函数指针进行赋值并且通过函数指针来调用函数,它的本质是一个指针。而指针函数只是说明它是一个返回值为指针的函数,其本质是一个函数。

5、引用传递、值传递和指针传递

C++语言中,函数的参数和返回值的传递方式有3种:即值传递、引用传递和指针传递。

(1)、值传递

形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。

(2)、指针传递

形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。

(3)、引用传递

形参相当于是实参的“别名”,对形参的操作其实就是对实参的操作,在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

最后,总结一下指针和引用的相同点和不同点

相同点:

都是地址的概念,指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。

不同点:

指针是一个实体,而引用仅是个别名;

引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”,指针可以“见异思迁”;

引用没有const,指针有const,const的指针不可变;(具体指没有int& const a这种形式,而const int& a是有的,前者指引用本身即别名不可以改变,这是当然的,所以不需要这种形式,后者指引用所指的值不可以改变)

引用不能为空,指针可以为空;

“sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;

指针和引用的自增(++)运算意义不一样;

引用是类型安全的,而指针不是(引用比指针多了类型检查)。

以上就是本文的全部内容,希望对大家的学习有所帮助。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索指针
值传递
c语言函数指针数组、c语言指针详解、c语言二级指针详解、c语言指针详解视频、c语言指针用法详解,以便于您获取更多的相关知识。

时间: 2024-10-03 13:11:41

详解C++中的指针、数组指针与函数指针_C 语言的相关文章

详解WordPress中用于合成数组的wp_parse_args()函数_php技巧

wp_parse_args() 函数是 WordPress 核心经常用到的函数,它的用途很多,但最主要用来给一个数组参数(args)绑定默认值. 因为 wp_parse_args() 函数返回的一定是一个数组,所以他会把传入查询字符串和对象(object)自动转换成数组,给了使用者更加方便的条件,也增加了兼容性. 常见的 query_posts().wp_list_comments() 和 get_terms() 函数都使用了 wp_parse_args() 函数来帮它给数组参数添加默认值. 用

详解C++中new运算符和delete运算符的使用_C 语言

C++ 支持使用 new 和 delete 运算符动态分配和释放对象.这些运算符为来自称为"自由存储"的池中的对象分配内存. new 运算符调用特殊函数 operator new,delete 运算符调用特殊函数 operator delete. 在 Visual C++ .NET 2002 中,标准 C++ 库中的 new 功能将支持 C++ 标准中指定的行为,如果内存分配失败,则会引发 std::bad_alloc 异常. 如果内存分配失败,C 运行库的 new 函数也将引发 st

详解C#中委托,事件与回调函数讲解_C#教程

.Net编程中最经常用的元素,事件必然是其中之一.无论在ASP.NET还是WINFrom开发中,窗体加载(Load),绘制(Paint),初始化(Init)等等. "protected void Page_Load(object sender, EventArgs e)"这段代码相信没有人不熟悉的.细心一点一定会发现,非常多的事件方法都是带了"object sender, EventArgs e"这两个参数.这是不是和委托非常相似呢? 一.委托(有些书中也称为委派)

详解C++中StringBuilder类的实现及其性能优化_C 语言

介绍经常出现客户端打电话抱怨说:你们的程序慢如蜗牛.你开始检查可能的疑点:文件IO,数据库访问速度,甚至查看web服务. 但是这些可能的疑点都很正常,一点问题都没有. 你使用最顺手的性能分析工具分析,发现瓶颈在于一个小函数,这个函数的作用是将一个长的字符串链表写到一文件中. 你对这个函数做了如下优化:将所有的小字符串连接成一个长的字符串,执行一次文件写入操作,避免成千上万次的小字符串写文件操作. 这个优化只做对了一半. 你先测试大字符串写文件的速度,发现快如闪电.然后你再测试所有字符串拼接的速度

详解C++中的一维数组和二维数组_C 语言

C++一维数组 定义一维数组 定义一维数组的一般格式为:     类型标识符  数组名[常量表达式]; 例如: int a[10]; 它表示数组名为a,此数组为整型,有10个元素. 关于一维数组的几点说明: 1) 数组名定名规则和变量名相同,遵循标识符定名规则. 2) 用方括号括起来的常量表达式表示下标值,如下面的写法是合法的: int a[10]; int a[2*5]; int a[n*2]; //假设前面已定义了n为常变量 3) 常量表达式的值表示元素的个数,即数组长度.例如,在"int

详解Java中ByteArray字节数组的输入输出流的用法_java

ByteArrayInputStream 介绍ByteArrayInputStream 是字节数组输入流.它继承于InputStream. 它包含一个内部缓冲区,该缓冲区包含从流中读取的字节:通俗点说,它的内部缓冲区就是一个字节数组,而ByteArrayInputStream本质就是通过字节数组来实现的. 我们都知道,InputStream通过read()向外提供接口,供它们来读取字节数据:而ByteArrayInputStream 的内部额外的定义了一个计数器,它被用来跟踪 read() 方法

详解C#中通过委托来实现回调函数功能的方法_C#教程

委托(delegate)是一种可以把引用存储为函数的类型,这类似于c++中的函数指针. 回调函数c++中的回调函数,就是用函数指针来实现的.类似的,c#中用委托,来实现回调函数的功能. 回调函数为什么被称为回调函数?比如你调用了一个函数,那么就叫调用,但是如果你在调用一个函数的时候,还需要把一个函数提供给该函数,让这个函数来调用你的函数,那么你提供的这个函数就被称为回调函数(callback). 对于python这样的动态语言而言,就没有c#,c++提供特殊的语法实现回调函数,因为在python

详解WordPress中添加和执行动作的函数使用方法_php技巧

add_action()(添加动作)add_action() 函数用来挂载一个函数到动作钩子上. 用法 add_action( $tag, $function_to_add, $priority, $accepted_args ); 参数 $hook (字符串)(必须)挂载函数的动作名称. 默认值:None $function_to_add (回调函数)(必须)挂载的函数,直接填写字符串形式的函数名即可. 默认值:None $priority (整数)(可选)动作执行的优先级,数值越小越先被执行

C语言中操作密码文件的一些函数总结_C 语言

C语言setpwent()函数:从头读取密码文件中的账号数据 头文件: #include <pwd.h> #include <sys/types.h> 定义函数: void setpwent(void); 函数说明:setpwent()用来将getpwent()的读写地址指回密码文件开头. 范例 #include <pwd.h> #include <sys/types.h> main() { struct passwd *user; int i; for(i

详解次小生成树以及相关的C++求解方法_C 语言

次小生成树的定义设 G=(V,E,w)是连通的无向图,T 是图G 的一个最小生成树.如果有另一棵树T1,满 足不存在树T',ω(T')<ω(T1) ,则称T1是图G的次小生成树. 求解次小生成树的算法约定:由T 进行一次可行交换得到的新的生成树所组成的集合,称为树T的邻集,记为N(T). 定理 3:设T是图G的最小生成树,如果T1满足ω(T1)=min{ω(T')| T'∈N(T)},则T1是G 的次小生成树. 证明:如果 T1 不是G 的次小生成树,那么必定存在另一个生成树T',T'=T 使得