引用传递有两种传参方式,具体可参考文章

概括地讲,就是

  • *声明一个形参是指针,所以需要传递指针实参,对应的函数实现也应当遵循指针的语法。这种实现思路并不针对于C或者C++,因为它们都有指针,所以都可以通过指针来达到引用传参的效果,但是这种实现本质上不叫引用传参,因为传递的是指针,而不是实参的引用。

  • &这个操作符,在形参声明时,表示该形参是一个引用,不同于指针,也不是取地址操作符,该引用操作符属于C++的标准。函数被调用时,不会在内存中开辟新的空间,而是相当于给实参起了一个新名字,比如说如下代码中:

    void fun(int &a){
    a=2;
    }
    //调用fun函数
    int num = 1;
    fun(num);

    在这个代码中,调用fun函数时,没有给a形参开辟内存空间,a实际上就是num变量的别名,a和num属于完全一样的存在。

参考链接:

https://stackoverflow.com/questions/57483/what-are-the-differences-between-a-pointer-variable-and-a-reference-variable-in

https://stackoverflow.com/questions/2229498/passing-by-reference-in-c

理解了指针传参和引用传参,再讲一下数组传参。

先思考一下,下面这段代码的输出

#include<iostream>
using namespace std;
//通过数组名称传递
void fun1(int arr[]);
//通过指针传递
void fun2(int *arr);
int main() {
int arr[2] = {2,0};
fun1(arr);
for(int i=0; i<2; i++) {
cout<<arr[i]<<endl;
} cout<<endl<<endl;
fun2(arr);
for(int i=0; i<2; i++) {
cout<<arr[i]<<endl;
} } void fun1(int arr[]) {
arr[0]=9;
arr[1]=8; }
void fun2(int *arr) {
arr[0]=7;
*(++arr)=6;
}

Output:

我们知道数组的本质就是一连串相同数据类型的数据,在内存中是连续存放的,同时数组的名称,就是一个指针,它指向了第一个元素【下标为0】,所以,

fun1(int arr[])
fun2(int *arr)

这两种方式完全一样,本质都是指针。既然如此,那么就需要理解对指针的操作了。

//1.使用[]符号
/*
通过示例程序,可以发现,直接通过'指针[i]'操作,可以直接对相应的数组元素进行修改
*/
arr[0]=9;
arr[1]=8; //2.对指针进行算数运算
/*
arr的值实际上是一个内存地址,同一平台下指针大小都相同
比如PC x86上是4字节,x64上是8字节
但是,不同类型的指针步长不同,比如int类型的指针为4个字节,char类型指针步长为1个字节
所以下面这行代码,如果arr是int类型指针,假设它的值为000000000062FE10,那么++arr之后,它的值为000000000062FE14
如果arr是char类型指针,假设它的值为000000000062FE10,那么++arr之后,它的值为000000000062FE11
*/
++arr; //3.指针解引用
/*
通过'*'对指针进行解引用操作
*/ //4.取出指针的地址'&'
/*
&是取址操作符,但是好像对指针取址也没有什么意义吧
*/

联想到这里,再谈一个容易出错的误区,先思考一下如下代码的输出:

//数组传参求数组长度
#include<stdio.h>
int sizeofarr(int arr[]) {
printf("%d\n",sizeof(arr));
printf("%d\n",sizeof(arr[0]));
printf("%d\n",sizeof(int)); return sizeof(arr)/sizeof(int);
}
int main() {
int arr[10] = {2,0,9,3,2,1,2,5,6,7};
printf("size of arr calculating by parameter: %d",sizeofarr(arr)); printf("\n\n%d\n",sizeof(arr));
printf("%d\n",sizeof(arr[0]));
printf("%d\n",sizeof(int)); printf("the actual size of arr: %d",sizeof(arr)/sizeof(arr[0]));
return 0;
}

sizeof(arr)/sizeof(arr[0])这是一个十分常用的求数组长度的方法,前提是,不把arr传递到函数里面求长度,为什么这么说呢?参考如下打印结果:

我的机子是64位的,所以sizeof(pointer)就是8,所以通过函数来求数组长度得到的结果就是2。

那么如何避免这种错误呢?

要么函数再加一个参数,表示数组的长度,要么定义一个全局的常量表示数组的长度。

参考链接:https://stackoverflow.com/a/10349610

