一个传值的问题”*”与”*”

1/*********************************************************
2* Desc:参数传递:使用引用传递指针和直接传递指针地址的区别
3* Author:charley
4* DateTime:2010-12-7 11:00
02***********************************************************/
03#include <iostream>
04using namespace std;
05  
06/*
07函数声明
08*/
09void swapByRef(int *&,int *&);
10void swapByPoi(int *,int *);
11  
12int main(void)
13{
14    inti=10;
15    intj=20;
16    int*pi=&i; //pi指向i所在的内存地址
17    int*pj=&j;//pj指向j所在的内存地址
18      
19    //通过引用传递参数,传递的是指针本身
20    cout<<"调用swapByRef()之前:pi="<<pi<<",*pi="<<*pi<<";pj="<<pj<<",*pj="<<*pj<<endl;
21    swapByRef(pi,pj);
22    cout<<"调用swapByRef()之后:pi="<<pi<<",*pi="<<*pi<<";pj="<<pj<<",*pj="<<*pj<<endl;
23      
24    cout<<"**********************"<<endl;
25  
26    //通过指针来传递参数,传递的是指针地址
27    cout<<"调用swapByPoi()之前:pi="<<pi<<",*pi="<<*pi<<";pj="<<pj<<",*pj="<<*pj<<endl;
28    swapByPoi(&i,&j);
29    //或者直接 swapByPoi(pi,pj);
30    cout<<"调用swapByPoi()之后:pi="<<pi<<",*pi="<<*pi<<";pj="<<pj<<",*pj="<<*pj<<endl;
31  
32    getchar();
33    return0;
34}
35  
36/*
37通过引用传递参数:
38参数为整型指针的引用,
39引用是指针的一个别名,传递时不需要在内存中分配空间来接收参数
40参考:swapByRef(int &v1,int &v2)
41*/
42void swapByRef(int *&v1,int *&v2)
43{
44    int*temp=v1;//指针赋值,指针执行的地址变化了
45    v1=v2;
46    v2=temp;
47}
48  
49/*
50通过指针来传递参数:
51参数为整型指针变量
52内存存需要为形参分配空间来接收传进来的指针地址
53参考:swapByPoi(int v1,int v2)
54*/
55void swapByPoi(int *v1,int *v2)
56{
57    inttemp=*v1; //操作指针指向的内容,指针执行的地址未变化
58    *v1=*v2;
59    *v2=temp;
60}

执行结果:

1

 

从结果可以看出:

1. swapByRef方法是直接交换参数的指针执行的地址,所以指针指向的内容也换了

2. swapByPoi方法只是操作指针指向的内容,指针执行的地址未变化

 

 

#include <stdio.h>

void swap(int x,int y)//这是错误的写法
{
int temp;
temp=x;
x=y;
y=temp;
}

int main()
{
int a=5,b=8;
swap(a,b);
printf("%d %d\n",a,b);
return 0;
}

代码很容易理解,就是交换2个变量a和b的值并输出,但是运行后我们发现输出结果不是"8 5"而依旧是"5 8",也就是说交换函数并没有将2个变量的值交换,这是为什么呢?

我们知道,C语言中整型变量的形式参数传递的是值而不是地址,也就是形式参数实际上是复制了实际参数的值进入函数运算的,而被复制的实际参数的值并没有改变。就这段代码来说,就是形参x复制了a的值变成5,形参y复制了b的值变成8,然后在swap函数中进行交换,使得x=8,y=5,但实际上a和b的值并没有被交换,这也就是为什么这段代码并没有实现交换的原因。

那么怎么解决呢?

先前我们说了C语言中整型变量的形式参数传递的是值而不是地址,那么现在我们就让它传递地址,直接交换实际参数的值。

#include <stdio.h>

void swap(int *x,int *y)//使用指针传递地址
{
int temp;
temp=*x;
*x=*y;
*y=temp;
}

int main()
{
int a=5,b=8;
swap(&a,&b);
printf("%d %d\n",a,b);
return 0;
}

我们使用指针变量来进行地址传递,形式参数为变量a和b的地址,swap函数直接交换a和b的地址所指向的值。这里一定注意形式参数传递的是地址而不是值

 

 

 

C++引用&和指针在作为形参时的区别

int n;

int &m = n;

在C++中,多了一个C语言没有的引用声明符&,如上,m就是n的引用,简单的说m就是n的别名,两者在内存中占同样的位置,不对m开辟新的内存空间,对m的任何操作,对n来说是一样的。

对于引用,有以下三条规则:

