精华内容
下载资源
问答
  • c语言函数调用及应用举例
    万次阅读 多人点赞
    2019-04-20 16:27:29

    一,函数的定义

    一般来说,执行源程序就是执行主函数main,其他函数只能被主函数所调用,而其他函数之间也可以相互调用。

    1.标准库函数:

    分为:I/O函数,字符串,字符处理函数,数学函数,接口函数,时间转换和操作函数,动态地址分配函数,目录函数,过程控制函数,字符屏幕和图形功能函数。

    这些库函数在不同的头文件中声明。比如:

    math.h头文件中有:sin(x),cos(x),exp(x)(求e^x),fabs(x)(求x的绝对值)等库函数。

    stdio.h头文件中有:scanf(),printf(),gets(),puts(),getchar(),putchar()等库函数。

    string.h头文件中有:strcmp(),strcpy(),strcat(),strlen等库函数。

    2.函数的定义:

    (1)定义无参函数:

    类型名  函数名()

    {

    函数体

    }

    or

    类型名  函数名(void)

    {

    函数体

    }

    (2)定义有参函数

    类型名 函数名(形式参数表列)

    {

    函数体

    }

    (3)定义空函数

    类型名 函数名()

    {    }

    二,函数的调用

    1.函数调用时的参数传递

    函数间通过参数来传递数据,即通过主调函数中的实际参数(实参)向被调用函数中的形式参数(形参)进行传递。

    实参向形参传递数据的方式:实参将值单向传递给形参,形参的变化不影响实参值。

    for example:

    #include<stdio.h>
    #include<stdlib.h>
    int main()
    {
    	int a, b;
    	void swap(int a, int b);		//函数声明
    	scanf("%d%d", &a, &b);		//键盘输入
    	swap(a, b);		//函数调用
    	printf("最终的a,b值:\n  a=%d b=%d\n", a, b);
    	system("pause");
    	return 0;
    }
    void swap(int a, int b)
    {
    	int t;
    	if (a < b)
    	{
    		t = a;
    		a = b;
    		b = t;		//a中放大值,b中放小值
    	}
    	printf("自定义函数的a,b值:\n  a=%d b=%d\n", a, b);
    }
    

    运行结果为:

    分析:形参交换了数据,而实参保持原数据不变。这是单向的值传递,所以形参的值改变后而实参的值没有改变。

    • 形参在函数中是变量名,在函数调用时,形参被临时分配相应的内存,调用结束后,形参单元被释放,而实参单元保留并维持原值。
    • 实参是表达式,负责向对应的形参标识的内存单元传递数据,实参向形参的数据传递是“值传递”。
    • 实参与形参必须个数相同
    • 对应的形参和实参的类型必须一致

    2.函数的返回值

    (1)函数的返回值通过函数中的return语句获得。如果需要从调用函数带回一个函数值(供主函数使用),被调函数中需包含return语句。

    for example:

    int max(int x,int y)
    {
        return(x>y?x:y);
    }

    (2)在定义函数时要指定函数值的类型

    int max(float x,float y)            //函数值为整型
    char letter(char c1,char c2)            //函数值为字符型
    double max(int x,int y)            //函数值为双精度型

    (3)函数类型决定返回值的类型。

    3.函数的嵌套

    定义函数时不能定义另一个函数,但是可以进行嵌套调用函数。

    for example:

    *用函数嵌套找出4个数中的最大值。

    #include<stdio.h>
    #include<stdlib.h>
    int max2(int a, int b)			//找出a和b中的最大值
    {
    	if (a >= b)
    	{
    		return a;			//	a作为返回值
    	}
    	return b;				//	b作为返回值
    }
    int max4(int a, int b, int c, int d)	//定义找4个数最大值的函数
    {
    	int m;		//存最大值
    	m = max2(a, b);		//调用max2函数,将a,b中大的值放在m中
    	m = max2(m, c);		//调用max2函数,将a,b,c中大的值放在m中
    	m = max2(m, d);		//调用max2函数,将a,b,c,d中大的值放在m中
    	return m;		//返回到主函数
    }
    int main()
    {
    	int a, b, c, d;
    	int max;
    	printf("请输入四个数:\n");
    	scanf("%d%d%d%d", &a, &b, &c, &d);
    	max = max4(a, b, c, d);			//调用max4函数
    	printf("最大数位:%d\n", max);
    	system("pause");
    	return 0;
    }
    

    三,函数的递归

    1.递归概念:

    函数的递归调用是指:一个函数在他的函数体内直接或间接地调用它自身。分为:直接递归(函数直接调用自身)和间接递归(函数通过其他函数调用自身)。可分为“回溯”和“递推”两个阶段。

    2.递归函数的一般形式:

    反值类型   递归函数名(参数说明表)

    {

    if(递归终止条件)

    返回值=递归终止值;

    else

    返回值=递归调用(...)的表达式;

    return 返回值;

    }

    3.递归函数举例:

    *用递归求n的阶乘。

    #include<stdio.h>
    #include<stdlib.h>
    int fac(int n)		//定义函数
    {
    	int f;
    	if (n < 0)
    		printf("数据错误\n");
    	else if (n == 0 || n == 1)
    		f = 1;
    	else
    		f = n* fac(n - 1);			//n!=n*(n-1)
    	return f;			//返回主函数
    }
    int main()
    {
    	int n, y;
    	printf("请输入n的值\n");
    	scanf("%d", &n);
    	y = fac(n);		//这里n为实参
    	printf("%d!=%d\n", n, y);
    	system("pause");
    	return 0;
    }

    汉诺塔问题为经典的递归调用实例。代码如下:

    #include<stdio.h>
    #include<stdlib.h>
    void move(char x, char y)	//输出移盘方案
    {
    	printf("%c->%c\n", x, y);
    }
    void hanoi(int n, char one, char two, char three)		//移盘
    {
    	if (n == 1)
    		move(one, three);		//如果是1个盘,直接从第一个座移到第3个座上
    	else
    	{
    		hanoi(n - 1, one, three, two);		
    		move(one, three);
    		hanoi(n - 1, two, one, three);
    	}
    }
    int main()
    {
    	int n;
    	printf("输入盘的个数\n");
    	scanf("%d", &n);
    	printf("移盘的步骤:\n");
    	hanoi(n, 'A', 'B', 'C');
    	system("pause");
    	return 0;
    

    分析:将n个盘子从A座上移到C座上需要三步:

    (1)将A上的n-1个盘子借助C座先移到B座上;

    (2)把A座上剩下的一个盘子移到C座上;

    (3)将n-1个盘从B座上借助于A移到C座上。

     

    更多相关内容
  • C语言函数调用栈(一)

    2021-02-02 23:22:49
    程序的执行过程可看作连续的函数调用。当一个函数执行完毕时,程序要回到调用指令的下一条指令(紧接call指令)处继续执行。函数调用过程通常使用堆栈实现,每个用户态进程对应一个调用栈结构(callstack)。编译器使用...
  • C语言是一个强大的语言,特别是对于嵌入式开发过程中有时需要反汇编分析代码中存在的问题,函数C语言中的难点,关于函数调用也是很多人不能理解的,很多知道的也是一知半解。对C语言调用有了一个比较清晰的...
  • C语言函数调用函数的调用指的就是函数的使用方法。在程序中使用已经定义的函数,可以使用函数调用表达式,其一般格式如下:函数名(实参1, 实参2, …) //实参对应于函数定义时的形参声明程序执行时,函数调用表达式将...

    C语言函数被定义以后可以被多次调用,调用的时候可以向它传递参数。

    C语言函数调用

    函数的调用指的就是函数的使用方法。

    在程序中使用已经定义的函数,可以使用函数调用表达式,其一般格式如下:

    函数名(实参1, 实参2, …) //实参对应于函数定义时的形参声明

    程序执行时,函数调用表达式将会被函数返回值所代替(见图 1)。函数的返回值一般由 return 语句指定。

    a01b0cd5a67aa2913932c97ed19bfa7d.gif

    图 1:函数调用时参数的传递(值传递)和值的返回

    程序运行中进行函数调用后,程序的流程会转到被调用的函数处,同时传递过来的实参的值被赋值给函数对应的形参(形参初始化),接着执行函数体语句,在遇到 return 语句,或者执行到函数体最后的大括号时,程序流程就会从该函数跳转到原来调用函数的位置(见图 2)。

    e0e333913d54bcd4a6b657704905d5c4.gif

    图 2:调用函数时程序的执行流程

    代码清单 1:使用函数求两个整数中较大的值

    #include

    #include

    /*---自定义函数Max2:返回较大值---*/

    int Max2 (int a, int b)

    {

    if(a>b)

    return a;

    else

    return b;

    }

    /*---主函数---*/

    int main( )

    {

    int n1,n2;

    puts("请输入两个整数。\n");

    printf("整数1:"); scanf("%d",&n1);

    printf("整数2:"); scanf("%d",&n2);

    printf("较大的值是%d \n",Max2(n1,n2)); //调用Max2函数

    system("pause");

    return 0;

    }

    运行结果为:

    请输入两个整数。

    整数1:66

    整数2:47

    较大的值是66

    知识点总结

    函数调用的形式是在函数名后面加上小括号“()”。

    函数调用时,小括号“()”中的参数称为“实参”。

    函数调用的形式可称为“函数的调用表达式”。

    函数调用表达式的值就是函数的返回值。

    函数调用时参数的传递:值传递

    上面的代码清单 1 中,main( ) 函数通过 Max2(n1,n2) 调用自定义函数 Max2 时,实参变量 n1 的值被赋值给 Max2 的形参变量 a,实参变量 n2 的值被赋值给 Max2 的形参变量 b,此时,a 是 n1 的副本,两者具有相同的值,b 是 n2 的副本,两者具有相同的值。像这样通过值来进行参数传递的机制称为值传递。

    由于函数间参数的传递是通过值传递进行的,所以,函数调用表达式中的实参可以是另一个有返回值的函数调用表达式(见图 3)。

    d2378c348a6934c2d72300082d2d0e07.gif

    图 3:将函数的返回值作为参数传递给函数

    知识点总结

    函数间参数的传递是通过值的传递进行的。

    函数调用时实参的值会被赋给形参。

    形参所指的变量是对应的实参所指的变量的副本,它们具有相同的值。

    3. 函数调用时数组的传递

    自定义函数中,如果形参接收的是一个数组,则定义函数时要在形参声明中加上[ ]。而在函数调用表达式中的实参则直接使用数组名即可(见图 4)。

    指向数组的形参声明格式如下:

    类型名 形参名[ ] //形参名与指向的原数组名不同

    //类型名与数组的数据类型相同

    4b6c789c7fbad8062103cdcbb7d6a373.gif

    图 4:函数调用中数组和变量值的传递

    代码清单 2:使用函数(数组的传递)计算数学成绩和英语成绩的最高分

    #include

    #include

    #define NUMBER 5

    /*--自定义函数:返回拥有n个元素的数组v中的最大值--*/

    int Max_of(int v[],int n)

    {

    int i,max=0;

    for(i=0;i

    if(v[i]>max) max=v[i];

    return max;

    }

    /*---主函数---*/

    int main()

    {

    system("color 70");

    int i,eng[NUMBER],math[NUMBER],max_e,max_m;

    printf("请输入%d名学生的成绩。\n",NUMBER);

    for(i=0;i

    printf("[%d]英语:",i+1); scanf("%d",&eng[i]);

    printf(" 数学:"); scanf("%d",&math[i]);

    }

    max_e=Max_of(eng,NUMBER); //调用Max_of函数

    max_m=Max_of(math,NUMBER); //调用Max_of函数

    printf("英语最高分=%d\n",max_e);

    printf("数学最高分=%d\n",max_m);

    system("pause");

    return 0;

    }

    运行结果为:

    请输入5名学生的成绩。

    [1]英语:89

    数学:78

    [2]英语:77

    数学:88

    [3]英语:79

    数学:83

    [4]英语:71

    数学:87

    [5]英语:70

    数学:96

    英语最高分=89

    数学最高分=96

    图 5 展示了函数调用中数组的传递和变量值传递的区别。

    f0ce3505c5988c71e090ac3c46c0fed1.gif

    图 5:函数调用中数组的传递和变量值传递的区别

    知识点总结

    函数内接收数组的形参所指的数组就是原数组本身,只是数组名改变为形参的参数名而已(有别于一般变量参数值的传递)。

    在函数内对形参数组的修改实际上就是对实参数组(原数组)的修改。

    在函数内改变形参变量的值不会影响实参变量。

    展开全文
  • 假如函数在调用它之前定义... 您可能感兴趣的文章:深入理解C++中public、protected及private用法C/C++函数调用的几种方式总结浅析C语言中堆和栈的区别关于C语言中参数的传值问题浅谈C语言函数调用参数压栈的相关问题
  • C语言函数调用堆栈过程

    千次阅读 2018-11-01 17:15:27
    函数调用堆栈过程 调用约定 函数的调用约定很多,常见的包括__stdcall,__cdecl,__fastcall,__thiscall等等。主要的区别在于约束的三个事件,一个是参数传递是从左开始呢还是从右开始,还有就是堆栈清理的清理方是...

    函数调用堆栈过程

    调用约定

    函数的调用约定很多,常见的包括__stdcall,__cdecl,__fastcall,__thiscall等等。
    主要的区别在于约束的三个事件,一个是参数传递是从左开始呢还是从右开始,还有就是堆栈清理的清理方是调用者还是被调用者。另外来说不同的函数调用约定函数产生的符号名称不同

    举个栗子,对于cdecl,参数是从右到左传递,堆栈平衡是由调用函数来执行的;而win32API一般使用的是stdcall,参数同样是采用了从右往左传递,而函数的堆栈平衡则是由被调用函数执行(不支持可变参数);fastcall参数直接放入寄存器而非栈中,规定前两个参数分别放入ecx和edx中,当寄存器用完时候参数才按照从右往左的顺序压入堆栈。

    调用约定使用场景
    _cdeclc调用约定
    _stdcallwindows标准调用约定
    _fastcall快速调用约定
    _thiscallC++成员函数调用约定

    压栈过程

    int add(int a, int b)
    {
        return a+b;
    }
    
    int main()
    {
        int a = 1;
        int b = 2;
        int res = add(a,b);
        return 0;
    }
    1. 首先从main函数初始,ebp和esp分别存放函数的栈底地址和栈顶地址,此时ebp-4即是a,ebp-8则是b的地址。
    2. 然后调用函数add,第一先将参数从右往左依次入栈,push在调用方的函数栈当中,也就是说此时esp往里开辟了两个参数
      图片描述
    3. 执行call指令,首先将下一条指令地址进行入栈,
      图片描述
    4. 随后开辟新栈,进行现场保护
      图片描述

      • 这里省略了现场保护的过程,主要做的就是push了多个寄存器(例如edi,ebx,edi)的值,在完成后还原现场进行pop,对程序没有什么其他影响这里省略。
      • 将edi置为栈顶地址,ecx置为11h,eax置为0CCCCCCCCh。
      • 从edi开始循环拷贝eax,也就是将整个栈内初始化为0CCCCCCCCh,也就是常见的“烫”。
    5. 执行add函数
      开辟一个临时变量,值是(a)(ebp+8) + (b)(ebp+0Ch),将这个值放入eax中。
    6. 执行完成后回退栈针
      图片描述

      • 首先mov esp,ebp 将add的函数栈回退。
      • 随后pop,将[ebp]的值弹出给ebp,也就是ebp弹回退到main函数的栈底。
      • 执行ret指令,将下一条指令的地址弹出给eip寄存器。
      • 随后在main函数的函数栈中回退形参变量所占用的内存 add esp+8。

    那么再来看看其他情况

    上面的返回值是一个int类型,也就是C的内置类型,通过eax寄存器带出。

    如果是一个double或者long long呢?那么可以通过eax、edx两个寄存器带出。

    如果是一个自定义类型呢?其实也是类似的:

    • 首先在参数传参过程中不能直接去push一个寄存器了,而现在是通过开辟内存后,将自定义类型的实参b的地址放入esi中,循环赋给实参。
      例如说自定义类型的b参数
      图片描述
    • 参数传递完成之后,再来看看返回值,返回值首先会在压入所有的形参之后,将main函数中返回值(临时量)的地址压入参数。
      图片描述
    • 对返回值的操作也是类似的,通过esi和edi、ecx,循环拷贝到main函数的函数栈之中。
    • 临时量返回值的地址是最后才会压栈的,那么它的地址一定是ebx+8
    展开全文
  • c语言函数调用原理底层分析

    千次阅读 2019-03-26 22:51:27
    2函数调用机制 2.1按调用约定传递参数 2.1调用约定 调用方(caller)和被调方(callee)需要约定以下内容: 1传参顺序 2传递参数的媒介(是放栈还是寄存器) 3清理参数的责任归属 4返回值的传递媒介(返回值...

    1函数的功能主要是为了复用性,不同的属性可以参数化

     

    2函数调用机制

    2.1按调用约定传递参数

    2.1调用约定

    调用方(caller)和被调方(callee)需要约定以下内容:

    1传参顺序

    2传递参数的媒介(是放栈还是寄存器)

    3清理参数的责任归属

    4返回值的传递媒介(返回值是放栈还是寄存器)

    __cdecl:传参顺序从右往左;

    使用栈顶传递参数;

    由调用方清理参数;

     

    __stdcall:传参顺序从右往左;

    使用栈顶传递参数;

    由被调方清理参数;

     

    __fastcall传参顺序从右往左;

    左边前两个基本属性类型的参数通过处理器传递,其余各参数使用栈 顶传递参数;

    由被调用方清理参数;

    2.2保存函数返回地址

    2.2.1流程转移到被调用方

    2.3保存调用方的栈底

    2.4设置当前栈顶为被调用方的栈底(此时被调方处于空栈状态)

    2.5根据局部变量所需的总空间抬高栈顶(为局部变量分配空间)

    2.6保存处理器环境(把调用方的处理器中的值复制到栈顶(不保存的话,调用方寄存 器的值会被被调方覆盖))

    2.7debug选项组在此时设置局部变量的初值为0xcccccccc

     

    2.8执行函数体

     

    2.9恢复处理器的环境(把栈顶的值复制到处理器中)

    2.10释放局部变量空间

    2.11从栈顶取值恢复到调用方的栈底

    2.12从栈顶取值作为返回地址

    2.12.1__stdcall,__fastcal被调用方此时释放参数空间

    2.13流程恢复到调用方的代码

    2.13.1__cdecl调用方此时释放参数空间

    这些流程可以用图表示,也可以在内存中查看栈的存放顺序如下图

    内存中栈存放如下图

     

    展开全文
  • 本文主要为大家详细讲解一下C语言函数调用参数压栈的相关问题。
  • C语言函数调用过程

    千次阅读 多人点赞 2018-04-22 18:44:44
    C语言函数调用过程 反汇编代码 main()函数的创建 Add()函数的调用过程 main()函数的销毁 C语言函数调用过程 先上一段代码 #include&lt;stdio.h&gt; int Add(int x, int y) { int z = 0; z = x...
  • C语言函数调用规定.doc
  • C语言函数调用约定.doc
  • C语言函数调用实验.doc
  • C语言函数调用实验.rar
  • C语言函数调用规定.rar
  • C语言函数调用规定.pdf
  • C语言函数调用常见问题(1)

    千次阅读 2019-01-09 11:34:58
    在我看来 有许多计算问题如果通过函数调用方式来解决就会使得代码整体看起来简介又便于识别 但是在调用函数时候要注意以下几个问题 一、基本功能 1、函数调用,即把函数的输入值填进函数名后面的括号中,不需要注明...
  • C语言函数调用汇编语言函数[归纳].pdf
  • C语言函数调用时候内存中栈的动态变化详细分析

    千次阅读 多人点赞 2019-05-02 00:23:41
    先了解如下几点知识和过程: ...这些指令代码是存放在内存中进程的代码段,同一个函数内的指令代码是按照地址顺序存储的(编译器决定的)(也就是说只要指令地址+1就可以自动得到下一条指令的地址...
  • C语言函数调用栈实例分析.md
  • C语言函数调用是怎么样一个过程?

    千次阅读 2019-03-07 19:04:27
    大多数CPU上的程序实现使用栈来支持函数调用操作,栈被用来传递函数参数、存储返回信息、临时保存寄存器原有的值以备恢复以及用来存储局部变量。 函数调用操作所使用的栈部分叫做栈帧结构,每个函数调用都有属于...
  • #include "stdafx.h" //实现1!+2!+..+n!求和,并输出每个阶乘值 void jiechenghe(int n); int main() { int n; printf("请输入n:"); scanf("%d",&n); jiechenghe(n); return 0; } ....
  • c语言函数调用详细过程[参考].pdf
  • C语言函数调用

    2013-08-26 09:28:55
    C语言三个重要函数调用,传值,传址,传引用
  • C语言函数调用的底层机制C语言函数调用的底层机制C语言函数调用的底层机制C语言函数调用的底层机制C语言函数调用的底层机制C语言函数调用的底层机制
  • c语言函数调用中用指针操作数组

    千次阅读 2020-08-18 17:23:07
    直接上代码 #include using namespace std; int p[20]; void change(int *p){ for(int... } 输出为 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 如果你传入的指针指向的是一个数组,在函数体中就可以直接用数组下标等操作
  • 差不多每个程序员都知道,函数调用过程,就是层层入栈出栈的过程。 那么这个过程中的详细的细节是什么样子的呢? 阅读了以下几篇文章之后,对整个过程基本理解了: C函数调用过程原理及函数栈帧分析 阅读经典——...
  • Python3.x + Graphviz自动化绘制C语言 函数调用关系图、结构体关系图 已使用Cython将Python代码转化为c,可以自行编译安装 1.2. 软件架构 软件架构说明 1.3. 安装教程 sudo -H pip3 in...
  • 我想,你只要看了C语言上关于传值函数调用的测试题,一切都会了然于胸:1. 考题一:程序代码如下:void Exchg1(int x, int y) {int tmp;tmp=x;x=y;y=tmp;printf(“x=%d,y=%d/n”,x,y)}void main(){int a=4,b=6;...
  • 浅谈C语言函数调用与系统调用

    千次阅读 2019-11-12 09:55:50
    很多初学C语言的同学,亦或者开发中很少接触系统底层的同学可能会认为函数调用以及系统调用是一回事。因为在应用程序,两者都被抽象成接口去给应用程序调用。其实函数调用和系统调用还是有区别,我们通过下图先有个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 442,681
精华内容 177,072
关键字:

c语言函数调用

友情链接: 7805.zip