22.1.18函数

函数是什么?

函数是子程序

(独立模块,由一条或多条语句组成)

一般会有输入参数和返回值,提供对过程的封装和细节的隐藏,这些代码通常被集成为软件库。

C语言:

  1. 库函数
  2. 自定义函数

库函数

常用、基础

早期C语言没有库函数

把一些常用的功能实现成函数,集成为库,由C语言直接提供

扫描二维码关注公众号,回复: 14262458 查看本文章

C语言标准,就可以直接规定库函数标准

例如:

int strlen(const char* str)

功能:求str指向字符串的长度

C语言常用库函数:

  1. IO函数
  2. 字符串操作函数
  3. 内存操作函数
  4. 时间/日期函数
  5. 数学函数
  6. 其他库函数

strcpy

#include <stdio.h>
#include <string.h>

int mian()
{
    char arr1[] = "abcdef";//a b c d e f \0
    char arr2[20] = { 0 };
    //char arr2[20] ="xxxxxxxxxx";//会把\0也拷贝过去
    
    //把arr1中的abcdef拷贝到arr2中
    strcpy(arr2,arr1);
    
    printf("%s\n",arr2);
    
    return 0;
}

memset

memory set 内存设置

  1. 设置字节的时候以字节为单位
  2. 每个字节的内容是一样value

sizeof返回的值的类型是size_t

size_t unsigned int


int main()
{
    char arr[] = "hello bit";
    //把arr中的hello改为五个x
    memset(arr,'x',5);
    
    //如果要改后面的bit
   // memset(arr+6,'x',3)
   
    printf("%s\n",arr);//xxxxx bit
    return 0;
}

自定义函数

函数 输入参数 返回值

函数的组成:

ret_type fun_name(para1,*)
{
        statement;//语句项
}

ret_type 返回类型

fun_name 函数名

para1 函数参数

写一个函数找出两个整数中的最大值

int get_max(int x, int y)
{
    /*
    if(x>y)
    return x;
    else
    return y;
    */
    return(x>y?x:y);
}


int main()
{
    int a = 0;
    int b = 0;
    scanf("%d %d",&a,&b);
    //使用函数求a,b中的最大值
    //max
    int m = get_max(a,b);
    printf("%d",m);
    
    return 0;
}

写一个函数可以交换两个整形变量的内容

//程序有bug,xy独立x,y的改变不影响a,b
//当实参传给形参的时候,形参是实参的一份临时拷贝,对形参的修改不会影响实参

//形参
void swap(int x,int y)
{
    int tmp = 0;
    tmp = x;
    x = y;
    y = tmp;
}

int main()
{
    int a = 0;
    int b = 0;
    scanf("%d %d",&a,&b);
    printf("交换前:a=%d,b=%d\n",a,b);
    //实参
    swap(a,b);
    printf("交换后:a=%d,b=%d\n",a,b);
    
    return 0;
}
//通过指针使两个函数进行连接
void swap(int x, int y)
{
    int tmp = 0;
    tmp = x;
    x = y;
    y = tmp;
}

void swap2(int* pa, int* pb)
{
    int tmp = *pa;
    *pa = *pb;
    *pb = tmp;
}

int main()
{
    int a = 0;
    int b = 0;
    scanf("%d %d", &a, &b);
    printf("交换前:a=%d,b=%d\n", a, b);
    //实参
   // swap1(a, b);
    swap2(&a, &b);
    //int* p1 = &a;
    //int* p2 = &b;
    //swap(p1,p2);
    printf("交换后:a=%d,b=%d\n", a, b);

    return 0;
}

int main()
{
    int a = 10;
    int* pa = &a;
    *pa=20;
    printf("%d\n",a);//a
    return 0;
}

函数参数

实际参数(实参)

真实传递给函数的参数

可以是常量,变量,表达式,函数等等,但在函数调用时必须是确定的值

形式参数(形参)

函数名后定义括号中的变量,只有在调用函数的时候才会占内存空间(实例化)

被调用的时候创建,后自动销毁

在调用函数传指针,形参需要和实参联系,需要改变实参具体的值

传地址功能更强大

函数的调用(实际都是传值)

传值调用:

函数的形参和实参分别占用不同内存块 对形参的修改不会影响实参

传址调用

把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式

使形参与实参建立真正联系,函数内部可以直接作为函数外部变量

判断一个数是否为素数

/判断一个数是否为素数
//is_prime(i)
//返回1是素数
//返回0不是素数

#include <math.h>

int is_prime(int n)
{
	//2~n-1试除
	//2~sqrt(n)试除  n的平方根
	int j = 0;
	for (j = 2; j <= sqrt(n); j++)
	{
		if (n % j == 0)//可以整除就不是素数
		{
			return 0;
		}
	}
	return 1;
}


int main()
{

	//打印100~200之前的素数
	int i = 0;
	for (i = 100; i <= 200; i++)
	{
		//判断i
		if (is_prime(i) == 1)
		{
			printf("%d ", i);
		}
	}
	return 0;

}

先写函数怎么使用---测试

TDD test driven development 测试驱动开发

写一个函数判断一年是否为闰年



int is_leap_year(int y)
{
	if(((y%4==0) && (y%100!=0))||(y%400==0)))
		return 1;
	else
		return 0;
	//return ((y%4==0) && (y%100!=0))||(y%400==0);
}

int main()
{
	//1000-2000年的闰年
	int y = 0;
	for (y = 1000; y <= 2000; y++)
	{
		//判断
		if (is_leap_year(y) == 1)
		{
			printf("%d ", y);
		}
	}

	return 0;
}

