方法在内存的形式
计算机在分配空间时有系统空间、用户空间、堆栈。用户空间类存放用户程序(代码块),在调用方法时才计算该方法使用多少空间(根据其变量的类型)。我称之为段空间(以{}称呼,也可称呼临时空间),在方法结束时系统收回。
这也是初学者在学习时常常无法理解的部分,就以简单的数据交换来说。在调用已下方法后显示数据并没有交换。
void swap_1(int a,int b)
{
int temp;
temp = a;
a = b;
b = temp;
}
这个方法是交换(传递实参),但是本方法在调用后生成了段空间,段空间在内存中有了三个int类型的长度(a、b、temp),交换了在段空间内a和b的值,在方法结束后空间收回,并没有改变实际我们需要改变的值。所以我们在进行数据交换的时候需要传入实际的地址(传递形参),方法如下。
void swap_2(int *a,int * b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
方法的操作实质和方法参数传递规则
前面提到调用方法到方法结束的过程,下面来描述方法在内存中的操作实质和方法参数传递规则。
操作实质就是出入栈;
方法参数传递规则是从右向左传递;
我们通过操作可变参数来进行阐述:
什么是可变参数
可变参数是指在函数定义时不确定参数数量的一种参数类型。在C中由...表示方法的可变参数,如常见的printf()和scanf()方法就是可变参数方法,但是可变参数的类型要相同。
方法的实质和参数传递规则
首先通过使用函数调用和可变参数方法来进行统一阐述。
char* unionString(const char* str1, const char* str2)
{
static char str[10];
sprintf(str, "%s%s", str1, str2);
return str;
}
int main() {
printf("%s\n%s\n", unionString("123", "456"), unionString("abc", "def"));
}
输出结果:
123456
123456
代码解释:
- unionString方法传入两个地址,返回一个地址。
- static是在代码在编译时就初始化,方法调用时不执行初始化(引入静态空间的str的地址)。
- sprintf方法在本函数内是将str1加str2内容替换到str字符数组中,末尾有转义符\0
- 在执行printf方法时参数从右向左,进行入栈,先执行第三参数;
- 第三个参数是函数调用,将字符数组为“abcdef\0",返回字符数组首地址,将返回值存入内存空间。
- 第三个参数是函数调用,由于操作的地址相同,字符数组的内容替换为为“123456\0",返回字符数组首地址,将返回值存入内存空间,第二个参数返回值和第三参数返回值相同都为str的地址。
- 传入第一个参数,这个参数也是个地址,这个地址指向"%s\n%s\n"。
- printf方法开始执行,进行出栈。
- 根据读取的字符串,进行解析,遇到%s(%s表示进行输出字符直到\0或者到达长度上限)弹栈,弹出第二个参数的返回值输出字符123456。
- 遇到转移字符\n,换行,继续解析执行。
- 遇到第二个%s,弹栈,弹出第三个参数的返回值输出字符123456
- 遇到转移字符\n,换行,解析执行完成,方法结束。
小结
C语言本身就是面对过程,操作数据空间(指针)和数据。