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 }

 通過上面的例子可以看出,我們能返回程序數據區、堆區變量、常量的地址,但不能返回棧區的變量、常量的地址。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM