• 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 
    ",a,b);
     9     temp=a;
    10     a=b;
    11     b=temp;
    12     printf("交换后,a=%d  b=%d 
    ",a,b);
    13 }
    14 int main()
    15 {
    16     int x=10,y=20;
    17     printf("交换前,x=%d  y=%d 
    ",x,y);
    18     swap(x,y);
    19     printf("交换后,x=%d  y=%d 
    ",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    
    ",a,b);
     9     printf("交换前,a=%d  b=%d 
    ",*a,*b);
    10     temp=*a;
    11     *a=*b;
    12     *b=temp;
    13     printf("交换后,a=%d  b=%d 
    ",*a,*b);
    14 }
    15 int main()
    16 {
    17     int x=10,y=20;
    18     printf("x地址:%p    y地址:%p
    ",&x,&y);
    19     printf("交换前,x=%d  y=%d 
    ",x,y);
    20     swap(&x,&y);
    21     printf("交换后,x=%d  y=%d 
    ",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 
    ", buf);
    10     func(buf);
    11     printf("主调函数申请内存,同级指针传递,栈上字符串返回:%s 
    ", buf);
    12 }
    13 
    14 void printString(char* str)
    15 {
    16     strcpy(str, "Hello,World!");
    17     printf("主调函数申请内存,同级指针传递,堆上字符串返回:%s 
    ", 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 
    ", p);
    26     printString(p);
    27     printf("字符串长度=%d 
    ", 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 
    ", *pp);
    10 }
    11 void test01()
    12 {
    13     char* p = "主调函数定义初始字符串";
    14     printf("%s 
    ", p);
    15     buildString(p);
    16     printf("%s 
    ", 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 
    ", sTring);
    10     pp = sTring;
    11 }
    12 void test01()
    13 {
    14     char* p = NULL;
    15     getString01(p);
    16     printf("返回数组地址得到: %p, p=%s 
    
    ", p, p);
    17 }
    18 
    19 void getString02(char* pp)  //传递指针地址
    20 {
    21     char* pOint = "Hello,Kitty!";
    22     printf("字符串指针地址是:%p 
    ", pOint);
    23     pp = pOint;
    24 }
    25 void test02()
    26 {
    27     char* p = NULL;
    28     getString02(p);
    29     printf("返回指针地址得到:%p, p= %s 
    
    ", 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 
    ", pp);
    40 }
    41 void test03()
    42 {
    43     char* p = NULL;
    44     getString03(p);
    45     printf("返回堆地址得到:  %p, p=%s 
    ", 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 
    ", sTring);
    10     *pp = sTring;
    11 }
    12 void test01()
    13 {
    14     char* p = NULL;
    15     getString01(&p);
    16     printf("返回数组地址得到: %p, p=%s 
    
    ", p, p);
    17 }
    18 
    19 void getString02(char** pp)  //传递指针地址
    20 {
    21     char* pOint = "Hello,Kitty!";
    22     printf("字符串指针地址是:%p 
    ", pOint);
    23     *pp = pOint;
    24 }
    25 void test02()
    26 {
    27     char* p = NULL;
    28     getString02(&p);
    29     printf("返回指针地址得到:%p, p= %s 
    
    ", 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 
    ", pp);
    40 }
    41 void test03()
    42 {
    43     char* p = NULL;
    44     getString03(&p);
    45     printf("返回堆地址得到:  %p, p=%s 
    ", p, p);
    46 }
    47 int main(void)
    48 {
    49     test01();  //调用函数,得到输出:“传递同级指针得:(null)”
    50     test02();
    51     test03();
    52     system("pause");
    53     return EXIT_SUCCESS;
    54 }

    运行上面例程,结论是: 被调函数在堆上,或者以指针形式在程序数据区申请内存,其对形参的定义都可以传递给实参。在栈上定义的字符串数组,由于栈上变量的生命周期的原因,无法正确传递给实参。

  • 相关阅读:
    转载的:关于matlab中princomp的使用说明
    STL容器Vector
    Ubuntu20.04下创建Pycharm桌面图标
    c++和c中const的区别
    内存性能分析\垃圾回收 文章
    jq使用教程
    iOS15适配 UITableView下移22px
    linux 内核头文件(转)
    bjfu1143 小蝌蚪安家 解题报告
    hdu 1874 畅通工程续 flody
  • 原文地址:https://www.cnblogs.com/GoldCrop/p/11065311.html
Copyright © 2020-2023  润新知