C語言函數間參數的傳遞方式(二)沒有返回,僅僅靠形參、實參傳遞參數的函數


這一篇我們來看看沒有返回,只靠形參、實參傳遞參數的函數,先來學習最簡單的一種:

1、傳值調用(賦值傳遞)

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 
 5 void swap(int a,int b)
 6 {
 7     int temp;
 8     printf("交換前,a=%d  b=%d \n",a,b);
 9     temp=a;
10     a=b;
11     b=temp;
12     printf("交換后,a=%d  b=%d \n",a,b);
13 }
14 int main()
15 {
16     int x=10,y=20;
17     printf("交換前,x=%d  y=%d \n",x,y);
18     swap(x,y);
19     printf("交換后,x=%d  y=%d \n",x,y);
20     return 0;
21 }

從運行程序結果可以看出:被調函數swap只對形參操作,實參無變化。顯然,傳值調用屬於單向值傳遞,函數運行結果不影響、不改變調用函數的實參。

看過了最簡單的,下面來看看復雜一點兒的————引用調用(指針傳遞、賦地址傳遞)。C語言中,這個詞也被叫做“指針傳遞”、“賦地址傳遞”。在C++語言中,則有另外的含義了。用起來,也會方便許多,但是,C語言不支持。引用調用(指針傳遞、賦地址傳遞)分為同級指針傳遞,和二級指針傳遞2種方式。同時,根據主調函數是否申請內存,又分兩種情況來分析。下面先來看:

2、主調函數申請內存條件下,同級指針傳遞:

     2.1  主調函數申請內存,同級指針傳遞(傳遞變量地址)

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 
 5 void swap(int * a,int *b)
 6 {
 7     int temp;
 8     printf("a地址:%p    b地址:%p    \n",a,b);
 9     printf("交換前,a=%d  b=%d \n",*a,*b);
10     temp=*a;
11     *a=*b;
12     *b=temp;
13     printf("交換后,a=%d  b=%d \n",*a,*b);
14 }
15 int main()
16 {
17     int x=10,y=20;
18     printf("x地址:%p    y地址:%p\n",&x,&y);
19     printf("交換前,x=%d  y=%d \n",x,y);
20     swap(&x,&y);
21     printf("交換后,x=%d  y=%d \n",x,y);
22     return 0;
23 }

本例中,main主函數申請了2個變量——x和y,並把它們的地址——&x和&y傳遞給被調函數swap,被調函數的形參定義了2個指針變量int *a,int *b來接收。由於a,b,&x,&y都是地址,相當於a=&x,b=&y。

如果把&x和&y也看成指針,則有*a=*(&x)=x,*b=*(&y)=y。顯然,對其解引用后,所得值為變量的值,而不是地址。所以稱之為同級指針傳遞(因為a,b和&x,&y都是只需一次解引用操作即可求得變量的值,我認為稱之為“一級指針傳遞”更為貼切)。

從程序運行結果來看,被調函數修改了實參的值。所以,我們能得出結論:主調函數申請內存,同級指針傳遞實參變量地址,被調函數能夠修改實參的值。

下面我們來看看堆和棧上字符串地址的傳遞:

      2.2  主調函數申請內存,同級指針傳遞(傳遞堆上、棧上字符串地址)

 1 void func(char* p)
 2 {
 3     strcpy(p, "Hello,World!");
 4 }
 5 void test01()
 6 {
 7     //分配到棧上
 8     char buf[1024] ="I like C語言!";
 9     printf("棧上初始字符串:%s \n", buf);
10     func(buf);
11     printf("主調函數申請內存,同級指針傳遞,棧上字符串返回:%s \n", buf);
12 }
13 
14 void printString(char* str)
15 {
16     strcpy(str, "Hello,World!");
17     printf("主調函數申請內存,同級指針傳遞,堆上字符串返回:%s \n", str);
18 }
19 void test02()
20 {
21     //分配到堆區
22     char* p = malloc(sizeof(char) * 64);
23     memset(p, 0, 64);    
24     strcpy(p, "I like C語言!");
25     printf("堆上初始字符串:%s \n", p);
26     printString(p);
27     printf("字符串長度=%d \n", strlen(p));
28 }
29 
30 int main()
31 {
32     test01();
33     test02();
34     system("pause");
35     return EXIT_SUCCESS;
}

這里,由於我們可以把字符串名“buf”和指針“p”看作地址,顯然,這也是同級指針傳遞。並且,通過程序運行結果,我們可以得出結論:主調函數申請內存,同級指針傳遞字符串地址,被調函數能夠對堆和棧上字符串進行賦值,修改操作。

 下面再來看一段代碼:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 
 5 void buildString(char* pp)
 6 {
 7     char* temp = "被調函數修改字符串";
 8     pp = temp;
 9     printf("%s \n", *pp);
10 }
11 void test01()
12 {
13     char* p = "主調函數定義初始字符串";
14     printf("%s \n", p);
15     buildString(p);
16     printf("%s \n", p);
17 }
18 
19 int main()
20 {
21     test01();
22     return 0;
23 }

