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

2021/02/16 16:49
阅读数 93

其实,对于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 

 

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

 

 

 

 

编译:g++ -g -Wall test1.cpp

运行:./a.out

输出:

*a = 10

&a = 0xbfd4447c

*p = 10

&p = 0xbfd44460

 

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

 

我们再进一步:

 

 

 

编译输出:

*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 分配内存成功了。

 

本文的pdf下载地址:c++之指针作为函数参数传递的问题.pdf

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

展开阅读全文
c++
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部