如何编写有多个返回值的C语言函数

2023-11-14

 

1引言
  
  笔者从事C语言教学多年,在教学中学生们常常会问到如何编写具有多个返回值的C语言函数。编写有多个返回值的函数是所有C语言教材里均没有提到的知识点,但在实际教学与应用的过程中我们都有可能会遇到这样的问题。有学生也尝试了不少方法:如把多个需要返回的值作相应的处理后变成一个可以用return语句返回的数据,再在主调函数中拆开返回的数据使之变成几个值;或者把需要返回多个值的一个函数分开几个函数去实现多个值的返回。这些方法虽然最终都能实现返回要求的多个值,但从程序算法的合理性与最优化方面去考虑,显然不理想。我们知道C语言函数的返回值是通过函数中的return语句来实现的,可是每调用一次函数,return语句只能返回一个值。那么当我们希望从一个函数中返回多个值时,用什么方法去实现比较合理呢?在教学过程中,我建议学生跳出对return语句的定势思维,一步步引导学生通过几种间接方式实现多个返回值的C语言函数。以下是笔者在教学过程中引导学生采用的三种不同方法编写多个返回值的C语言函数。
  
  2方法1:利用全局变量
  
  分析:全局变量作为C语言的一个知识点,虽然我们都了解它的特点,但在实际教学过程中应用得并不是很多。由于全局变量的作用域是从定义变量开始直到程序结束,而对于编写有多个返回值的C语言函数,我们可以考虑把要返回的多个值定义成全局变量。当函数被调用时,全局变量被更改,我们再把更改后的全局变量值应用于主调函数中。函数被调用后被更改后的全局变量值即为函数的数个返回值。下面以一个实例演示该方法的应用。
  实例1:编写函数求3个数中的最大值与最小值。
  方法:把最大值、最小值分别定义成2个全局变量max、min,在用户自定义函数中把求出来的最大值与最小值分别赋给全局变量max、min。函数调用完毕后全局变量的max、min值即保存了函数要求返回的值。程序参考代码如下:
  #include "stdio.h"
  #include "conio.h"
  int max,min;/*定义两个全局变量用于保存函数返回值*/
  void max_min(int a,int b,int c) /*定义求最大最小值的函数*/
  {max=min=a; /*初始化最大最小值*/
   if(max   if(max   if(min>b)min=b;
  if(min>c)min=c;
  }
  main()
  {int x,y,z;
  printf(" 请输入3个整数:\n");
  scanf("%d,%d,%d",&x,&y,&z);
  max_min(x,y,z) ;/*调用求最大值与最小值的函数*/
  printf("三个数中的最大值为:%d;最小值为:%d",max,min);/*输出最大值与最小值*/
  getch();
  }
  调试结果如下:
  请输入3个整数:
  5,-6,2
  三个数中的最大值为:5;最小值为:-6
  注意:该方法虽然可以实现有多个返回值的函数,但由于全局变量不能保证值的正确性(因为其作用域是全局,所以程序范围内都可以修改它的值,如果出现错误将非常难以发现),并且全局变量增加了程序间模块的耦合,所以该方法要慎用。
  
  3方法2:传递数组指针
  
  分析:在教学过程中,我们知道C语言函数参数的传递方式有值传递与地址传递。当进行值传递时,主调函数把实参的值复制给形参,形参获得从主调函数传递过来的值运行函数。在值传递过程中被调函数参数值的更改不能导致实参值的更改。而如果是地址传递,由于传递过程中从实参传递过来的是地址,所以被调函数中形参值的更改会直接导致实参值的更改。因此,我们可以考虑把多个返回值作为数组元素定义成一个数组的形式,并使该数组的地址作为函数的形式参数,以传址方式传递数组参数。函数被调用后,形参数组元素改变导致实参改变,我们再从改变后的实参数组元素中获得函数的多个返回值。以下实例演示该方法的应用。
  实例2:编写函数求一维整形数组的最大值与最小值,并把最大值与最小值返回给主调函数。
  方法:以指针方式传递该一维数组的地址,然后把数组的最大值与数组的第一个元素交换,把数组的最小值与最后一个元素交换。函数被调用完毕后,实参数组中的第一元素为数组的最大值,实参数组中最后一个元素为数组的最小值,从而实现返回数组的最大值与最小值的功能。程序参考代码如下:
  #include "stdio.h"
  #include "conio.h"
  void max_min(int *ptr,int n) /*定义求数组最大值最小值的函数,传递数组指针*/
  {int i,j,k;/*j保存最大值所在位置,k保存最小值所在位置*/
  int *temp;/*用于交换位置*/
  *temp=*ptr;
  for(i=0;i  {
  if(*ptr<*(ptr+i))/*最大值与第一个元素进行交换*/
  {
  k=i;
  *temp=*ptr;
  *ptr=*(ptr+k);
  *(ptr+k)=*temp ;
  }
  if(*(ptr+n-1)>*(ptr+i))/*最小值与最后一个元素进行交换*/
  {
  j=i;
  *temp =*(ptr+n-1);
  *(ptr+n-1)=*(ptr+j);
  *(ptr+j)= *temp ;}
  }
  }
  /*调用最大最小值函数*/
  main()
  {
  int A[6],i;
  for(i=0;i<6;i++)
   scanf("%d",&A[i]);
  max_min(A,6);
  printf("max=%d, min=%d\n \n",A[0],A[5]);
  getch();
  }
  调试结果如下:
  请输入6个整形数,以空格隔开:
  5 8 9 32 -6 4
  max=32,min=-6

注意:该方法适用于多个返回值的数据类型一致的情况。当返回值数据类型不一致时,不适用该方法。
  
  4方法3:传递结构体指针
  
  分析:结构体作为教学中的一个难点,教材对它介绍的内容并不多,应用的实例更是少之又少,所以学生对于结构体普遍掌握情况不理想。其实,编写返回多个值的C语言函数,也可以考虑采用结构体的方式去实现。通过方法2,我们知道如果返回的数个数值的数据类型不一致,可以通过定义全局变量实现有多个返回值的C语言函数,也可以考虑把要求返回的数个值定义成一个结构体,然后同样以传递结构体指针方式把结构体的指针传递给形参结构体指针,那么函数中对形参结构体的修改即是对实参结构体的修改,函数被调用后获取的实参结构体成员即为函数的多个返回值,下面以实例演示该方法的应用。
  实例3:编写一个用户自定义函数,允许用户录入学生的基本信息(包括学号、姓名、所属班级、总评成绩),并返回这些基本信息给主调函数。
  


  方法:把学生基本信息定义成一个结构体,在用户自定义函数中传递该结构体的指针,则自定义函数中对结构体成员的录入操作即是对实参结构体成员的录入操作,从而实现多个返回值。参考代码如下:
  #include "stdio.h"
  #include "conio.h"
  struct inf{/*定义学生结构体,分别包含成员学号、姓名、班别、总评成绩*/
   char xh[12];
   char name[20];
   char class[15];
   int chj;
  };
  main(void)
  {
  struct inf a1; /*定义学生结构体类型变量*/
  void xxxx(struct inf *ptr);
  printf("请输入学号,姓名,班别,总评成绩,以空格隔开:\n") ;
  xxxx(&a1);/*调用函数,以学生结构体类型变量地址作为实参*/
  printf("学号:%s,姓名: %s,班别:%s,总评成绩:%d",a1.xh, a1.name,a1.class,a1.chj);
  getch();
  }
  void xxxx(struct inf *ptr)/*该函数实现对结构体成员数据的录入操作*/
  {
   char xh1[12],name1[20],class1[15];
   int chj1;
  scanf("%s%s%s%d",xh1,name1,class1,&chj1);
   strcpy(ptr->xh,xh1);
  strcpy(ptr->name,name1);
  strcpy(ptr->class,class1);
  ptr->chj=chj1;
   }
  调试结果如下:
  请输入学号,姓名,班别,总评成绩,以空格隔开:
  200102LiLi200185
  学号:200102,姓名: LiLi,班别:2001,总评成绩:85
  注意:当函数要求返回的多个值是相互联系的或者返回的多个值数据类型不一致时可以采用该方法。
  
  5结束语
  
  对于以上这三种方法,如果想要返回的数个值数据类型一致,可以考虑采用方法2;而对于不同数据类型的返回值,如果各个数值之间是相互联系的,则方法3较为合适;方法1虽然在很多情况下都可以实现多个返回值的C语言函数,但毕竟全局变量应用过程中有很多危险,要慎重使用。
  通过对以上几种方法的分析讲解,在教学过程中,学生再遇到这样的问题时,就能根据返回值的情况选择合适的途径去实现多个返回值的C语言函数。另外,如果再遇到类似的无法用教材知识点去直接解决的问题时,他们基本都能举一反三地尝试采用间接方式去解决。
  
  参考文献
  [1] 谭浩强. C程序设计(第二版)[M]. 北京:清华大学出版社,1999.
  [2] 薛万鹏译. C程序设计教程[M]. 北京:机械工业出版社,2000.
  [3] 邓劲生译. Visual C++程序员实用大全[M]. 北京:中国水利水电出版社,2005.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何编写有多个返回值的C语言函数 的相关文章

  • 结构中字符串的管理

    我知道字符串的长度是可变的 因此它们需要内存中的可变空间来存储 当我们在 a 中定义一个字符串项时struct the struct的大小的长度将是可变的 较旧的语言通过使用固定长度的字符串来管理此问题 但是 C 中没有办法定义固定长度的字
  • 为什么找不到ImageView类?

    当我转到图形布局时 我在创建第一个 Android 应用程序 pdf Android Application Development for For Dummies 中的静默切换模式 时遇到了麻烦 在 main xml 文件中插入了 Ima
  • 在 C 或 C++ 中返回结构是否安全?

    我的理解是不应该这样做 但我相信我已经看到过这样做的示例 注意代码不一定在语法上正确 但想法就在那里 typedef struct int a b mystruct 然后这是一个函数 mystruct func int c int d my
  • 使用 javascript/jQuery 更改类的背景颜色属性

    这似乎是一个简单的问题 但没有任何解决办法 我正在尝试使用 javascript jQuery 动态更改某些文本的背景颜色 从白色或粉色到绿色 但由于某种原因它不起作用 文本使用名为 novice 的 CSS 类进行样式设置 这是CSS 这
  • “struct X typedef”与“typedef struct X”的含义是什么?

    我在现有代码库中有以下 工作 代码 在 C 和 C 之间共享的包含文件中使用 在 MSVC 2010 和 Windows DDK 上编译 struct X USHORT x typedef X PX And enum MY ENUM enu
  • 在 C 中使用另一个结构中的二维结构数组的编码问题

    我正在使用一个二维结构数组 它是另一个结构的一部分 这不是我做过很多事的事情 所以我遇到了问题 该函数在接近末尾的 测试 for 循环后最终失败 它在出现段错误之前正确打印出一行 我的代码中将数据读入虚拟二维结构数组的部分工作得很好 所以它
  • C# 中的类和模块有什么用

    有人可以解释一下类和模块之间的区别吗 你什么时候使用其中一种而不是另一种 我正在使用 C 更新 我的意思是相当于 VB 模块的 C 版本 这在很大程度上取决于您所指的 模块 Visual Basic 的模块 C 中没有真正等效的 VB Ne
  • 结构体tag和name,为什么声明为name的局部变量会编译?

    在我最近看到的一些代码中 有一个如下定义的结构 typedef struct tagMyStruct int numberOne int numberTwo MYSTRUCT 按照我的理解 tagMyStruct是新的数据类型并且MYSTR
  • GLSL 中的二阶函数?

    我正在寻找一种方法来使用一个函数作为 GLSL 中另一个函数的参数 在常规 C 中 可以通过传递函数指针作为函数参数来模拟它 似乎其他语言 如 HLSL 现在提供了处理高级构造 如高阶函数 的方法 或者可以使用以下命令来模拟它们巧妙利用 H
  • 如何使用javascript通过类名更改html元素的值

    这是我用来更改 html 元素值的代码 a class classname href Vtech com This text to be chnage a 如何在页面加载瞬间更改此文本 看来你需要添加DOMContentLoaded或者把你
  • 非静态字段、方法或属性需要对象引用

    我知道人们以前问过这个问题 但场景太具体 我对基本原理感到困惑 我有两个基本版本的 C 程序 一种有效 一种无效 如果有人能解释为什么我收到错误 我会很高兴非静态字段 方法或属性需要对象引用在第二个程序中 Works namespace E
  • 从模板类创建对象时出错

    我一直在尝试找到一种方法 从 C 中的多元正态分布中采样随机向量 同时具有均值向量和协方差矩阵 就像 Matlab 的那样mvnrnd功能有效 我找到了实现此功能的类的相关代码这一页 http lost found wandering bl
  • 检查一个类是否是另一个类的子类

    我想在不创建实例的情况下检查一个类是否是另一个类的子类 我有一个类 它接收类名作为参数 作为验证过程的一部分 我想检查它是否属于特定的类系列 以防止安全问题等 有什么好的方法可以做到这一点吗 is subclass of http php
  • 使用 jQuery 更改 CSS 类属性

    有没有办法使用 jQuery 更改 CSS 类的属性 而不是元素属性 这是一个实际的例子 我有一个 div 类red red background red 我想转班级red背景属性 而不是具有类的元素red分配的背景 如果我用 jQuery
  • 动态创建类 - Python

    我需要动态创建一个类 为了更详细地讲 我需要动态创建 Django 的子类Form class 通过 动态 我打算根据用户提供的配置创建一个类 e g 我想要一个名为CommentForm这应该子类化Form class 该类应该有一个选定
  • 内联函数以及类和头文件

    头文件中定义的任何函数都会自动内联吗 如果我在类中声明一个函数并使用关键字 inline 在外部给出定义 那么这个函数会是内联的吗 如果是 为什么这不违反内联函数应在声明时赋予主体的法律 类定义中定义的任何函数都是内联的 任何标记的功能in
  • 以类型化内存视图作为成员的结构定义

    目前我正在尝试让一个具有类型化内存视图的结构能够工作 例如 ctypedef struct node unsigned int inds 如果 inds 不是内存视图 据我所知 它可以完美地工作 然而 通过内存视图并使用类似的东西 def
  • 为什么我无法访问打字稿类的构造函数中的抽象属性

    abstract class Route abstract readonly name string protected abstract pattern string public constructor Do something wit
  • 类方法作为 JavaScript 中的事件处理程序?

    JavaScript 中是否有最佳实践或通用方法将类成员作为事件处理程序 考虑以下简单示例
  • 如何将 UDF 中的结构或类数组返回到数据帧列值中?

    d ID 1 pID 1000 startTime 2018 07 02T03 34 20 endTime 2018 07 03T02 40 20 ID 1 pID 1000 startTime 2018 07 02T03 45 20 en

随机推荐