C和C++引用传递和数组传参引用的更多相关文章

  1. python 传值引用和传参引用

    调用同事的函数,传入goods_list,获取商品信息,然后将商品信息与goods_list的信息进行匹配,合并. 但是同事返回数据的同时改变了我传入的参数,goods_list.相当于传参引用,也就 ...

  2. c/c++ 数组传参

    在c/c++中,在进行数组传参时,数组的元素个数默认是不作为实参传入调用函数,也就是说c/c++ 不允许向函数传递一个完整的数组作为参数 实例: 1.形式参数是一个指针,实参包括数组长度: 1 voi ...

  3. c++数组传参

    最近感觉老是碰到数组传参的问题,特别是二维的数组,每次报错都感觉头疼,烦躁:这里必须总结一下了,先把暂时能解决的问题写在这吧,以便以后碰到查看! 先看一个一维数组传参:这样用数组传参是很不安全的:会输 ...

  4. C# 数组 深拷贝 和 数组传参

    前言 C#中引用类型无法使用const,因此传参的时候使用引用类型,一定要注意是否会改变其值.下面介绍几种 数组的 深拷贝方法. 前提 下面的测试代码有一些前提, sw为Stopwatch nForT ...

  5. C++中用二维数组传参时形参该怎样写[转]

    二维数组的存储方式是和一维数组没什么区别,但是用二维数组做参数,它的形参该怎样写? 要注意的是:函数中的形参其实就相当于一个声明,并不产生内存分配,形参的目的就是要让编译器知道函数参数的数据类型. 正 ...

  6. C语言学习笔记 (006) - 二维数组传参的三种表现形式

    # include <stdio.h> # include <stdlib.h> # define M # define N int getdate(int (*sp)[M]) ...

  7. Java中引用类型变量,对象,值类型,值传递,引用传递 区别与定义

    一.Java中什么叫做引用类型变量?引用:就是按内存地址查询       比如:String s = new String();这个其实是在栈内存里分配一块内存空间为s,在堆内存里new了一个Stri ...

  8. java的值传递和引用传递

    昨天博主在对于值传递和引用传递这里栽了一个大坑啊,导致一下午时间都浪费在这里,我们先说下值传递和引用传递java官方解释: 值传递:(形式参数类型是基本数据类型):方法调用时,实际参数把它的值传递给对 ...

  9. Java学习小结(1)-数组的创建与传参

    (一)数组的创建 数组的创建包括两部分:数组的申明与分配内存空间. int score[]=null; //申明一维数组 score=new int[3]; //分配长度为3的空间 数组的申明还有另外 ...

随机推荐

  1. 百万it资源百度网盘链接分享

    自己大量时间整理的优质资源,容量达3000多G,有需要的朋友可以微我,资源截图:  面试资料: 书籍类: 视频类: 以上只是部分资源,想要资源的亲请加微信咨询. 欢迎加微信咨询,请备注资源: 独乐乐不 ...

  2. WebGL简易教程(五):图形变换(模型、视图、投影变换)

    [toc] 1. 概述 通过之前的教程,对WebGL中可编程渲染管线的流程有了一定的认识.但是只有前面的知识还不足以绘制真正的三维场景,可以发现之前我们绘制的点.三角形的坐标都是[-1,1]之间,Z值 ...

  3. Win10 安装配置 MongoDB 4.0 踩坑记

    redis 官方没有 Windows 版的,微软维护的已经好久没更新了,所以就在想着换成 MongoDB. 于是一趟被我复杂化的踩坑之旅就开始了,同时也记录一下,避免有人遇见跟我一样的问题. 首先在  ...

  4. kotlin -- 可见性修饰符

    puiblic Kotlin的可见修饰符与Java类似,但是默认可见性不同,Java默认包私有,kotlin默认public ### internal internal 只在模块内部可见.一个模块就是 ...

  5. Ubuntu18.04安装好MySQL5.7后,root账号登录密码问题

    不知道从哪个版本开始,在Ubuntu上用apt安装MySQL后,不会提示让你设置密码了. 安装MySQL5.7 sudo apt install mysql-server -y 然后找到MySQL的配 ...

  6. Java8 Period.between方法坑及注意事项

    在使用Java8 新特性中关于Period.between的方法时需注意该方法获取日期的区间问题. @Test public void test1(){ LocalDate from = LocalD ...

  7. JS中的排序算法-冒泡排序解析

    冒泡排序算法 例子:10,8,9,6,4,20,5  从小到大排序 第一轮  1)10>8  交换数据 得到:8,10,9,6,4,20,5 2)10>9  交换数据 得到:8,9,10, ...

  8. Springboot 系列(十四)迅速启用 HTTPS 加密你的网站

    1. 获取 HTTPS 证书 正常情况下 HTTPS 证书需要从证书授权中心获得,这样获得的证书才具有公信力,也会被各种浏览器客户端所认可.常见的证书品牌如 Symantec,GeoTrustm,Tr ...

  9. MySQL时间盲注五种延时方法 (PWNHUB 非预期解)

    转自cdxy师傅:https://www.cdxy.me/?p=789 PWNHUB 一道盲注题过滤了常规的sleep和benchmark函数,引发对时间盲注中延时方法的思考. 延时函数 SLEEP ...

  10. Python 3 既是激进的又是克制的,这些提议被否决了

    [译]PEP 3099--Python 3 中不会改变的事情 导语: Python 3.8 已经发布了,引进了不少变更点.关于 3.9 预计引入的修改,也披露了一些.我们之前还关注过 GIL 的移除计 ...