学习日记·C语言学习-函数

目录

一函数的基础知识

二传值和传地址

三传地址

四函数的传出传入参数

五命令行参数(主函数参数)

六使用注意事项

七函数指针

八函数指针数组及指针复杂声明

九复杂指针的声明

十可变参数


1、函数基础语法(函数定义、调用、声明)

2、函数的使用注意事项(传值、返回值)

一函数的基础知识

#include <stdio.h>
int add(int a,int b);//函数的声明
//函数放在主函数的前面
int add(int a,int b)
{
    return a+b;
}
int main(int argc, char const *argv[])
{
    /**
     * 函数基础语法:
     * 1、函数三要素:调用、函数定义、声明
     * 2、函数的使用注意事项:传值、返回值
     * 3、企业级函数(复用性、维护性、扩展性)--华为编码
     */
    /**
     * 1、函数三要素:函数名、函数形参、函数返回值
     * 函数名:命名体现自注释,提高代码的可读性 :动词_名词(不要用拼音)
     * 函数的形参:传什么类型,就要用什么类型的变量来接;(a ==元素指针,aa ==int(*a)[]  aaa = int (*aa)[][])
     * 函数的返回值:return 0;结束当前函数;exit(1);结束整个函数
     * 2、函数的使用形式:函数的声明(在调用函数前需声明函数)、函数的定义、函数调用
     * 函数定义:函数名、函数的返回值、形参的类型及变量名
     * 函数调用:函数名、实参的变量名或者实参的地址
     * 函数声明:函数名、函数返回值、形参的类型(变量名可以不提供);不分配内存空间
     * */
    int sum = add(5,6);//函数调用
    printf("sum = %d\n",sum);
    return 0;
}

二传值和传地址

传值

#include <stdio.h>    
#include "swap_int.h"                                                                                          
    /**
     * 函数的注意事项:
     * 1、函数的传参:
     * 传值 VS 传地址
     * */
    int main(int argc, char const *argv[])
    {
        int a=5,b=6;
        printf("left= %d,right = %d\n",a,b);                                 
        void swap_int(a,b);
        printf("left= %d,right = %d\n",a,b);
        return 0;
    }

 

 

根据图解,没有调用到

传指针的时候,不要以为就是在传地址

三传地址

判断:修改指针变量对应内存空间的值(传指针变量的地址) ,还是要修改指针变量指向内存空间的值(传指针变量名)

#include <stdio.h>
void func(char **ptr)//这里就是在传递对应的地址
{
    (*ptr)++;//从地址调取,从而改变值
}
//void func(char *ptr)
// //实际上只是在传递ptr的值而不是地址,形参是不可以改变的
// {
//     ptr++;
//     *ptr = 'E';
// }
int main()
{
    char c[100] = "hello";
    char *ptr ;
    ptr = c;
    //传指针的时候,不要以为就是在传地址
    //判断:修改指针变量对应内存空间的值(传指针变量的地址)
    //     ,还是要修改指针变量指向内存空间的值(传指针变量名)
​
    // func(&ptr);
    func(c);
​
    printf("ptr = %s\n",ptr);
​
    return 0;
}

面试题

主要注意函数调用地址的方法

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//void get_men(char *ptr)//这里并没有将指针地址传递过去
//方法1
void get_men(char **ptr)
{
    *ptr = (char *)malloc(sizeof(char) * 100);//动态分配空间
}
//方法2
char * get_men2(char *ptr)//字符指针型,返回的是地址
{
    ptr = (char *)malloc(sizeof(char) * 100);
​
    if(ptr == NULL)//是否分配成功
    {
        printf("malloc error!\n");
        exit(1);//结束所有程序
    }
​
    return ptr;
}
int main(int argc, char const *argv[])
{
    char *ptr;//ptr对应的内存空间
    char *ptr1;
    //get_men(ptr);//传实参变量名(只能使用不用修改) ptr野指针
    get_men(&ptr);
    ptr1=get_men2(ptr1);//返回值必须有人接着
​
    memset(ptr,0,sizeof(char) * 100);//清除脏数据
​
    strcpy(ptr,"hello world");
​
    printf("ptr =%s\n",ptr);
​
    strcpy(ptr1,"hello world");
​
    printf("ptr1 =%s\n",ptr1);
​
    return 0;
}

四函数的传出传入参数

传入参数:实际上就是只传递给函数但是不修改的实参

传出参数:传递给函数修改的实参(相当函数的返回值)

函数如果返回多个值?

利用传出参数

#include <stdio.h>
int func(char *ptr)
{
    *ptr = 'a';//实参op
    return 5;
}
int main(int argc, char const *argv[])
{
    char op;
    int result = func(&op);//op为传出参数
    //op=='a'  result == 5;
    return 0;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int continue_max_str(char *dest,char *src)//传入参数
{
    int len = 0;
    int max_len = 0;
    while(*src !='\0')
    {
        while((*src >= '0' && *src <= '9') && *src != '\0')
        {
            len++;
           
            src++;
        }
        if(len>max_len)
        {
             strncpy(dest,src-len,len);
            //  char *strncpy(char *dest, const char *src,              //  size_t n) 
            //  把 src 所指向的字符串复制到 dest,最多复制 n 个字             //  符。
            //  当 src 的长度小于 n 时,dest 的剩余部分将用空字节填            //  充。
            *(dest + len) = '\0';
            max_len =len;
        }
        len = 0;
​
        src++;
    }
    return max_len;
}
​
int main(int argc, char const *argv[])
{
    //char *src;//此时空间地址不够,必须要动态分配
    char *src = (char *)malloc(sizeof(char)*100);
    char *dest = (char *)malloc(sizeof(char)*100);
    printf("Please input src:\n");
    scanf("%s",src);
​
    printf("src = %s\n",src);
​
    //int max_len=continue_max_str(src);//只返回长度没有返回值
    int max_len=continue_max_str(dest,src);
​
    printf("the max len = %d\n",max_len);
    printf("the max str = %s\n",dest);
    return 0;
}

五命令行参数(主函数参数)

#include <stdio.h>
int main(int argc, char *argv[])//char **argv是一样的
{
    //argc:命令行参数的个数
    //argv:参数都保存在指针数组里面
    printf("argc = %d\n",argc);
    //将命令本身传递进去所以为1
    for (int i = 0; i < argc; i++)
    {
        printf("argv[%d] = %s\n",i,argv[i]);
        //保存的就是命令本身
    }
    return 0;
}

六使用注意事项

函数的返回值:不能返回局部变量的地址

如何返回多个值--结构体、传出参数

#include <stdio.h>
char * func3()
{
    char src[100] = "hello world";
    return src;//不能返回局部变量的地址,因为空间会释放
}
int * func4()
{
    static int num = 6;
    //使用static可以延长它的生命周期,至结束后释放
    return &num;
}
int main(int argc, char const *argv[])
{
    char * tmp = func3();
​
    printf("tmp = %s\n",tmp);
​
    int * p = func4();//p指向的空间已经被释放,所以无效
​
    printf("tmp = %d\n",*p);
     
    return 0;
    //代表函数正常退出
    //如果没有return 0;系统会挨个判断耽误时间
}                                                                                                            
               

七函数指针

#include <stdio.h>
int add(int a,int b)
{
    return a+b;
}
​
int test(int (*p_func)(int,int),int a,int b)//p_func:指向的函数称之为回调函数
{
    return p_func(a,b);
}
​
int main(int argc, char const *argv[])
{
    //函数指针变量:变量,保存地址,地址是函数的地址(函数的入口地址)
    //函数名:指针,保存函数地址(函数入口地址)
    //什么时候使用函数指针?做形参;
    //函数指针功能应用作用:1、隐藏调用接口和调用形式 2、间接体现多态,提高代码的扩展性;
​
    int sum = add(5,6);
​
    int (*p_func)(int,int);//p_func:函数指针变量,指向函数地址,里面有两个int类型的形参
​
    printf("sizeof(p_func) = %ld\n",sizeof(p_func));//函数指针在64位是8个字节,函数指针终究是指针
​
    p_func = add;//传地址
    //p_func = &add;//函数名找地址(编译也不会出错)
​
    printf("%d\n",p_func(5,6));
    //printf("%d\n",(*p_func)(5,6));//不涉及到步长
​
    test(add,5,6);
​
    return 0;
}
#include <stdio.h>
typedef int (*T)(int,int);//声明T为函数指针类型
void GetArray(int *a,int length)
{
    printf("请输入10个数字:\n");
    int i;
    for(i = 0;i<length;i++)
    {
        scanf("%d",&a[i]);
    }
}
int less (int x,int y)
{
    return x<y?1:0;
}
int greater(int x,int y)
{
    return x>y?1:0;
}
void Sort(int a[],int length,T p)//传入函数需要函数指针来接受
{
    int i,j;
    for(i = 0;i<length-1;i++)
    {
        for ( j = 0; j < length-1-i; j++)
        {
            int t = a[j];
            a[j]=a[j+1];
            a[j+1]=t;
        }
    }
}
void print(int *a,int length)
{
    int i;
    for(i = 0;i<length;i++)
    {
        printf("%d",a[i]);
    }
    printf("\n");
}
int main(int argc, char const *argv[])
{
    int a[10]={0};
    int length = sizeof(a)/sizeof(a[0]);
    GetArray(a,length);
    Sort(a,length,greater);
    print(a,length);
    return 0;
}

八函数指针数组及指针复杂声明

 

int a;
int *a;
int **a;
int a[10];
int *a[10];
int (*a)[10];
int (*a)(int);
int (*a[10])(int);

九复杂指针的声明

int *(*(*fp1)(int))[10];

 

fp1:函数指针变量,指向的函数形参int,返回值是一个指针数组,该指针指向的数组里面里的每个元素都是int *

int *(*(*arr[5])())();

arr:函数指针数组,数组里每个元素都是函数指针,指向一个形参为空,返回值为函数指针,该指针指向一个形参为空,返回值int *

float (*(*b())[])();

b:函数,形参为空,返回值为指针,指针指向一个数组,数组里的每个元素都是指针,这些指针指向函数,函数的形参为空,返回值为float

十可变参数

 

  • 可变参数的实现原理

  • 形参在栈空间上开辟空间的地址是连续的

  • 三个宏

  • void va_start(va_list arg_ptr,prev_param);//va_list可变参数的类型

  • type va_arg(va_list arg_ptr,type);

  • void va_end(va_list arg_ptr);

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值