记录2:c语言函数的使用

c语言函数的使用


函数的概述

  • 一堆代码的集合,用一个标签描述它;标签 -> 函数名
    • 函数具备3要素,在定义函数时,必须将3要素告知编译器
      1. 函数名
      2. 输入参数
      3. 返回值
    • 如何用指针保存函数
      • int fun(int , int , char )
        int (*p)(int , int ,char )
      • 例如:
        #include <stdio.h>
        int main(void)
        {
          int (*p)(const char * ,);
          printf("Hello world!");
          p = printf;
          p("+++++++");
          return 0;
        }
      
    • 定义函数,调用函数
         int fun(int a,char b){
      
         }
         int main(void)
         {
             fun(10,2);
             return 0;
         }
      

函数的参数

基本功能:承上启下

基本实现方式:

  调用子函数:

    函数名 (要传递的数据); //实参

  被调用的子函数:

    函数的返回值 函数名 (要接受的数据) //形参

     {

     ……


     }

实参 传递-> 形参 传递的形式是 拷贝

 如:

#include <stdio.h>

void myfun(int buf)
{
  buf = buf + 10;
  printf("函数执行值为:%d\n",buf);//30
}

int main(void)
{
  int a = 20;
  myfun(a);
  printf("执行后值为:%d\n",a);//20
  return 0;
}

1. 值传递

  如实现两数交换

#include <stdio.h>

void myswap(int a,int b);
int main(void)
{
	int a = 20;
	int b = 30;
    printf("Before myswap the a is %d,the b is %d\n",a,b);//20 30
	myswap(a,b);
	printf("The a is %d,the b is %d\n",a,b);//20 30
}

void myswap(int a,int b)
{
	a = a^b;
	b = a^b;
	a = a^b;
	printf("子函数内 a: %d ,b: %d\n",a,b);// 30 20
}

形参是实参的拷贝,值传递只交换了备份的值,并没有实现原值的交换。

即值传递,在子函数中无论对形参做了多么复杂的运算,都不会改变原值;可以保护调用者自己空间的值不被修改。

2. 地址传递

  如两数交换

#include <stdio.h>

void myswap(int *a,int *b);
int main(void)
{
	int a = 20;
	int b = 30;
    printf("Before myswap the a is %d,the b is %d\n",a,b);//20 30
	myswap(&a,&b);
	printf("The a is %d,the b is %d\n",a,b);//30 20
}

void myswap(int *a,int *b)
{
	*a = *a^*b;
	*b = *a^*b;
	*a = *a^*b;
}

地址传递将原值的地址传给子函数,可以对地址中的值进行修改,从而实现原值的交换。

地址传递可以让子函数修改调用者自己空间内的值;
连续空间的传递采用地址传递,节约内存空间

3. 连续空间的传递

  • 数组
    • 数组名

      int a[10];

      实参:fun(a); 形参: void fun(int *p)
      数组传递用地址传递的方式 形参: void fun(int p[10]) 此处的p[10]实际上还是说地址,依然当指针看待

  • 结构体
    • 结构体变量

      struct abc{int a; int b; int c}

      struct buf;

      值传递

      实参: fun(buf);
      形参: void fun(struct abc a1)

      这种方式,要拷贝一个结构体,消耗内存较大

      地址传递

      实参: fun(&buf); 形参: void fun(struct abc *a2)

      这种方式不用再拷贝一个结构体,消耗内存较小,节约空间

在连续空间中要注意连续空间的读写性,如果只读用修饰型关键字 const 修饰 指针
如: int printf(const chat *format,…); int sprintf(char *str,const char *format,…);



  • 空间两大要素:空间首地址、结束标志

    根据结束标志的不同分为两类:字符空间、非字符空间

    • 字符空间   结束标志:’\0’

      如:字符长度函数
    int strlen(const char *p)
    {
      int i = 0;
      //if(p == NULL);
      while(p[i]){
        i++;
      }
      return i;
    }
    int main(void)
    {
      int len =0;
      len = strlen("Hello world!");
      printf("长度:%d\n",len);
      return 0;
    }
    
    

    注: 在使用strcpy()函数时,可能出现内存泄漏,可使用strncpy()来防止此情况出现;从效率角度来说,对于strlen、strcpy等具体的实现可根据cpu使用汇编来实现

    • 非字符空间   结束标志:数量(一般为 字节B)
      • 为了处理更多的非字符空间 形参一般用 void *p

        如 memcpy(),void *memcpy(void *dest,const void *src,int n)

        void *p的使用:
        int fun(void *p,int len)
        {
          unsigned char *tmp = (unsigned char *)p;
          for(int i = 0;i < len;i++){
            ...
          }
          return ...
        }
        

可认为 char *p | const char *p 为字符空间标识;void *p 为非字符空间、数据空间标识

函数的返回值

承上启下功能的一种形式,地址传递也起到启下的作用

  1. 基本语法

    返回类型 函数名称 (输入列表)

    {

     return 表达式

    }

    调用者与被调用者的返回值传递方式:拷贝
  2. 返回类型
    • 基本数据类型
      • 一般为 int、char等等,还包括结构体,但如果直接返回结构体,冗余度高,一般使用指针实现

        fun()main()
        int fun1(void)int a=0;
        a=fun1();
        void fun2(int *p)int a=0;
        fun2(&a);
        int *fun1(void)int *p;
        p=fun1();
        void fun2(int **p)int *p;
        fun2(&p);
    • 空间类型(指针)—— 指针作为空间返回的唯一数据类型
      • 要保证指针指向合法性
        #include <stdio.h>
        
        char *fun(void)
        {
          char a[] = "Hello world!";
          return a; 
        }
        int main()
        {
          char *p;
          p = fun();
          printf("the p is %s\n",p);//此时p指向的a[]在函数执行后被销毁,p指向了未知的东西
          return 0;
        }
        

        必须要保证函数返回的地址所指向的空间合法(不是局部变量)

        上面的程序中的子函数可以改为

        方式1:

        char *fun(void)
        {
          return "Hello world!";
        }
        

        或者

        方式2:

        char *fun(void)
        {
          static char a[] = "Hello world!";
          return a;
        }
        
      • 返回空间在函数内部的实现方式
        1. 只读区 —— 如上子函数修改 方式1
        2. 静态区 —— 如上子函数修改 方式2
        3. 堆区 malloc() free()
        #include <stdio.h>
        #include <sring.h>
        #include <stdlib.h>
        
        char *fun(void)
        {
          char *a = (char *)malloc(100);
          strcpy(a,"Hello world!");
          return a;
        }
        int main(void)
        {
          char *p
          p = fun();
          printf("the p is %s\n",p);
          free(p);
          return 0;
        }
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值