• C利用可变参数列表统计一组数的平均值,利用函数形式参数栈原理实现指针运算


    //描述:利用可变参数列表统计一组数的平均值
    #include <stdarg.h>
    #include <stdio.h>
    
    float average(int num, ...);//函数原型;即声明
    float average2(int num, ...);//num个数
    void add(int num, int x, int y, int z);
    int main(void){
    	int a=10;
    	int b=20;
    	printf("a地址:%p b地址:%p
    ",&a,&b);
    	//宏来实现
    	float aver = average(4, 10,20,30,40);
    	printf("aver:%.2f
    ",aver);
    	//调用指针可变参数来实现
    	aver = average(4, 10,20,30,40);
    	printf("aver2:%.2f
    ",aver);
    	
    	//调用add
    	add(4,20,30,40);
    	/*
    	输出:说明依次压入栈中的顺序是 可能根据机器不同入栈先后也不同
    	从下面输出结果看;高地址 n 先入栈;依次是x,y,最后z入栈
    n地址:0x7ffff656d8ac 
    x地址:0x7ffff656d8a8
    y地址:0x7ffff656d8a4
    z地址:0x7ffff656d8a0
    	
    	*/
    	return 0;
    }
    float average(int val, ...)
    {
    	//定义一个va_list类型的变量用于访问可变参数类别
    	va_list varlist;
    	int count;
    	float sum = 0;
    	//初始化可变参数列表
    	va_start(varlist,val);
    	//通过循环获取可变参数列表的参数
    	for(count=0;count<val;count++){
    		sum += va_arg(varlist,int);
    	}
    	va_end(varlist);
    
    	return sum/val;
    }
    /*描述:利用函数变量在栈中存储的原理来实现平均数
    linux 中函数的参数如 int(int a,int b,int c) 依次是从 右边向左依次
    压入栈空间的;所有可以定义一个指针来循环获取每一个可变参数的值
    */
    float average2(int num,...)
    {
    	int* p = #
    	float sum = 0;
    	int i=1;
    	for(; i<num;i++){
    		sum += *(p+i);
    	}
    	return sum/num;
    }
    //扩展:使用函数栈的原理 利用指针来操作形式参数
    void add(int num, int x, int y ,int z)
    {
    	//形式参数的地址
    	printf("n地址:%p
    ",&num);
    	printf("x地址:%p
    ",&x);
    	printf("y地址:%p
    ",&y);
    	printf("z地址:%p
    ",&z);
    	
    }
    

      

    从上面来看;add函数参数入栈顺序 从左到右LInux 和Windows不一样

    进一步发现,Pascal语言不支持可变长参数,而C语言支持这种特色,正是这个原因使得C语言函数参数入栈顺序为从右至左。
    具体原因为:C方式参数入栈顺序(从右至左)的好处就是可以动态变化参数个数。
    通过栈堆分析可知,自左向右的入栈方式,最前面的参数被压在栈底。
    除非知道参数个数,否则是无法通过栈指针的相对位移求得最左边的参数。
    这样就变成了左边参数的个数不确定,正好和动态参数个数的方向相反。
     
    因此,C语言函数参数采用自右向左的入栈顺序,主要原因是为了支持可变长参数形式,
    C语言中可变参数都是从左到右,所以不管你有多少个参数反正将最右面的那个压入栈底,最左面的参数出入栈顶。换句话说,如果不支持这个特色,
    C语言完全和Pascal一样,采用自左向右的参数入栈方式
     
     
  • 相关阅读:
    Linux的学习--系统目录
    PHP内核的学习--创建PHP扩展
    PHP的学习--连接MySQL的三种方式
    MIME Type
    颜色的命名
    JavaScript的学习--生成二维码
    MySQL的学习--触发器
    Google Guava之--cache
    java代码调用oracle存储过程
    oracle序列
  • 原文地址:https://www.cnblogs.com/wanglijun/p/8540642.html
Copyright © 2020-2023  润新知