首先,摘抄一段《CPrimer》的内容:
1、形式参数是被调函数中的变量,实际参数是主调函数赋给被调函数的具体值。实际参数可以是常量、变量,或甚至是更复杂的表达式。无论实际参数是何种形式都要求被求值,然后该值被拷贝给被调函数相应的形式参数。再次强调:实际参数是具体的值(哪怕是以变量、表达式等形式存在,在传递给被调函数时,也要先转换成具体的值),该值要被赋给作为形式参数的变量。
2、因为被调函数使用的值是从主调函数中拷贝而来,所以无论被调函数对拷贝数据进行什么操作,都不会影响主调函数中的原始数据。
总结一下:
1、实际参数在传递给被调函数的时候是具体值,我们不必关心它原来的形式(哪怕是变量、表达式等等)。形式参数是变量,在被调用执行的过程中,形参变量是要被创建并占用栈上的空间的,而这个形参变量的值,从实参拷贝而来。
2、由于形参变量被创建并占用栈上空间,所以在被调用函数运行时,形参所发生的任何变化,都不会影响实参,因为它们是彼此独立的两个变量(这里暂且把实参当成变量)。下面看例程:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define NAME "高德科技" #define ADDRESS "阳光街1号" #define PLACE "207室" #define WIDTH 40 #define SPACE ' ' void show_n_char(char ch,int num); int main() { int spaces; show_n_char('*',WIDTH); //打印40个* putchar(' '); //putchar(" ") 不行 show_n_char(SPACE,12); //打印12个空格 printf("%s ",NAME); //打印单位名称 spaces=(WIDTH-strlen(ADDRESS)); //计算40-ADDRESS后,剩余长度。spaces作为show_n_char函数的实参,算出确切的值 show_n_char(SPACE,spaces); //打印spaces个长度的空格,以便让ADDRESS靠右 printf("%s ",ADDRESS); //打印地址 show_n_char(SPACE,(WIDTH-strlen(PLACE))/2); //打印1/2个WIDTH-PLACE长度的空格 printf("%s ",PLACE); //以便让PLACE居中 show_n_char('*',WIDTH); //打印40个* putchar(' '); //换行 return 0; } void show_n_char(char ch,int num) { for(int count=1;count<=num;count++) putchar(ch); }
下面这个例程能更好地说明上面的2条总结:
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> void allocateString(char* pp) //声明了字符指针形参——pp,当这个函数被调用时,编译器在栈上会真实地创建这个变量pp { printf("pp的地址是: %p, pp=%s ", &pp, pp); char* temp = malloc(100); //创建临时字符指针 if (temp == NULL) return; memset(temp, 0, 100); strcpy(temp, "Hello,world!"); //上面3条语句是初始化及赋值 printf("temp的地址是: %p, temp=%s ", &temp, temp); pp = temp; //将临时变量temp的地址赋给pp。注意:仅仅改变了pp的值!并没有对调用函数提供的实参p作任何改动 printf("pp的地址是: %p, pp=%s ", &pp, pp); } void test02(void) { char* p = NULL; //创建字符指针pp,并初始化。 printf("p的地址是: %p, p=%s ", &p, p); allocateString(p); //调用allocateString函数,并将‘NULL’这个值拷贝给它的形参——pp printf("实参p=%s ", p); printf("p的地址是:%p ", &p); } int main() { test02(); //调用函数,得到输出:“传递同级指针得:(null)” system("pause"); return EXIT_SUCCESS; }
从上面程序能看出:p,pp,temp三个变量在内存中的位置相近,显然,编译器在栈上都给分配了内存。
画个图,仔细分析程序对内存的操作: