C语言函数间参数的传递方式(一)有返回的函数

“我们是伞兵,本来就该被包围的!”----《兄弟连》。

在战争中,伞兵天生就该被包围,而在编程语言中,函数生来就该被调用。在被调用的过程中,执行函数的指令,完成值和参数的传递。按照不同的传递方式,函数可以分为下面几类:

 

 

 1、先来看返回变量、常量的函数:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 int func(int a)
 5 {
 6     a=2*a*a;
 7     printf("a=%d\n",a);
 8     return a;
 9 }
10 int main()
11 {
12     int b=func(10);
13     printf("b=%d\n",b);
14     return 0;
15 }

 

上面的函数是返回变量的值,如果把被调函数func中的变量a换成常量,程序依然能够得到正确结果。例如:

 1 #include <stdio.h>
 2 
 3 int func()
 4 {
 5     const char a='W';
 6     printf("A=%c \n",a);
 7     return a;
 8 }
 9 int main()
10 {
11     char b=func();
12     printf("b=%c \n",b);
13     return 0;
14 }

也许有人会问,辛辛苦苦敲了半天代码,就返回了一个字符,为什么不返回一个字符串那?返回字符串不是不行,可要返回字符串,就不能按照返回一般的变量、常量来处理了。我们知道,在C语言编程环境下,字符串只能用字符型数组或者字符型指针来声明和定义,不存在C++语言语言环境下的string类型。因此,当你要返回字符串的时候,其实需要返回的是字符串的地址。这就引出了我们的下一个课题:

2、返回字符串地址

函数不仅能返回值,还能返回地址。返回地址时,需要在函数的返回值数据类型前面加”*“,下面看例程:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 
 5 char* getString()
 6 {
 7     char str[] = "hello,world";
 8     return str;                  //返回数组地址
 9 }
10 void test02()
11 {
12     char* p = NULL;
13     p = getString();  //接收字符串数组地址
14     printf("test02返回字符串数组:  %s \n", p); 
15     /* 因为p接收的是被返回的字符串数组的地址。而字符串数组在栈上,    当getString函数
16     执行完以后,str字符串已经被内存释放了,test02函数调用它的结果就不确定了。 */
17 }                
18 
19 int main()
20 {
21     test02();
22     return 0;
23 }

运行程序,我们会发现,字符串数组没有被正确输出。下面再看一例:

3、局部变量地址的返回

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 
 5 int* func()
 6 {
 7     int a = 10;
 8     return &a;
 9 }
10 void test01()
11 {
12     int* p = func(); //这种调用,结果已经不重要了,因为a的内存(因该是a所指向的内存)
13                      //被系统释放了,我们没有权限区操作这块内存
14     printf("test01第一次:a=%d \n", *p); //第一次输出‘10’,因为系统默认为作者保留这段内存
15     printf("test02第二次:a=%d \n", *p); //第二次输出内容就不定了,系统已经将这段内存释放了
16 }
17 
18 int main()
19 {
20     test01();
21     return 0;
22 }

如果我们用VS2015以上编辑器运行上面代码,控制台会输出注解的内容。如果用codeblock或者其他编辑器运行,则有可能无任何输出,因为你输出的内存数据是无效的。综合起来看,函数不能返回在被调函数中定义的局部变量、数组形式声明的字符串(字符串数组)。因为他们存放在栈上。随着被调函数运行结束,这些局部变量、字符串等占用的内存被释放。再访问上述内存空间就是非法访问了。那么是不是函数就不能返回地址了那?不是!函数可以返回存放在程序数据区、堆区的地址(关于内存分区的内容参见:https://www.cnblogs.com/GoldCrop/p/11030984.html)。详见下面例子:

4、堆及程序数据区地址的返回

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 
 5 char* getString01()
 6 {
 7     char *str= malloc(64);  //在堆上定义字符串
 8     memset(str,0,64);
 9     strcpy(str,"hello,world");
10     return str;       //返回字符串地址
11 }
12 void test02()
13 {
14     char *q = getString01();    //接收字符串地址
15     printf("堆上字符串内容       :%s \n", q);  /* 因为字符串地址存放在堆区,即使getString01
16                                    运行完后,字符串所在内存也不会被释放,可以返回字符串地址 */
17 }                
18 
19 char* getString02()
20 {
21     char* str = "hello,world!"; //声明并定义字符串指针变量,字符串存储在数据区
22     return str;                 //返回指针地址
23 }
24 void test03()
25 {
26     char* p = NULL;
27     p= getString02();
28     printf("程序数据区字符串内容 :%s \n", p);
29 }
30 int main()
31 {
32     test02();
33     test03();
34     return 0;
35 }

 通过上面的例子可以看出,我们能返回程序数据区、堆区变量、常量的地址,但不能返回栈区的变量、常量的地址。

posted @ 2019-06-21 15:10  大老菜  阅读(2895)  评论(0编辑  收藏  举报