C语言函数

C语言包含两部分:c语法和c标准库,除了标准库里的函数可以用以外,还可以自定义函数

1. C标准库及库函数

1.1. 库函数使用示例

1.1.1. 随机函数

生成某一范围内的随机数,srand和rand配合使用产生伪随机数序列。
rand函数在产生随机数前,需要系统提供的生成伪随机数序列的种子,rand根据这个种子的值产生随机数。如果种子没有变化,每次调用rand函数生成的伪随机数序列都是一样的。

  1. rand:
    1. 声明:int rand(void),产生一组[0, RAND_MAX]的伪随机数,
    2. 返回值:int,所在的声明文件:stdlib.h
  2. srand:
    1. 声明:void srand(unsigned int seed),初始化随机数生成器;参数unsigned int,伪随机数生成算法使用的整数值作为种子
    2. 返回值:void,所在的声明文件:stdlib.h
#include <stdlib.h>
#include <time.h>

// RAND_MAX = 0x7fff // 01111111 11111111 32767 short
int main(void)
{
  srand(time(NULL)); // 使用当前时间作为种子,使得每次运行程序时生成的随机数序列不同。
  for (int i = 0; i < 10; i++)
  {
    printf("%d\t", rand() % 100); // 58      73      18      16      39      12      87      73      91      70. 100以内生成10个随机数
  }
  return 0;
}

1.1.2. 获取时间函数

localtime:

  1. 声明:struct tm * localtime(const time_t * timer),将 time_t 转换为本地时间的 tm 结构,参数:time_t*
  2. 返回值:struct tm*返回从1990.1.1 00:00:00累计的秒数,所在的声明文件:stdlib.h
int main()
{
  time_t rawtime;
  rawtime = time(NULL);
  struct tm *timeinfo;
  timeinfo = localtime(&rawtime);
  printf("year: %d\n", timeinfo->tm_year + 1900);
  printf("month: %d\n", timeinfo->tm_mon + 1);
  printf("day: %d\n", timeinfo->tm_mday);
  printf("hour: %d\n", timeinfo->tm_hour);
  printf("minute: %d\n", timeinfo->tm_min);
  printf("second: %d\n", timeinfo->tm_sec);
  return 0;
}

1.2. 常用库函数

  1. double sqrt(double x):计算x的平方根
  2. double pow(double x, double y):计算x的y次幂
  3. double cell(double x):向上取整
  4. double floor(double x):向下取整
  5. int toupper(int x):将x转大写
  6. int tolower(int x):将x转小写
  7. int rand(void):产生一个随机数
  8. void srand(unsigned int seedS):产生一个随机数种子
int main()
{
  double data = 9.0;
  double root = sqrt(data); 
  printf("%lf\n", root); // 3.000000
  double power = pow(data, 2);
  printf("%lf\n", power); // 81.000000
  printf("%f\n", ceil(3.14)); // 4.000000
  printf("%f\n", floor(3.14)); // 3.000000

  for (char ch = 'a'; ch < 'z'; ch++)
  {
    putchar(toupper(ch)); // ABCDEFGHIJKLMNOPQRSTUVWXY
    // putchar(ch - 32);
  }
  printf("\n");
  for (char i = 'A'; i < 'Z'; i++)
  {
    putchar(tolower(i)); // abcdefghijklmnopqrstuvwxy
    // putchar(i + 32);
  }
  return 0;
}

2. 自定义函数

自顶向下,逐步细化在这里插入图片描述
最上面的main代表了一个函数,下面的abcdefghig都是一个个函数

2.1. 语法格式

自定义函数必须满足以下格式
在这里插入图片描述

2.2. 调用方法

2.2.1. 先声明后使用

double myMax(double x, double y)
{
  double m;
  m = x > y ? x : y;
  return m;
}

int main()
{
  double a = 5.6;
  double b = 7.8;
  double maxDouble = myMax(a, b);
  printf("两者中的最大值为:%f\n", maxDouble);
  return 0;
}

2.2.2. 前向声明

若是定义在前,调用在后,则正常。如果定义在后,调用在前,编译器会complain

// 入参中如果没有参数,可以使用void表示无入参。通常省略
// int *func(void); // int *func();
// 如果没有返回值,即返回类型是void,void不可省略;若省略,系统会默认返回int
// void func2();

// 进程空间
// 函数在被调用之前,其内所有的变量尚未开辟空间。空间的开辟始于函数调用
// 空间的开辟起始于函数调用,空间消失结束于函数调用完毕
// 传值
// void func(int a);
void func(int a);
int main()
{
  int a = 10;
  // 通过传值的方式,达不到修改变量a的内容的目的,但是地址对于不同的作用域来说,是开放的
  func(a);
  printf("main a = %d\n", a); // main a = 10
  return 0;
}
void func(int a)
{
  a++;
  printf("func a = %d\n", a); // func a = 11
}

3. 传值与传址

传值与传址,本质上都是传递一个数值
传递地址,可能改变地址所对应的原数值,因为地址对于不同作用域的函数来讲是公开的。

void mySwap(int *pa, int *pb);
int main()
{
  int a = 3, b = 5;
  printf("&a = %#x, &b = %#x\n", &a, &b); // &a = 0x6b513358, &b = 0x6b513354
  printf("a = %d, b = %d\n", a, b);       // a = 3, b = 5
  mySwap(&a, &b);
  printf("a = %d, b = %d\n", a, b); // a = 5, b = 3
  return 0;
}
void mySwap(int *pa, int *pb)
{
  int temp = *pa;
  *pa = *pb;
  *pb = temp;
}

在这里插入图片描述

4. 函数调用

4.1. 实参与形参

4.1.1.形参

在定义或声明函数中指定的形参,在未出现函数调用时没,不占内存中的存储单元。只有在发生函数调用时,形参才被分配内存空间。在调用结束时,行参所占的内存单元也被释放

4.1.2. 实参

实参可以是常量、变量或表达式,但要求他们有确定的值,在调用时将实参的值赋给行参

4.2. 普通调用

函数间可以互相调用的,常见的有平行调用和嵌套调用

void foo(); // 前向声明
void func() 
{
	printf("void func()\n");
	foo(); // 嵌套调用
}
void foo() 
{
	printf("void foo()\n");
}
int main() 
{
	foo();
	return 0;
}

5. 函数递归

5.1. 递归定义

函数自身调用自身,或是间接调用自身

5.1.1. 猴子吃桃子问题

猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘了多少?
在这里插入图片描述

int peachCount(int day) 
{
	if(day == 10) 
		return 1;
	else
		return (peachCount(++day)+1)*2;
}

5.2. 递归小结

5.2.1. 书写结构

递归返回 func(递归条件)
{
	if(递归终止条件)
		终止处理;
	else
		func(趋于递归终结的条件);
}

5.3. 递归与循环论述

递归和循环的共同点:有起点和终点,重复做同样的事情,所以很多时候,两者可以相互转换。
递归内存消耗大,容易导致栈溢出,所以能用迭代解决的问题,不要用递归来完成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Qi妙代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值