实现一个整形有序数组的二分查找

//找到返回下标
//找不到返回-1

int binary_search(int arr[],int k,int sz)
{
	int left = 0;
	int right = sz - 1;

	while (left <= right)
	{
		int mid = left + (right - left) / 2;
			if (arr[mid] < k)
			{
				left = mid + 1;
			}
			else if (arr[mid] > k)
			{
				right = mid - 1;

			}
			else
			{
				return mid;
			}
	}
	return -1;
}

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int k = 0;
	scanf("%d", &k);//要查找的元素
	int sz = sizeof(arr) / sizeof(arr[0]);//数组中元素个数
	int ret = binary_search(arr, k,sz);
	if (-1 == ret)
	{
		printf("找不到\n");

	}
	else
	{
		printf("找到了,下标为:%d\n", ret);
	}
	return 0;
}

数组在传参的时候,传过去的不是整个数组,传递的是数组首元素的地址

写一个函数,每调用一次这个函数,就会将num的值增加1

void test(int* p)
{
	*p = *p + 1;
	//(*p)++;
}

int main()
{
	int num = 0;
	
	test(&num);
	printf("%d\n", num);
	test(&num);
	printf("%d\n", num);
	test(&num);
	printf("%d\n", num);
	test(&num);
	printf("%d\n", num);
	return 0;
}

函数的嵌套调用和链式访问

嵌套调用

注意:不可嵌套定义!

链式访问

把一个函数的返回值作为另一个函数的参数

int main()
{
    //int len = strlen("abcdef");
    //printf("len = %d\n",len);
    
    printf("len = %d\n", strlen("abcdef"));
    return 0;
}

函数的声明和定义

test.c                        test.exe

            编译 链接

声明

在函数使用之前,先声明后使用

定义

指函数的具体实现,交代函数的功能实现

#include <stdio.h>

//函数的声明
//形参的名字可以省略·
int Add(int x, int y);
//int Add(int ,int);

int main()
{
     int a=10;
     int b=20;
     int sum = Add(a,b);//函数的实现
     printf("%d\n",sum);
     return 0;
}

//函数定义
int Add(int x, int y)
{
    return x+y;
}

//这是教科书式写法

企业写法:

提取出来成为一个模块

头文件,源文件拆开

add.h          函数声明 

add.c           函数定义

test.c            #include "add.h"(包含头文件 )

   

不想暴露函数的实现(不愿意暴露代码):编译静态库 生成一个add.lib

解决方案资源管理器→右击项目名称→属性→常规→配置类型→将应用程序.exe改为静态库.lib

如何使用: 

导入静态库 ,先导入现有项

在test.c 中写:

#include "add.h"

#pragma comment(lib, "add.lib")

函数递归

什么是递归?(大化小)

1.程序调用自身的编程技巧

2.在定义或说明中,直接或间接自己调用自己

3.大大减少代码量

int main()
{
    printf("hehe\n");
    main();
    return 0;
}
//死循环打印hehe后面栈溢出,程序结束

stack overflow栈溢出

输入1234 打印1 2 3 4

void print(int n)
{
    if (n>9)
    {
        print(n/10);//结果不断赋给n
    }
    printf("%d ",n%10);
}

int main()
{
    unsigned int num = 0;
    scanf("%d",&num);
    print(num);
}

递推 先执行if 4 3 2 1

回归 返回执行printf 1 2 3 4

print(1234)

print(123) 4

print(12) 3 4

print(1)2 3 4

这几个数字先被存放在栈区,当结束if循环时n=1所以先打印出1

递归必要条件:

  1. 存在限制条件,当满足这个限制条件,递归便不再继续(跳出条件)
  2. 每次递归调用后越来越接近这个限制条件

编写函数不允许创建临时变量,求字符串长度

#include<string.h>
#include<stdio.h>

int my_strlen(char* str)
{
	if (*str != '\0')
		return 1 + my_strlen(str + 1);
	else
		return 0;
}

int main()
	{
		char arr[] = "abcd";
        int len = my_strlen(arr);
        printf("%d\n", len);

        return 0;
	}

a b c d \0

my_strlen("abcd")

1+my_strlen("bcd")

1+1+my_strlen("cd")

1+1+1+my_strlen("d")

1+1+1+1+my_strlen("\0")

1+1+1+1+0=4

递归和迭代

求n的阶乘(不考虑溢出)

             n<=1, fac(n)=1

            n>1, fac(n)=n*fac(n-1)

//求n的阶乘,不考虑溢出
//迭代就是循环

int fac1(int n)
{
	if (n <= 1)
		return 1;
	else
		return n * fac(n - 1);
}

int fac(int n)
{
	int i = 0;
	int ret = 1;
	for (i = 1; i <= n; i++)
	{
		ret = ret * i;

	}
	return ret;
}

int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = fac(n);
	printf("%d\n", ret);

	return 0;
}

求第n个斐波那契数

1 1 2 3 5 8 13 21 34 55......

前两个数相加等于后面一个数

n<=2,fib(n)= 1

n>2, fib(n)=fib(n-1)+fib(n-2)

//int fib(int n)
//{
//	if (n <= 2)
//		return 1;
//	else
//		return fib(n - 1) + fib(n - 2);
//}

int fib(int n)
{
	int a = 1;
	int b = 1;
	int c = 1;

	while (n > 2)
	{
		c = a + b;
		a = b;
		b = c;
		n--;
	}

	return c;
}

int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = fib(n);
	printf("%d\n", ret);

	return 0;
}

猜你喜欢

转载自blog.csdn.net/Ll_R_lL/article/details/122559131