言C语言陷阱与技巧第21节,函数只能返回一个值吗?有多个返回值怎么办?

如今几乎找不到只专注于一门编程语言的程序员了。大多数程序员在自己平时的工作和生活中,一般都使用不止一门编程语言,例如小编在工作中主要使用的是C语言,但是有时候验证算法也会使用 matlab 和 python,在业余做别的项目时还会用到 C#。

不得不承认,就便用性而言,C语言的确相对比较简陋,所以如果从C语言转向别的编程语言还好,要是从 python 这样的高级语言转向 C语言,常常会感到一些“不便”。例如使用 python 编写程序时,函数返回多个值是非常方便的:

def fun():
    ...
    return a, b

但是很多C语言初学者在编写某个函数,需要返回多个值时会感到困难,毕竟C语言的 return 语法只能返回一个值,返回多个值就会引起语法错误:

int fun()
{
    ...
    return a, b;    // 非法
}
那么,是不是C语言函数无法返回多个值呢?请继续往下看。

“返回”多个值

虽然C语言的语法限定 return 语句只能返回一个值,但C语言函数完全可以向函数调用者传递多个值。可能有些读者像小编一样,尝试过使用全局变量作为多值传递的手段:

int a, b;
void fun(){
    ...
    a = res1;
    b = res2;
}
int main()
{
    fun();
    printf("%d %d\n", a, b);
    return 0;
}

上述C语言代码中,fun() 函数会将最终处理结果 res1 和 res2 存入 a 和 b,利用全局变量的全局可见性,间接的将两个结果“返回”给 main() 函数。这样做当然没问题,但是如果涉及到多线程编程,没有同步保护的使用全局变量就不安全了,很容易给程序带来意想不到的问题,所以,在实际的C语言程序开发中,极少使用这种方法。

怎样才能更好的让C语言函数返回多个值呢?

C语言区别其他大多数高级编程语言的特性是指针语法,事实上,C语言的指针非常强大,利用指针,我们能够很轻易的让C语言函数安全的“返回”多个值。

C语言的指针允许程序直接操作内存,所以函数可以将任意多的值放入内存(只要内存够用),再将这些值的地址和访问方式告诉调用者,那么调用者完全可以将这些值从内存中取出,这样的过程其实就实现了C语言函数“返回”任意多的值。

下面是一个使用C语言中的指针语法返回多个值的例子:

void fun(int *a, int *b)
{
    ...
    *a = res1;
    *b = res2;
}
int main()
{
    int x=1, y=2;
    fun(&x, &y);
    printf("%d %d\n", x, y);
    return 0;
}

在上述C语言代码中,fun() 函数接收两个参数,不过这两个参数都是 int 指针类型,main() 函数调用 fun() 时,将自己的局部变量 x 和 y 的地址传递给 fun(),此时 fun() 的参数 a 指向变量 x,参数 b 指向变量 y。

借助于指针语法,fun() 函数可以直接操作 main() 函数中的变量 x 和 y,所以 fun() 函数不仅可以读取 x 和 y 的初值,也可以在自己的内部逻辑处理完毕后,将处理结果直接写到 x 和 y。这样看来,甚至都无需 return 语法,C语言函数就能很方便的返回多个值。

小结

本节主要讨论了C语言函数返回多个值的两个方法:一是借助全局变量,再就是使用指针。考虑到全局变量在多线程编程中需要做同步保护,比较麻烦,所以在实际的C语言程序开发中,需要返回多个值时,更多是借助指针实现。

不过,如果需要返回的值比较多,通过被调用函数参数传递“返回值”就不方便了。事实上,如果某个函数的参数过多,也比较影响C语言程序的效率。针对这种情况,借助指针联合结构体语法,能够实现更方便更安全的“返回值”传递。如果读者对这种方法感到迷惑,可以阅读本专栏的下一篇文章,感谢支持。

阅读更多:   杂谈 , C语言
添加新评论

icon_redface.gificon_idea.gificon_cool.gif2016kuk.gificon_mrgreen.gif2016shuai.gif2016tp.gif2016db.gif2016ch.gificon_razz.gif2016zj.gificon_sad.gificon_cry.gif2016zhh.gificon_question.gif2016jk.gif2016bs.gificon_lol.gif2016qiao.gificon_surprised.gif2016fendou.gif2016ll.gif