C语言学习05

自定义函数:

有两情况适合把代码封装成自定义函数: ​ 1、代码量过多,一般代码量超过50行就要考虑封装成函数,方便管理代码,提高代码的安全性(程序员平均每50行会出现一个BUG)。 ​ 2、如果一个代码需要在不同位置多次执行,为了防止出现代码冗余,就要把它封装成函数,方便重复使用,也能降低可执行文件的大小。

函数声明:

返回值类型 函数名(参数列表);

1、根据函数的功能为函数取名字,在Linux系统下函数名全部小写,多个单词用下划线分隔。 ​ 2、参数列表,指的是函数执行时,调用者需要传递它的数据,此时重点关注的是参数的类型,在函数声明时可以忽略参数的名,如果函数执行时不需要调用者传递数据则写void。

返回值类型 函数名(类型名 形参名1,类型名 形参名2,...);
返回值类型 函数名(int n1,int n2,...);
返回值类型 函数名(void);

3、返回值类型,指的是函数的执行结果是什么类型的数据,如果函数没有返回值,则写void。 ​ 4、函数声明就是告诉编译器该函数的格式,方便编译器检查调用者的使用是否正确。

5、一般函数声明放在main函数之前

函数定义:
返回值类型 函数名(类型 参数名)
{
    // 函数体
}
// 如果函数的定义出现在调用之前,函数声明可以省略
函数调用:

函数名(实参);

1、调用者会把实参赋值给形参变量。 2、函数的返回值会放置在调用位置,可立即使用,也可用变量保存。

练习3:实现一个判断是否是素数的函数,调用它打印出100-1000之间的所有素数
#include <stdio.h>
#include <stdbool.h>
​
bool is_prime(int num);
​
int main(int argc,const char* argv[])
{
    for(int i=100; i<1000; i++)
    {
        if(is_prime(i))
            printf("%d ",i);
    }
    bool flag = is_prime(9999);                                                                         
}
​
bool is_prime(int num)
{
    for(int i=2; i<=num/2; i++)
    {
        if(0 == num%i)  return false;
    }
    return true;
}
作业2:输入两个日期yyyy-mm-dd,计算相差多少天,考虑封装函数
#include <stdio.h>                                                                                                         
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
​
//  判断闰平年
bool is_leap(uint16_t year);
//  计算日期天数函数
uint32_t date_to_days(uint16_t year,uint8_t month,uint8_t day);
​
int main(int argc,const char* argv[])
{
    uint16_t y = 0;
    uint8_t m = 0,d = 0;
    printf("请输入一个日期(yyyy-mm-dd)");
    scanf("%hu-%hhu-%hhu",&y,&m,&d);
    uint32_t day = date_to_days(y,m,d);
​
    printf("请再输入一个日期(yyyy-mm-dd)");
    scanf("%hu-%hhu-%hhu",&y,&m,&d);
    printf("间隔了%d天\n",
            abs((int)date_to_days(y,m,d)-(int)day));
}
​
//  计算日期天数函数
uint32_t date_to_days(uint16_t year,uint8_t month,uint8_t day)
{
    uint32_t sum = day;
​
    for(int y=1; y<year; y++)
    {   
        sum += 365 + is_leap(y);
    }   
    char arr[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
    arr[1] += is_leap(year);
​
    for(int m=0; m<month-1; m++)
    {
        sum += arr[m];
    }
    return sum;
}
​
//  判断闰平年
bool is_leap(uint16_t year)
{
    return 0==year%4 && 0!=year%100 || 0==year%400;
}
​

自定义函数要注意的问题:

1、函数的命名空间互相独立,函数之间传参是单向值传递(实参给形参赋值),所以两个函数之间不能通过传参共享变量。

#include <stdio.h>
int func(int num)
{
    printf("func:%d\n",num);
    num = 100;
    printf("func:%d\n",num);
    printf("func:%p\n",&num);
    return 0;
}
​
//  实现一个交换两个变量的值的函数
void swap(int n1,int n2)
{
    printf("swap:n1:%d n2:%d\n",n1,n2);
    int temp = n1;
    n1 = n2;
    n2 = temp;
    printf("swap:n1:%d n2:%d\n",n1,n2);
}
​
int main(int argc,const char* argv[])
{
    int num = 10;
    printf("main:%d\n",num);
    printf("main:%p\n",&num);
    func(num);
    printf("main:%d\n",num);
int num1 = 10,num2 = 20;
    printf("num1:%d num2:%d\n",num1,num2);
    swap(num1,num2);
    printf("num1:%d num2:%d\n",num1,num2);
}                                                                              

2、C语言中如果函数的参数列表是空的,则意味着该函数提供任意类型、多个参数都可以调用,容易给调用者造成误会,影响代码的可读性,如果函数执行时不需要调用者传递数据则参数列表要写void,不要空着。

#include <stdio.h>
​
int func(void)
{
    printf("func\n");
}
​
int main(int argc,const char* argv[])
{
    func(); 
    //func(10); 
    //func(3.14,10);    
    //func(3.14,"hehe",10);                                  
}
​

3、如果函数有返回值但没有写return语句,调用该函数时依然有返回值。 ​ 当调用一个有返回值的函数时,系统会为调用者和被调用者约定一个空间用于存储返回值,而return语句的作用就是把一个数据存储到这个空间,如果没有写return语句,调用者依然会从共用空间读取返回值,只是读取到的数据是随机的。

#include <stdio.h>
​
int func(void)
{
    //return 10;
}
​
int main(int argc,const char* argv[])
{
    int num = func();
    printf("%d\n",num);                                      
}
​

gcc -Wall -Werror xxx.c 可以防止漏写return语句。

xxx.c:x:x: error: control reaches end of non-void function [-Werror=return-type]

4、当使用数组作为函数的参数传递时,它的长度信息就丢失了,(数组会蜕变成指针),无法使用sizeof计算数组的长度,需要调用者额外提供一个参数作为数组的长度。

void show_arr(int arr[],size_t len)
{
    for(int i=0; i<len; i++)
    {   
        printf("%d ",arr[i]);
    }   
}
int main(int argc,const char* argv[])
{
    int arr[] = {1,2,3,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5};
    show_arr(arr,sizeof(arr)/sizeof(arr[0]));
}
练习4:定义一个函数,功能是对一个数组进行升序排序

5、当函数中使用数组作为参数传递是,是"址传递" ,是可以被函数所共享数组

6、当使用二维数组作为函数的参数时,C语言规则定义二维数组时必须有列数,所以要行、列数在前,数组在后,并且把列数设置给数组。

void show_arr(int row,int col,int arr[][col])
{
    for(int i=0; i<row; i++)
    {   
        for(int j=0; j<col; j++)
        {
            printf("%d ",arr[i][j]);
        }
        printf("\n");
    }   
}
​
int main(int argc,const char* argv[])
{
    int arr[2][5] = { 
        {1,2,3,4,5},
        {2,3,4,5,6}
    };  
    show_arr(2,5,arr);
    return 0;                                               
}
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值