(1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
(2)不能有NULL 引用,引用必须与合法的存储单元关联(指针则可以是NULL)。
(3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。

 

假如在一个函数中动态申请内存空间,用指针和用引用作形参会得到不同的结果,如下面的例子:

void fun(int* b){  //用指针做形参
 b = (int*)malloc(sizeof(int)*3);

 for(int i=0; i<3; i++){
  a[i] = i;
 }
}

void fun(int* &b){  //用引用做形参
 b = (int*)malloc(sizeof(int)*3);

 for(int i=0; i<3; i++){
  b[i] = i;
 }
}

如果在main函数中定义了一个int型的空指针并分别作为实参传入,如下:

int main(){
 int *a = NULL;

 fun(a);

 for(int i=0; i<3; i++){
  cout << a[i] << " ";
 }
 cout << "\n";

 return 0;
}

结果用指针的函数会出现内存访问出错,用引用的函数则运行正常并正确输出1 2 3.

这是因为:

1.指针虽然是地址传递,但实际上也是在函数中又定义了一个新的指针让其与传入的指针指向同一地址。但两个指针本身作为变量在内存中的存放地址是不同的,就是说这是两个不同的变量,只是内容(即所指地址)相同。

2.在函数中对新定义的指针动态申请内存,但是当函数结束后,申请的内存的生命周期也就结束了,所以当回到主函数时,作为实参的指针地址和内容都没有变化。仍然是个空指针,对其进行访问自然出现了内存读错误了。

假如在main函数中这样写:

int *a = (int*)malloc(sizeof(int)*3);

就不会出现内存读错误了,但是输出结果还是错误的,道理也是一样的。

3.用引用作为实参传入时,fun函数中的b其实就是主函数中a的别名(或者叫外号),反正就是操作完全相同,地址相同,内容相同的一个变量,所以当fun函数返回时,对b的操作在主函数中对a同样有效。

 

再看一个例子:

int *a = NULL;

char* b = (char*)a;

 

int *a = NULL;

char* &b = (char*)a;

这一次是在编译阶段的区别:

用指针可以通过编译,而用引用则不可以,提示类型转换出错。

 

通过这两个例子可以看出,指针比引用灵活,也更加危险。

 

摘自『高质量c++编程』
条款一:指针与引用的区别
指针与引用看上去完全不同(指针用操作符’*’和’->’,引用使用操作符’.’),但是它们似乎有相同的功能。指针与引用都是让你间接引用其他对象。你如何决定在什么时候使用指针,在什么时候使用引用呢?
首先,要认识到在任何情况下都不能用指向空值的引用。一个引用必须总是指向某些对象。因此如果你使用一个变量并让它指向一个对象,但是该变量在某些时候也可能不指向任何对象,这时你应该把变量声明为指针,因为这样你可以赋空值给该变量。相反,如果变量肯定指向一个对象,例如你的设计不允许变量为空,这时你就可以把变量声明为引用。

 

PS:引用在定义时不可加const,否则编译出错,在形参前面则可以加const以确保在函数中该变量不会被修改。

 

个人认为:其实形参建立的是一个新的地址,只是这地址是实参内容的一个COPY,假如实参为p,形参就为_p;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/254604.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring boot 扩展之AutoConfigurationImportListener

最近阅读spring boot源码时发现&#xff0c;发现当spring使用ConfigurationClassParser加载使用Configuration注解类后&#xff0c;会使用AutoConfigurationImportSelector对加载的 Configuration注解的类进行一次过滤。当AutoConfigurationImportSelector过滤完成后会自动加载…

《高效程序员的45个习惯》-之一

敏捷开发是当下最流行的开发方法&#xff0c;它采用的是一种以人为核心、迭代、循序渐进的开发思想&#xff0c;值得你关注和学习。 最近我就阅读了一本有关敏捷开发的书籍&#xff0c;《高效程序员的45个习惯》。 它以“举反例”的方式来讲述了敏捷开发中程序员应该运用的…

《CLR via C#》之线程处理——线程基础

《CLR via C#》之线程处理——线程基础 《CLR via C#》之线程处理——线程基础windows为什么要支持线程线程开销CPU发展趋势CLR线程和Windows线程使用专用线程执行异步的计算限制操作线程调度和优先级windows为什么要支持线程 早期的操作系统只有一个执行线程&#xff0c;但同时…

spring boot之从零开始开发自己的网站

概述 首先要感谢两位大神&#xff0c;该项目的想法来源自tale和MyBlog。 做了一些改造&#xff0c;增加了一些功能和一些代码的重构&#xff0c;并且更换了博客主题。 关于项目&#xff0c;对于开发的练手项目&#xff0c;能够工程化&#xff0c;严谨一些。 关于文档&#x…

python day5--正则表达式

#----正则表达式 import re elink <a href"(.*)">(.*)</a> info <a href"http://www.baidu.com">baidu</a> cinfo re.findall(elink,info) print (cinfo) import re print(re.search (r^a,abc\neee)) #预期结果 ^匹配字符开…

WCF系列教程之WCF客户端调用服务

1、创建WCF客户端应用程序需要执行下列步骤 (1)、获取服务终结点的服务协定、绑定以及地址信息 (2)、使用该信息创建WCF客户端 (3)、调用操作 (4)、关闭WCF客户端对象 二、操作实例 1、WCF服务层搭建:新建契约层、服务层、和WCF宿主,添加必须的引用(这里不会的参考本人前面的随…

短信认证方案,用手机短信进行上网认证如何实现?

WFilter NGF的“Web认证”模块&#xff0c;提供了一系列的上网认证解决方案。包括如下认证方式&#xff1a;本地用户名密码认证AD域用户名密码认证企业邮箱用户名密码认证Radius用户名密码认证微信WiFi认证Facebook Wifi认证除此&#xff0c;WFilter NGF还有一个“其他”的选项…

Nginx 之一:编译安装nginx 1.8.1 及配置

转http://www.cnblogs.com/zhang-shijie/p/5294162.html 一&#xff1a;基介绍 官网地址www.nginx.org&#xff0c;nginx是由1994年毕业于俄罗斯国立莫斯科鲍曼科技大学的同学为俄罗斯rambler.ru公司开发的&#xff0c;开发工作最早从2002年开始&#xff0c;第一次公开发布时间…

PI校正环节的程序实现推导过程

PI校正环节在经典控制论中非常有用&#xff0c;特别是对负反馈控制系统&#xff0c;基本上都有PI校正环节。1.下面分别说明比例环节和积分环节的作用&#xff0c;以阶跃信号为例。①比例环节单独作用以上分析说明&#xff0c;若只有比例环节的控制系统&#xff0c;阶跃响应也是…

vs里根据json快速创建对应类的方法

有时候,我们在调用别人接口的时候,服务端返回了一个json格式的字符串,我们要获取json里面的数据的话一般有两种方式: 1.通过正则 2.反序列化成一个对象 第一种方式这里不再多说,主要说一下第二种,(为什么呢&#xff0c;你看到后面 你也会喜欢上第二种) 有人肯定会说, json字符串…

人工智能之基于face_recognition的人脸检测与识别

不久乘高铁出行&#xff0c;看见高铁火车站已经实现了“刷脸进站”&#xff0c;而且效率很高&#xff0c;很感兴趣&#xff0c;今天抽时间研究一下&#xff0c;其实没那么复杂。 我基本上是基于https://github.com/ageitgey/face_recognition上的资料和源码做一些尝试和试验。 …

iOS 升级https的方案选择

我的选择是将UIWebView统一替换为WKWebView WKWebView AFN SDWebImage https的支持之前的博客都有涉及转载于:https://www.cnblogs.com/Jusive/p/6867531.html

Python3抓取糗百、不得姐

​点击关注 异步图书&#xff0c;置顶公众号 每天与你分享 IT好书 技术干货 职场知识 重要提示1:本文所列程序均基于Python3.6,低于Python3.6的Python版本可能无法运行.重要提示2:因所抓取的网站可能随时更改展示内容,因此程序也需及时跟进.重要提示3:本程序仅供学习,不能拿去做…

Oracle优化-表设计

前言  绝大多数的Oracle数据库性能问题都是由于数据库设计不合理造成的&#xff0c;只有少部分问题根植于Database Buffer、Share Pool、Redo Log Buffer等内存模块配置不合理&#xff0c;I/O争用&#xff0c;CPU争用等DBA职责范围上。所以除非是面对一个业已完成不可变更的系…

Win10远程桌面 出现 身份验证错误,要求的函数不受支持,这可能是由于CredSSP加密Oracle修正 解决方法...

升级至win10 最新版本10.0.17134&#xff0c;远程桌面连接Window Server时报错信息如下&#xff1a; 出现身份验证错误&#xff0c;要求的函数不正确&#xff0c;这可能是由于CredSSP加密Oracle修正。 解决方法&#xff1a; 运行 gpedit.msc 本地组策略&#xff1a; 计算机配置…

Rsyslog 日志相关内容

[rootserver vusers_home]# rpm -ql rsyslog|more ###.so结尾为模块&#xff0c;模块有分im为输入模块&#xff0c;om 为输出模块/etc/logrotate.d/syslog/etc/pki/rsyslog/etc/rc.d/init.d/rsyslog/etc/rsyslog.conf/etc/rsyslog.d/etc/sysconfig/rsyslog/lib64/rsyslog…

MFC导出对话框类DLL的实现

1.新建基于对话框的应用程序 2.新建MFC DLL工程 3.选择MFC DLL 4.选择扩展Dll选项&#xff08;重要&#xff01;&#xff01;&#xff01;&#xff09; 5.为Dll工程添加一个MFC类&#xff0c;基类为CDialogEx 6.Dll新建的MFC 类中添加resource.h防止编译出错…

身于“乱世”,我们程序员应该如何打算?

今天看了这篇文章&#xff0c; 发现自己也有点生处乱世&#xff0c;不平之感&#xff0c;但是文章的朴实却让我有了一个良好的反省&#xff0c;特此转载 分类&#xff1a; 项目管理 2011-09-04 00:58 770人阅读 评论(12) 收藏 举报 不仅要低头拉车&#xff0c;还要抬头看路。…

es6--箭头函数

基本用法 ES6允许使用“箭头”&#xff08;>&#xff09;定义函数。 var f v > v; 上面的箭头函数等同于&#xff1a; var f function(v) {return v; }; 如果箭头函数不需要参数或需要多个参数&#xff0c;就使用一个圆括号代表参数部分。 var f () > 5; // 等同于…

NYOJ题目839合并

--------------------------- AC代码&#xff1a; 1 import java.util.Scanner;2 3 public class Main {4 5 public static void main(String[] args) {6 7 8 Scanner scnew Scanner(System.in);9 10 int timessc.nextInt(); 11 …