WHCSRL 技术网

C/C++ 读懂函数的形参和实参,一篇文章足够了

案例1:形参为非指针变量

int _tmain(int argc, _TCHAR* argv[])
{
	unsigned char a_param = 1;
	printf("a_param 的地址为 = %%p,a_param 的值 = %%d
", &a_param, a_param);
	FunParam(a_param);
	printf("执行后 
");
	printf("a_param 的地址为 = %%p,a_param 的值 = %%d
", &a_param, a_param);
	return 0;
}

/// unsigned char c_param = a_param;
void FunParam(unsigned char c_param)
{
	printf("c_param 的地址为 = %%p, c_param 的值为 = %%d
", &c_param, c_param);
	c_param = 2;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

执行
在这里插入图片描述

这里看到,形参c_param 和实参 a_param 在不同的地址上,但值相等。函数调用时,形参和实参的关系,可以这么表示
unsigned char c_param = a_param;
定义了一个c_param,将a_param 赋值给它。在这种情况下,形参和实参没有任何关系,因为它们在不同的地址上,改变形参不会影响实参。

案例2:形参为指针变量

int _tmain(int argc, _TCHAR* argv[])
{
	unsigned char debug_data = 2;
	unsigned char *a_param = &debug_data;
	printf("a_param 的地址为 = %%p,a_param 的值 = %%d
", a_param, *a_param);
	FunParam(a_param);
	printf("执行后,a_param 的地址为 = %%p, a_param 的值为 = %%d
", a_param, *a_param);
	return 0;
}

/// unsigned char *c_param = a_param;
void FunParam(unsigned char *c_param)
{
	printf("c_param 的地址为 = %%p, c_param 的值为 = %%d
", c_param, *c_param);
	*c_param = 3;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

执行
在这里插入图片描述
这里我们定义了一个FunParam 函数,形参时一个指针。同样的,我们用上面那个公式
unsigned char *c_param = a_param
函数调用时,定义了一个形参c_param,这个指针指向了a_param 这个指针所指向的内存地址(0x010FFE93),此时两个指针同时指向了同一块内存地址,因此当一个指针操作了这块内存地址,改变了值,另一个指针去访问这块内存时,值自然就变了。因此这种情况下,形参可以改变实参

案例3: 形参为指针的指针

int _tmain(int argc, _TCHAR* argv[])
{
	unsigned char debug_data = 2;
	unsigned char *a_param = &debug_data;
	printf("a_param 的地址为 = %%p, a_param指向的地址为 = %%p, a_param的值 = %%d
", &a_param, a_param, *a_param);
	FunParam(&a_param);
	printf(" 执行后 
");
	printf("a_param 的地址为 = %%p, a_param指向的地址为 = %%p, a_param的值 = %%d
", &a_param, a_param, *a_param);
	return 0;
}

/// unsigned char **c_param = &a_param;
void FunParam(unsigned char **c_param)
{
	printf("c_param 的地址为 = %%p, c_param 指向的地址为 = %%p,c_param 的值为 = %%d
", c_param, *c_param, **c_param);
	*c_param = (unsigned char*)malloc(1);
	if (c_param != NULL)
	{
		*(*c_param) = 3;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

执行
在这里插入图片描述
我们可以看到,执行后,实参指针指向的内存地址变了。同样套用公式
unsigned char **c_param = &a_param
调用函数时,定义了一个二级指针,指向了实参指针的地址,函数内,通过动态内存分配,二级指针操作实参指针的地址,将实参指针重新指向一块内存,并重新赋值。案例2只能改变指针指向的内存地址上的值,无法改变指针的指向;但是这里,我们不仅可以改变指针指向的内存的值,也可以改变指针的指向。我们往往通过这种方式,来初始化一个空指针。初始后,若要释放内存,则可使用方案2的处理,重新定义一个指针指向那块动态内存,然后释放

案例4:引用

int _tmain(int argc, _TCHAR* argv[])
{
	unsigned char a_param = 1;
	printf("a_param 的地址为 = %%p,a_param 的值 = %%d
", &a_param, a_param);
	FunParam(a_param);
	printf("执行后 
");
	printf("a_param 的地址为 = %%p,a_param 的值 = %%d
", &a_param, a_param);
	return 0;
}

/// unsigned char &c_param = a_param;
void FunParam(unsigned char &c_param)
{
	printf("c_param 的地址为 = %%p, c_param 的值为 = %%d
", &c_param, c_param);
	c_param = 2;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

执行后
在这里插入图片描述
依旧套用公式
unsigned char &c_param = a_param
引用的本质就是取一个别名,本体还是一样的。这里我们看到行参和实参的地址相同,因此改变形参等同于改变实参

推荐阅读