//描述:利用可变参数列表统计一组数的平均值
#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\n",&a,&b);
//宏来实现
float aver = average(4, 10,20,30,40);
printf("aver:%.2f\n",aver);
//调用指针可变参数来实现
aver = average(4, 10,20,30,40);
printf("aver2:%.2f\n",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\n",&num);
printf("x地址:%p\n",&x);
printf("y地址:%p\n",&y);
printf("z地址:%p\n",&z); }

  

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

进一步发现,Pascal语言不支持可变长参数,而C语言支持这种特色,正是这个原因使得C语言函数参数入栈顺序为从右至左。
具体原因为:C方式参数入栈顺序(从右至左)的好处就是可以动态变化参数个数。
通过栈堆分析可知,自左向右的入栈方式,最前面的参数被压在栈底。
除非知道参数个数,否则是无法通过栈指针的相对位移求得最左边的参数。
这样就变成了左边参数的个数不确定,正好和动态参数个数的方向相反。
 
因此,C语言函数参数采用自右向左的入栈顺序,主要原因是为了支持可变长参数形式,
C语言中可变参数都是从左到右,所以不管你有多少个参数反正将最右面的那个压入栈底,最左面的参数出入栈顶。换句话说,如果不支持这个特色,
C语言完全和Pascal一样,采用自左向右的参数入栈方式
 
 

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

  1. PHP函数可变参数列表的具体实现方法介绍

    PHP函数可变参数列表可以通过_get_args().func_num_args().func_get_arg()这三个函数来实现.我们下面就对此做了详细的介绍. AD:2014WOT全球软件技术峰会 ...

  2. 可变参数列表与printf()函数的实现

    问题 当我们刚开始学习C语言的时候,就接触到printf()函数,可是当时"道行"不深或许不够细心留意,又或者我们理所当然地认为库函数规定这样就是这样,没有发现这个函数与普通的函数 ...

  3. C++可变参数列表处理宏va_list、va_start、va_end的使用

      VA_LIST是在C语言中解决变参问题的一组宏他有这么几个成员: 1)va_list型变量: #ifdef     _M_ALPHA typedef    struct{ char* a0; /* ...

  4. 【转】C++可变参数列表处理宏va_list、va_start、va_end的使用

    VA_LIST是在C语言中解决变参问题的一组宏他有这么几个成员: 1)va_list型变量: #ifdef     _M_ALPHA typedef    struct{ char* a0; /*po ...

  5. C++实现可变参数列表

    // 接收数量不定的实参.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> #includ ...

  6. 可变参数列表---以dbg()为例

    在UART驱动的drivers/serial/samsung.h中遇到如下定义: #ifdef CONFIG_SERIAL_SAMSUNG_DEBUG extern void printascii(c ...

  7. Chapter5_初始化与清理_数组初始化与可变参数列表

    一.数组初始化 数组是相同类型的,用一个标识符名称封装到一起的一个对象序列或基本类型数据序列.编译器是不允许指定数组的长度的,当使用语句int[] a时,拥有的只是一个符号名,即一个数组的引用,并不拥 ...

  8. jdk5可变参数列表

    今天碰到了 public static String getAutoRelateRelationship(final JSONObject modifyJson, String... inUsedCo ...

  9. Java 可变参数列表

    1.可变参数列表的简单实现 当调用方法时,方法的参数个数或类型未知时,称其为可变参数列表.在以前的Java代码中,可以使用Object数组来实现这样的功能.因为,所有的类都是直接或间接继承于Objec ...

随机推荐

  1. 关于PATCH与PUT的区别

    两者的区别:PATCH:更新部分资源,非幂等,非安全PUT:更新整个资源,具有幂等性,非安全注:幂等性:多次请求的结果和请求一次的结果一样安全性:请求不改变资源状态 举个两者明显区别的例子(我对两者定 ...

  2. 气象netCDF数据可视化分析

    气象netCDF数据可视化分析 2019-09-19 15:34:22 自走棋 阅读数 162更多 分类专栏: web前端   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载 ...

  3. 测试PHP-FPM的工作流中的疑惑点

    顺序比较乱,想到什么测试什么,测试环境 PHP7.2 和 MariaDB10.3.11 PHP-FPM是 master/worker 多进程模型master负责和web-server通讯,把接受到请求 ...

  4. 如何更精准地设置 C# / .NET Core 项目的输出路径?(包括添加和删除各种前后缀)

    原文:如何更精准地设置 C# / .NET Core 项目的输出路径?(包括添加和删除各种前后缀) 我们都知道可以通过在 Visual Studio 中设置输出路径(OutputPath)来更改项目输 ...

  5. Java冒泡排序与快速排序笔记

    public class Sort { public static void sort() { Scanner input = new Scanner(System.in); int sort[] = ...

  6. java之struts2的ThreadLocal和ActionContext

    在之前的学习中,我们知道struts2可以将表单中的数据自动设置到处理类的属性上,还有类型转换等其他功能.那么struts2是怎样做这件事情的呢? struts2完成这些功能是通过拦截器来完成的,并且 ...

  7. Celery定时任务细讲

    Celery定时任务细讲 一.目录结构 任务所在目录 ├── celery_task # celery包 如果celery_task只是建了普通文件夹__init__可以没有,如果是包一定要有 │ ├ ...

  8. 关于素数表-C++

    废话不多说,先贴代码: #include <iostream> using namespace std; bool is_prime(int n) { || n == ) return f ...

  9. lnmp环境快速搭建及原理解析

    刚开始学习php的时候是在wamp环境下开发的,后来才接触到 lnmp 环境当时安装lnmp是按照一大长篇文档一步步的编译安装,当时是真不知道是在做什么啊!脑袋一片空白~~,只知道按照那么长的一篇文档 ...

  10. 【转载】 C#中List集合使用First()方法获取第一个元素

    在C#的List集合操作过程中,如果要获取List集合中的第一个元素对象,则一般会先通过获取到list[0]这种方式来获取第一个元素.其实在List集合中提供了获取最后一个元素的First()方法,调 ...