广告位联系
返回顶部
分享到

C语言中传值与传指针的介绍与区别

C语言 来源:互联网搜集 作者:守望 发布时间:2019-06-23 11:56:38 人浏览
摘要

本篇文章介绍C语言中传值与传指针的介绍与区别 前言 我们可能听过C语言中的传值和传指针,在其他语言中,也有传引用一说,那么他们到底有什么区别呢?如果你还不能准确地分辨,就该好好了解一下了。 传值 我们在初学C语言的时候就被老师教过,下面的方式是无

本篇文章介绍C语言中传值与传指针的介绍与区别

前言

我们可能听过C语言中的传值和传指针,在其他语言中,也有传引用一说,那么他们到底有什么区别呢?如果你还不能准确地分辨,就该好好了解一下了。

传值

我们在初学C语言的时候就被老师教过,下面的方式是无法交换a和b的值的:

 
#include<stdio.h>
void swap(int a,int b)
{
  int temp = a;
  a = b;
  b = temp;
  printf("swap a = %d,b = %d\n",a,b);
}
int main(void)
{
  int a = 10;
  int b = 20;
  printf("before swap:a = %d,b = %d\n",a,b);
  swap(a,b);
  printf("after swap:a = %d,b = %d\n",a,b);
  return 0;
}

运行结果如下:

before swap:a = 10,b = 20                                                                                                                                                                  
internal swap a = 20,b = 10                                                                                                                                                                
after  swap:a = 10,b = 20


可以看到,a和b的值最终并没有被交换。开始时a,b的值为10,20,而最终还是同样的值。

为什么呢?因为函数参数在传递的时候,都是传原数据的副本,也就是说,swap内部使用的a和b只是最初始a和b的一个副本而已,所以无论在swap函数内部对a和b做任何改变,都不会影响初始的a和b的值。

正因如此,我们常常被告知,不要把直接把结构体直接作为参数,这样效率会很低。由于结构体本身占用字节数较大,如果直接作为参数,那么将会产生一个较大的”副本“,如此一来,效率也就很低了。

我们再结合下面的图来理解:
 


 

首先图中方框中的上部分a和b代表了main函数中的a和b,即原始数据,而方框中的下部分a和b代表了函数的参数a和b,即原始数据的“副本”。(后面的图都是如此,上部分代表原始值,下部分代表函数参数值)。

调用swap函数前后的情形如下:
 


 

由于在swap中永远只是对a和b的副本进行操作,因此完全不影响原始的a和b的值。最终也不可能达到交换a和b的值的目的。

传指针

那么为解决上面的问题,我们知道,需要传指针。其代码如下:
 

 
#include<stdio.h>
void swap(int *a,int *b)
{
  int temp = *a;
  *a = *b;
  *b = temp;
  printf("swap a = %d,b = %d\n",*a,*b);
}
int main(void)
{
  int a = 10;
  int b = 20;
  printf("before swap:a = %d,b = %d\n",a,b);
  swap(&a,&b);
  printf("after swap:a = %d,b = %d\n",a,b);
  return 0;
}

运行结果:

before swap:a = 10,b = 20                                                                                                                                                                  
swap a = 20,b = 10                                                                                                                                                                         
after  swap:a = 20,b = 10


可以看到在这种情况下,a,b的值才是真正交换了。

为什么又有传值,又有传指针

看到这里,不知道你是否会疑惑,为什么给函数传递参数的时候,一会是传值,一会是传指针呢?为什么传指针就能改变参数的值呢?实际上,C语言里,参数传递都是值传递!也就是说,你认为的传指针也是传值,只不过它的值是指针类型罢了。

我们再通过图来理解前面为什么传指针就可以交换a,b的值:
 


 

从图中可以看出,虽然传递给函数的是指向a和b的指针的副本,但是它的副本同样也是指向a和b,因此虽然不能改变指针的指向,但是能改变参数a和b指向的内容,即改变原始a和b的值。

再看传指针

如果是为指针p申请一段内存,下面的代码能达到目的吗?
 

 
#include<stdio.h>
#include<stdlib.h>
void getMemery(int *p)
{
  /*申请1024个int大小*/
  p = malloc(sizeof(int)*1024);
  if(NULL == p)
  {
    printf("malloc failed\n");
    p = NULL;
  }
}
int main(void)
{
  int *p = NULL;
  getMemery(p);
  printf("address of p is %p\n",p);
  return 0;
}

通过前面的内容分析,肯定是达不到预期效果的。

运行结果:
 

address of p is (nil)


这是为什么呢?我们还是利用前面所知来分析,由于传递给getMemory函数的参数都是一个副本,因此函数内的p也是外部p的一个副本,因此即便在函数内部,将p指向了一块新申请的内存,仍然不会改变外面p的值,即p还是指向NULL。
 


 

如何修改呢?我们需要传入p的地址,即指向int类型指针的指针。
 

 
#include<stdio.h>
#include<stdlib.h>
void getMemery(int **p)
{
  /*申请1024个int大小*/
  *p = malloc(sizeof(int)*1024);
  if(NULL == *p)
  {
    printf("malloc failed\n");
    *p = NULL;
  }
}
int main(void)
{
  int *p = NULL;
  getMemery(&p);
  printf("address of p is %p\n",p);
  free(p);
  p = NULL;
  return 0;
}

运行结果如下:

address of p is 0x144f010


从运行结果可以看到,p的值被改变了。

可配合下面的图进行理解:
 


 

总结

本文总结如下:
 

  • 函数的形参都是原数据的“副本”,因此在函数内无法改变原数据
  • 函数中参数都是传值,传指针本质上也是传值
  • 如果想要改变入参内容,则需要传该入参的地址(指针和引用都是类似的作用),通过解引用修改其指向的内容
  • 以上结论不限于C语言


思考
 

  • 如何实现不借助第三个变量,交换两个整数的值?
  • 结合本文,理解C++/Java中所谓的传引用
  •  

版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://www.yanbinghu.com/2019/06/20/53981.html
相关文章
  • C++中类的六大默认成员函数的介绍

    C++中类的六大默认成员函数的介绍
    一、类的默认成员函数 二、构造函数Date(形参列表) 构造函数主要完成初始化对象,相当于C语言阶段写的Init函数。 默认构造函数:无参的构
  • C/C++实现遍历文件夹最全方法总结介绍

    C/C++实现遍历文件夹最全方法总结介绍
    一、filesystem(推荐) 在c++17中,引入了文件系统,使用起来非常方便 在VS中,可以直接在项目属性中调整: 只要是C++17即以上都可 然后头文件
  • C语言实现手写Map(数组+链表+红黑树)的代码

    C语言实现手写Map(数组+链表+红黑树)的代码
    要求 需要准备数组集合(List) 数据结构 需要准备单向链表(Linked) 数据结构 需要准备红黑树(Rbtree)数据结构 需要准备红黑树和链表适配策略
  • MySQL系列教程之使用C语言来连接数据库

    MySQL系列教程之使用C语言来连接数据库
    写在前面 知道了 Java中使用 JDBC编程 来连接数据库了,但是使用 C语言 来连接数据库却总是连接不上去~ 立即安排一波使用 C语言连接 MySQL数
  • 基于C语言实现简单学生成绩管理系统

    基于C语言实现简单学生成绩管理系统
    一、系统主要功能 1、密码登录 2、输入数据 3、查询成绩 4、修改成绩 5、输出所有学生成绩 6、退出系统 二、代码实现 1 2 3 4 5 6 7 8 9 10 11
  • C语言实现共享单车管理系统

    C语言实现共享单车管理系统
    1.功能模块图; 2.各个模块详细的功能描述。 1.登陆:登陆分为用户登陆,管理员登陆以及维修员登录,登陆后不同的用户所执行的操作
  • C++继承与菱形继承的介绍

    C++继承与菱形继承的介绍
    继承的概念和定义 继承机制是面向对象程序设计的一种实现代码复用的重要手段,它允许程序员在保持原有类特性的基础上进行拓展,增加
  • C/C++指针介绍与使用介绍

    C/C++指针介绍与使用介绍
    什么是指针 C/C++语言拥有在程序运行时获得变量的地址和操作地址的能力,这种用来操作地址的特殊类型变量被称作指针。 翻译翻译什么
  • C++进程的创建和进程ID标识介绍
    进程的ID 进程的ID,可称为PID。它是进程的唯一标识,类似于我们的身份证号是唯一标识,因为名字可能会和其他人相同,生日可能会与其他
  • C++分析如何用虚析构与纯虚析构处理内存泄漏

    C++分析如何用虚析构与纯虚析构处理内存泄漏
    一、问题引入 使用多态时,如果有一些子类的成员开辟在堆区,那么在父类执行完毕释放后,没有办法去释放子类的内存,这样会导致内存
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计