`
99381837
  • 浏览: 4916 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
文章分类
社区版块
存档分类
最新评论

c++之指针作为函数参数传递的问题

阅读更多
原创文章,转载请注明出处,谢谢!
作者:清林,博客名:飞空静渡

博客地址:http://blog.csdn.net/fjb2080

其实,对于C 或者C++ ,最难的一块地方估计就是指针了。指针是强大的,但也是很多人载在这里的地方。

前段时间写了一篇文章《C ++之 数组与指针的异同 》对C 和C ++中的指针做了一个初步的讲解。这次将讲解一下指针作为函数参数传递的问题。

很多人对于指针的使用是有所了解的,但还是经常会载在指针的问题上,是因为还不够了解指针的本质,其实如果了解指针的本质,对指针的使用也就一目了然了。

作为C 的初学者,经常会遇到指针作为函数参数传递的两个经典的问题。这里,我将透过指针的本质来来讲解这两个问题,这样以后无论你遇到什么样的指针问题,如果你以这样的方法来分析指针也许就迎刃而解了!

首先,第一个问题是这样的:
写一个函数,交换两个参数中的值。

初学者往往会这样写:

void exchange(int x, int y)
{
int p=x;
x = y;
y = p;
}

之后,你会查找资料了解到应该这样写:
void exchange(int *x, int *y)
{
int *p=x;
*x = *y;
*y = *p;
}

第二个问题是,写一个给某个指针分配内存的函数:
初学者往往是这样写:
void my_malloc(void* p, int size)
{
p = malloc(sizeof(int)*size);
}

然后又查在资料,知道应该这么写:
void my_malloc(void** p, int size)
{
*p = malloc(sizeof(int)*size);
}

虽然,网上很多这样的讨论,也有很多人做过很多的解释,但始终都无法给出一个令人一目了然,并可以长久记住的说法,这篇文章就是想试图解决这样的问题,给初学者一个原理性的了解!

首先,一定一定记住一点, 指针和变量一样,也是有地址的,只不过变量的值被解释成一个值,而指针的值被解释成一个地址。

下面,我们看一下代码:
void main()
{
int x;
int *p;
}

我们看这个函数的内存结构:


这是一个函数的栈结构,我们可以看到,变量和指针都占用了4 个字节。而且,由于我们对它们没有初始化,所以变量x 和指针p 里的内容都是随机的,就是说x 的值是不确定的,p 有可能指向某个内存地址,如果现在对p 操作也许会导致程序崩溃。

<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

其实,我们记住了,指针也是有地址的 这个概念,很多问题就迎刃而解了。

下面,我来分析一下,指针作为函数参数传递的情况。
<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->
如果,我们的代码是这样的,你看会怎么样:
int main(int argc, char* argv[])
{
int *a = new int(10);
func(a);
return 0;
}

第一个要说的当然是:指针也是有地址的。
第二个要说的是:当给一个函数的参数传递一个变量是,这个变量是复制过去的。

对于第二点,我们在理解void exchange(int x, int y) 函数想交换这两个变量的的值时就应该理解了。
例如:
int a;
int b;
exchange(a,b);
不能交换a 和b 的值,因为此时exchange(a,b) 中的a 和b 并不是原来的a 和b 变量,它们只不过是被复制过去了。

有了这两个概念,就不难理解指针作为函数参数传递的问题。

首先,我们来看下上面的代码中的a 指针和p 指针的内存结构。

我们看到,当我们以a 作为func 函数的参数传递进去的时候,函数复制了这个指针,但这两个指针的内容是一样的,也就是说是指向同一个内存,即10 。


如果你还不了解的话,我就通过一段代码和测试再来说明:

view plaincopy to clipboardprint?
#include <stdio.h> 
void func(int* p) 

    printf("*p = %d\n", *p); 
    printf("&p = %p\n", &p); 

int main(int argc, char *argv[]) 

    int *a = new int(10); 
    printf("*a = %d\n", *a); 
    printf("&a = %p\n", &a); 
    func(a); 
    return 0; 




编译:g++ -g -Wall test1.cpp
运行:./a.out
输出:
*a = 10
&a = 0xbfd4447c
*p = 10
&p = 0xbfd44460

我们看到输出,a 指向的地址的值和p 指向的地址里的值是一样的,都是10 。然而,对于指针a 和p 来说,它们自身的地址是不一样的,所以我们看到,函数func 复制了指针a 给p ,它们的值一样,但有不同的地址,是不同的指针。

我们再进一步:
view plaincopy to clipboardprint?
#include <stdio.h> 
void func(int* p) 

    printf("*p = %d\n", *p); 
    printf("&p = %p\n", &p); 
    printf("&*p = %p\n", &*p); 

int main(int argc, char *argv[]) 

    int *a = new int(10); 
    printf("*a = %d\n", *a); 
    printf("&a = %p\n", &a); 
    printf("&*a = %p\n", &*a); 
    func(a); 
    return 0; 




编译输出:
*a = 10
&a = 0xbfe1c77c
&*a = 0x94b6008
*p = 10
&p = 0xbfe1c760
&*p = 0x94b6008

我们可以进一步看到,a 指针所指向的值的地址和p 指针所指向的值的地址是一样的,都是 0x94b6008 ,就如同上图所示,为了加深印象,再看一下这个图 ,然后再对比一下程序输出 ,然后在体会一下我在上面提到的两点 ,一点是:指针是有地址的 。另一点是:函数的参数是复制过去的 。




说到这里,我们再回到文章开始时提到的两个问题,一个是交换问题:

void exchange(int *x, int *y)
{
int *p=x;
*x = *y;
*y = *p;
}

那么这样为什么可以交换:
int a = 2;
int b = 3;
exchange(&a, &b);

上我们以a 和b 的地址传递给exchange 函数时,函数复制了这两个地址,并赋值给x 和y 这个两个指针,这两个指针是指向变量a 和b 的,它们的图形如下:


那么,当我们反引用指针时:
int *p=x;
*x = *y;
*y = *p;

我们操作的是a 和b 里面的变量的值,所以,我们交换a 和b 的值就成功了。

我们再来看下第二个问题:
void my_malloc(void* p, int size)
{
p = malloc(sizeof(int)*size);
}
当这样时:
int *a;
my_malloc(a, 10);
为什么这个会失败!

下面,我来分析一下:
当我们调用my_malloc(a, 10); 函数,而函数还没执行到p = malloc(size); 语句时,情况是这样的:


我们看到a 和p 的指针的值都是一样的,都是指向某个不确定的地址。
这时,我们执行这个语句:
p = malloc(sizeof(int)*size);
我们把这个语句分开两部分来看,一个是先执行malloc(sizeof(int)*size) ,然后在执行赋值语句,把malloc(sizeof(int)*size) 的返回值付给p 。
第一步:先执行malloc(sizeof(int)*size) ;(这里我们只考虑malloc 分配内存成功的情况)

第二步:把执行malloc(sizeof(int)*size) 的返回值付给了p ,如下图:


由上图,我们可以知道,这就是为什么,我们还是不能给a 分配地址的了。

下面我们来分析这个:
void my_malloc(void** p, int size)
{
*p = malloc(sizeof(int)*size);
}

int *a;
my_malloc(&a , 10);
这样执行,为什么会成功!


我们看到,当执行函数
my_malloc(void** p, int size);
但还没有执行
*p = malloc(sizeof(int)*size);
语句时,它们的内存结构图如下所示:


其实这里,我们可以把二维指针和一维指针当成和变量一样,也是有地址的。只不过它的解释不一样而已。
变量:里面的值是一个数值。
一维指针:里面的值是个地址,而这个地址里的值是个数值。
二维指针:里面的值是个地址,而这个地址里的值也是个地址。

那么,我看着图来解释p :
p 里面是一个地址,这个地址是&a ,即是a 指针的地址值,而a 指针地址里面的值也是个地址,这个地址是指向一个不确定的地方,说得坳口,慢慢对比图来理解就会好了!

执行malloc(size) 后的图如下:


然后在执行赋值语句:
*p = malloc(sizeof(int)*size);
后,如下图所示:


然后,我们就给指针a 分配内存成功了。
分享到:
评论

相关推荐

    c++之指针作为函数参数传递的问题.pdf

    本文档“C++之指针作为函数参数传递的问题.pdf”深入探讨了指针在函数参数传递过程中的一些常见误区和正确实践。作者清林(博客名:飞空静渡)在其博客(http://blog.csdn.net/fjb2080)中分享了这些宝贵的知识点。 #...

    C/C++中多维数组指针作为函数参数传递程序

    C/C++中多维数组指针作为函数参数传递程序 在 C++ 中,多维数组指针作为函数参数传递是非常常见的编程技术。本文将详细介绍如何在 C/C++ 中将多维数组指针作为函数参数传递,並对相关知识点进行详细解释。 多维...

    指针函数作为参数传递(经典小实例)

    在这个例子中,`add`, `subtract`, 和 `multiply` 都被作为指针函数传递给了 `apply_operation`,根据传入的指针函数不同,执行了不同的操作。 指针函数在实际编程中有很多应用场景,比如排序算法中的比较函数,...

    单链表操作中指针作为函数参数的典型错误.cpp

    单链表操作中指针作为函数参数的典型错误.cpp

    c# 调用C++编写 的DLL函数各种参数传递问题。

    这篇文章将详细介绍 C# 调用 C++ 编写的 DLL 函数各种参数传递问题,包括不返回值的参数、带返回值的参数、传递结构体指针和传递结构体数组等。 1. 不返回值的参数 在 C++ 中,函数原型为 bool SendNewSms(char *...

    C++ 与C#之间的指针参数传递传参参考

    C++ 与C#之间的指针参数传递,实现无限量数据的传递,轻松无压力,方便在C++里面获取或者从C#传递数据到C++的动态库调用内。

    C++指针参数传递内存详解

    C++中的指针参数传递是一种常见的编程技术,但是许多开发者对其机理不甚了解,本文将深入剖析C++指针参数传递的内存机理,解决开发者们长期以来对函数指针参数传递的误解。 函数指针参数传递的机理 ---------------...

    C/C++ 函数指针的意义,函数指针的用法

    函数指针作为参数 函数指针不仅可以作为局部变量,还可以作为函数的参数,实现对回调函数的传递。这在设计模块化、可扩展的系统时尤为有用。例如: ```cpp int test2(int(*ra)(int), int b); ``` 这里,`ra`是一...

    C#调用C++动态库,执行回调函数并传递结构体参数

    C++动态库中,回调函数是一种特殊的函数,它的指针可以作为参数传递给其他函数,在适当的时候被调用。在C#中,我们将使用委托来表示这个回调函数。C++的回调函数需要考虑函数指针的调用约定,通常使用`__stdcall`...

    关于C++的函数参数传递方式

    ### 关于C++的函数参数传递方式 在C++编程中,函数参数的传递是非常重要的一个概念。通过函数参数的传递,我们可以实现不同函数间的数据交互。本文将深入解析C++中的函数参数传递机制,包括传值调用、传地址调用...

    C++指针探讨,关于C与C++函数指针指针函数

    例如,你可以将函数指针作为参数传递给其他函数,以便在运行时动态地决定执行哪个函数。这种方式在设计模式如策略模式中尤为常见。 函数指针和指针函数的区别在于它们的角色不同:函数指针本身就是一个可调用的对象...

    C C++语言函数参数传递及函数调用约定的探讨

    - 函数名可以传递给其他函数作为参数,通过函数指针变量可以在被调用函数中调用不同的实参函数。 - **示例代码**: ```c++ void process(int data, void (*func)(int)) { func(data); } void print(int data)...

    C++中回调函数(CallBack)的用法分析

    其错误是普通的C++成员函数都隐含了一个传递函数作为参数,亦即“this”指针,C++通过传递this指针给其成员函数从而实现程序函数可以访问C++的数据成员。这也可以理解为什么C++类的多个实例可以共享成员函数却-有...

    c++中指向函数的指针

    除了直接使用函数指针调用函数,我们还可以将函数指针作为参数传递给其他函数,或者让函数返回一个函数指针。在上面的示例中,`RtnFunc`函数返回了一个指向`hello`函数的指针,而`call`函数接受一个返回字符指针的...

    c/C++可变参数函数的参数传递机制剖析

    ### C/C++可变参数函数的参数传递机制剖析 #### 摘要 本文深入探讨了C/C++语言中可变参数函数的参数传递机制,并提出了一种更加精确且灵活的设计方法来处理这类函数。通过分析,我们不仅理解了如何在函数内部访问...

    C++函数的指针

    在实际应用中,函数指针常常用于动态执行操作,例如在不预先知道具体实现的情况下执行特定任务,或者作为参数传递给其他函数。例如,你可能会有一个函数`executeOperation(int (*operation)(int, int), int a, int b...

    C++中函数指针的含义

    总之,C++中的函数指针是一种强大的工具,它可以用于函数的动态调用、作为参数传递以及构建函数指针数组等,极大地扩展了C++的编程能力。正确理解和使用函数指针是成为一名熟练的C++程序员的关键。在实际编程中,...

    函数指针万能打印_C++_VS_

    在C++编程中,函数指针是一个非常强大的工具,它允许我们将函数作为其他函数的参数或者存储在变量中。在本示例中,“函数指针万能打印”着重讲解如何利用函数指针实现一个通用的打印系统,可以适应各种数据类型的...

    C++指针作为函数的参数进行传递时需要注意的一些问题

    然后调用函数使这两个变量的值交换,并且要求被调函数的传值通过传递指针来实现。程序1.1 代码如下:#include&lt;iostream&gt;#include&lt;string&gt;using namespace std;int main(){ string str1=”I love China!”,str2=”I ...

Global site tag (gtag.js) - Google Analytics