上面這段代碼無法正常運行,再次證明了一個事實:以指針形式聲明的字符串,保存在程序數據區,不能被改動。

通過上面3個例程,我們可以得出結論:主調函數申請內存,同級指針傳遞地址(無論是變量地址還是堆或者棧的地址)條件下,被調函數能夠修改實參的值。當然,程序數據區的字符串依然不能修改!

       2.3  在這里,我們提出一個問題:如果,在主調函數申請內存,二級指針傳遞地址(無論是變量地址還是堆或者棧的地址,甚至是程序數據區變量、常量地址)條件下,會發生什么那?也許,這將是我們下一篇隨筆的命題!

 

3、被調函數申請內存,同級指針傳遞地址

     3.1  被調函數申請內存,同級指針傳遞變量地址,這種情況不存在。或者說我不知道如何用C語言來就這種情況編程。

     3.2  被調函數申請內存,同級指針傳遞字符串地址

 1 #define _CRT_SECURE_NO_WARNINGS
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <string.h>
 5 
 6 void getString01(char* pp)  //傳遞數組地址
 7 {
 8     char sTring[] = "Hello,world!";
 9     printf("字符串數組地址是:%p \n", sTring);
10     pp = sTring;
11 }
12 void test01()
13 {
14     char* p = NULL;
15     getString01(p);
16     printf("返回數組地址得到: %p, p=%s \n\n", p, p);
17 }
18 
19 void getString02(char* pp)  //傳遞指針地址
20 {
21     char* pOint = "Hello,Kitty!";
22     printf("字符串指針地址是:%p \n", pOint);
23     pp = pOint;
24 }
25 void test02()
26 {
27     char* p = NULL;
28     getString02(p);
29     printf("返回指針地址得到:%p, p= %s \n\n", p, p);
30 }
31 
32 void getString03(char* pp)  //傳遞堆地址
33 {
34     char* hEap = malloc(20 * sizeof(char));
35     if (hEap == NULL) return;
36     memset(hEap, 0, 20 * sizeof(char));
37     strcpy(hEap, "Hello,Miss!");
38     pp = hEap;
39     printf("堆地址是:        %p \n", pp);
40 }
41 void test03()
42 {
43     char* p = NULL;
44     getString03(p);
45     printf("返回堆地址得到:  %p, p=%s \n", p, p);
46 }
47 int main(void)
48 {
49     test01();  //調用函數,得到輸出:“傳遞同級指針得:(null)”
50     test02();
51     test03();
52     system("pause");
53     return EXIT_SUCCESS;
54 }

運行上面例程,結論是: 被調函數無論是在堆上,還是在棧上,還是以指針形式在程序數據區申請內存,其對形參的定義都無法傳遞給實參。

     3.3  被調函數申請內存,二級指針傳遞字符串地址

 1 #define _CRT_SECURE_NO_WARNINGS
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <string.h>
 5 
 6 void getString01(char** pp)  //傳遞數組地址
 7 {
 8     char sTring[] = "Hello,world!";
 9     printf("字符串數組地址是:%p \n", sTring);
10     *pp = sTring;
11 }
12 void test01()
13 {
14     char* p = NULL;
15     getString01(&p);
16     printf("返回數組地址得到: %p, p=%s \n\n", p, p);
17 }
18 
19 void getString02(char** pp)  //傳遞指針地址
20 {
21     char* pOint = "Hello,Kitty!";
22     printf("字符串指針地址是:%p \n", pOint);
23     *pp = pOint;
24 }
25 void test02()
26 {
27     char* p = NULL;
28     getString02(&p);
29     printf("返回指針地址得到:%p, p= %s \n\n", p, p);
30 }
31 
32 void getString03(char** pp)  //傳遞堆地址
33 {
34     char* hEap = malloc(20 * sizeof(char));
35     if (hEap == NULL) return;
36     memset(hEap, 0, 20 * sizeof(char));
37     strcpy(hEap, "Hello,Miss!");
38     *pp = hEap;
39     printf("堆地址是:        %p \n", pp);
40 }
41 void test03()
42 {
43     char* p = NULL;
44     getString03(&p);
45     printf("返回堆地址得到:  %p, p=%s \n", p, p);
46 }
47 int main(void)
48 {
49     test01();  //調用函數,得到輸出:“傳遞同級指針得:(null)”
50     test02();
51     test03();
52     system("pause");
53     return EXIT_SUCCESS;
54 }

運行上面例程,結論是: 被調函數在堆上,或者以指針形式在程序數據區申請內存,其對形參的定義都可以傳遞給實參。在棧上定義的字符串數組,由於棧上變量的生命周期的原因,無法正確傳遞給實參。

 


免責聲明!

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



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