C语言函数基础知识

函数基本概念

  1. 函数:可重复使用的代码块,用于执行特定的任务或操作。
  2. 一个C程序可以由多个源文件构成,一个源文件是一个编译单位,一个源文件可以由多个函数构成,函数之间可以互相调用,函数是C程序基本的组成单位。
  3. 函数的作用:
    1. 封装功能,提高代码的结构化和复用性;
    2. 代码模块化:将程序按照功能拆分成若干模块单元,降低复杂度;
    3. 增强可维护性;
  4. 函数的分类:
    1. 库函数:标准函数,由c系统提供。使用库函数,必须包含对应的头文件。
    2. 自定义函数:解决需求自己定义的函数。

函数基本语法

函数的声明

  1. 声明函数语法
    1. 函数名:函数的名字,符合命名标识符规范。
    2. 函数体:函数中所包含的代码块。
    3. 参数:用于接收调用函数时传递进来的值。
    4. 返回值:函数执行完后,从函数传回调用点的值。返回值的类型与函数名前面的返回类型一致,没有返回值,返回类型可以用 void
#include <stdio.h>
// 定义函数|声明一个函数
// void代表空类型,说明咱们函数不需要书写return,不需要有返回值
void fun()
{
    // 书写代码片段
    // 曾经学习过的语法在函数体中都可以书写
    printf("Hello,Tom!");
    int a = 100;
    printf("%d\n", a);
}

// 小括号里面的称之为形式参数->形参,形参可以有多个,多个之间用逗号隔开
int fun1(int a)
{
    // 书写代码片段
    a += 10;
    return a;
}

// 形参可以有多个
double fun2(double a, double b, double c)
{
    double result = a + b + c;
    return result;
}

int fun3(int a, int b)
{
    return a > b ? a : b;
}

// return,一般在函数的函数体内部书写

int main()
{
    return 0;
}

// 函数的使用:第一步:先声明
//           第二步:在使用,可以复用多次

注意:函数不能嵌套声明,C程序中的所有函数都是相互独立的。

函数的调用

  1. 调用函数:函数名加上圆括号,参数写在小括号里,函数没调用一此,函数体语句执行一遍。
#include <stdio.h>

// 声明函数 实现 两整数相加
int fun(int a, int b) {
    return a + b;
}

// 主函数
int main() {
`   // 调用函数
    fun(10, 20);
    fun(30, 40);
    return 0;
}

函数的返回值

  1. 无返回值类型:函数无返回值,使用 void 表示。
  2. 有返回值类型:指明具体的类型,如int double char等。与函数体内的return搭配使用。
  3. 如果函数返回值类型不是void,但函数中没有return,则函数返回一个系统随机的垃圾值。

函数的参数

  1. 形参:定义函数时,函数名后面括号中声明的变量称为形式参数,简称形参。
  2. 实参:调用函数时,函数名后面括号中使用的常量、变量、表达式称为实际参数,简称实参。
  3. 实参的数量和形参的数量要保持一致。

主函数

  1. 主函数:程序的入口函数,程序一定要包含有且仅有一个主函数,程序是从主函数开始执行。
  2. 主函数可以调用其他函数,但是不能反过来调用,也不能调用自身。
  3. 主函数的返回值:0 表示运行成功,返回其他非0整数,表示运行失败。如果省略 return 0;编译器会自动加上。
  4. 主函数的参数:可以带有两个参数:形参——argc,表示传给程序的参数个数,最少是1;*argv[]——指针数组,数组的每个元素都是字符串。
#include <stdio.h>

int fun(int a, int b)
{

    return a + b;
}

// 主函数   5        {'a','b','c','d','e'}
// 总结:main主函数,在源文件当中没办法手动调用
// 只能通过cmd命令行完成调用与传递参数
int main(int argc, char *argv[])
{
    // 打印
    printf("argc=%d\n", argc);
    // 循环遍历数组
    for (int i = 0; i < argc; i++)
    {
        printf("%s\n", argv[i]);
    }

    return 0;
}

函数原型

  1. 函数必须先声明再使用,如果将函数声明写在主函数后面,在主函数前面给出函数原型。
  2. 函数原型:提前告诉编译器,每个函数的返回类型和参数类型。
#include <stdio.h>

// 函数原型:提前把函数声明,'相当于和编译器提前沟通好了'
// 函数原型花括号,函数体部分不用书写
int fun(int, int);
void fun1();

int main()
{
    int result = fun(10, 20);
    printf("计算的结果:%d\n", result);
    fun1();
    return 0;
}
// 底部定义函数
int fun(int a, int b)
{
    return a + b;
}

void fun1()
{
    printf("枪杆子里面出政权!\n");
    printf("打的一拳开,免得百拳来\n");
}

作用域

作用域:确定在代码中某个标识符的可见性和访问范围。

同一个作用域中不能声明同名的标识符。

全局作用域

  1. 全局作用域:在函数和代码块以外定义的变量、常量、数组等,在程序的任何地方都可以访问。
#include <stdio.h>
// 全局作用于:函数体、代码块(条件语句+循环语句)以外,全局作用域
// 全局作用域的数据可以在源文件的任意地方使用

// 全局变量:只是声明  但是没有初始化赋值--->0
// 对于全局数组,如果没有显式初始化它们,它们的元素将自动初始化为零值,字符数组,将初始化为空字符 \0。
int num; // 默认是数字零
// 全局变量
int a = 100;
double b = 6.6;
char ch = 'z';
// 全局常量
const double PI = 3.14;
// 全局数组
int arr[5] = {10, 20, 30, 40, 50};
// 函数体内部使用全局数据
void fun()
{
    printf("fun函数体内部:%d", a);
    printf("fun函数体内部:%lf", PI);
    for (int i = 0; i < 5; i++)
    {
        printf("fun函数体内部:%d\n", arr[i]);
    }
    printf("fun函数体内部使用全局变量num=%d\n", num);
}

int main()
{
    printf("全局变量:%d\n", a);
    printf("全局常量:%lf", PI);
    // 遍历全局数组
    for (int i = 0; i < 5; i++)
    {
        printf("数组:%d\n", arr[i]);
    }
    fun();
    printf("全局变量num=:%d", num);
    return 0;
}
  1. 全局变量:如果没有指定初始值,自动初始化为 0
  2. 全局数组:如果没有指点初始值,自动初始化为 0
  3. 字符数组:如果没有初始化,自动初始化为空字符 \0

局部作用域

  1. 局部作用域:在函数内定义的变量、常量、数组等。只能在该函数内部访问。函数的形参也是局部变量。
#include <stdio.h>
// 全局变量erha
int erha = 100;

// 函数的形参:a、b局部变量,只能在局部作用域中使用
int max(int a, int b)
{
    int result = a + b;
    printf("计算的结果:%d\n", result);
}

int main()
{
    // 局部作用域:创建变量、常量、数组、局部变量、局部常量、局部数组
    // 只能在当前局部作用域中使用
    // 函数的形参,也是局部局部变量
    int num = 12306;
    int arr[5] = {1, 2, 3, 4, 5};
    printf("主函数局部作用于:num=%d\n", num);
    max(10, 20);
    for (int i = 0; i < 5; i++)
    {
        printf("局部数组:%d\n", arr[i]);
    }
    return 0;
}
  1. 局部作用域中定义了与全局作用域中同名的标识符,优先使用本作用域中定义的数据。
  2. 局部变量、数组如果没有初始化,他们的初始值是机器垃圾值。

块级作用域

  1. 块级作用域:C99标准引入,在代码块(条件语句、循环语句)中定义的常量、变量、数组等,只能在该代码块中访问。代码块通常由花括号{} 结构。
#include <stdio.h>

void fun()
{
    {
        int a = 100;
        printf("娃哈哈!%d\n", a);
    }
    // printf("娃哈哈!%d\n", a); // 不能访问
}

int main()
{
    int i;
    // 块级作用域:条件语句 + 循环语句花括号----块级作用域
    if (1)
    {
        int a = 100;
        int b = 200;
        int result = a + b;
        printf("%d\n", result);
    }

    for (i = 0; i < 10; i++)
    {
        printf("%d\n", i);
    }
    printf("%d\n", i);
    fun();

    return 0;
}

作用域和内存

  1. 栈区域:局部变量、局部数组等通常存储在栈区(Stack),其生命周期受限与其定义的函数或块级作用域,当函数返回或块级作用域结束时,这些变量的内存会被自动释放。
  2. 全局静态区域:全局变量、全局数组等存储在全局静态区,这些全局的数据在程序整个生命周期内都存在,在程序结束时才被释放。

static和extern关键字

  1. static:可以声明静态变量和静态函数,控制变量和函数的作用范围和生存周期。
  2. 静态局部变量:使用static关键字修饰的局部变量,静态局部变量存储在内存中的全局静态区。
  3. 静态局部变量只在函数第一次调用时初始化并将生命周期延长到整个程序的执行期间。
  4. 静态局部变量如果声明时没有初始赋值,系统会自动初化为0
  5. 多文件编译:C编译器可以将多个源文件编译成一个可执行文件,只能通过cmd命令去编译。
  6. 静态全局变量:使用static关键字修饰的全局变量称为静态全局变量。静态全局变量仅对当前文件可见,其他文件不可访问,其他文件中可以定义与其同名的变量。
  7. extern:声明外部链接,可以引入其他源文件中定义的变量、函数等。
#include <stdio.h>
// extern 外链接,链接外部源文件,可以是多个源文件
extern int a;
extern int arr[];
extern int length;
extern void fn();
extern double b;
double b = 12.3;
int main() {


  printf("a = %d\n",a);
  for (int i = 1; i < length; i++) {
    printf("%d\n", arr[i]);
  }
  fn();
  printf("%lf\n",b);

  return 0;
}

     递归函数

  1. 递归函数:一个函数在函数体内又调用了本身,称为递归调用。递归函数需要满足的条件:
    1. 必须有一个明显的结束条件。
    2. 必须有一个趋近于结束条件的趋势。
#include <stdio.h>
// 递归函数实现斐波那契数列
// 定义函数
int fibonacci(int n) {
  // 明显的结束条件
  if (n == 1 || n == 2) {
    return 1;
  } else {
    // 趋近于结束条件的趋势
    return fibonacci(n - 1) + fibonacci(n - 2);
  }
}
int main() {
  int num;
  printf("请输入要查询斐波那契数列中数的位置:");
  scanf("%d", &num);
  int result = fibonacci(num);

  printf("%d位置斐波那契数是%d\n", num, result);

  return 0;
}

常用系统函数

字符串相关函数

与字符串相关函数,使用时必须引入对应的头文件——<string.h>

  1. strlen(str)   :返回str的长度,类型是size_t;
  2. strcpy(str1, str2):将str2的字符串复制到str1中(替换)。
  3. strcat(str1, str2) :将str2中的字符串追加到str1的后面。
#include <stdio.h>
// 引入头文件
#include <string.h>
// 字符串相关函数

int main() {
  char str[] = "Hello, world!"; // 14
  // strlen() 返回字符串的长度 类型size_t   计算时不计算 \0 的长度。
  int length = strlen(str);  // 13
  printf("str字符串的长度:%d\n", length);

  // strcpy(str1,str2) 将str2复制给str1
  char str1[] = "hello";
  char str2[] = "Wow";
  printf("str1为:%s\n", strcpy(str1, str2)); // WOw
  printf("str2为:%s\n", strcpy(str2,str1 )); // hello

  // strcat(str1, str2) 将str2 追加到 str1 的后面。
  printf("str1为:%s\n", strcat(str1, str2)); // helloWow


  return 0;
}

<stdio.h> 头文件中的函数(字符串函数):

  1. sprintf(),用于将格式化数据写入字符串,比printf多一个参数,三个参数,第一个参数是要写入的字符串。
  2. sscanf(),用于从一个字符串中按照指定的方式提取数据,比scanf多了一个参数,第一个参数是要提取的字符串。
#include <stdio.h>

int main() {
  int num = 100;
  double pay = 34.5;
  char str[100]; 
  // sprintf()  将内容写入字符串
  sprintf(str, "我有%d元,花了%lf元\n", num, pay);
  printf("%s", str); // 我有100元,花了34.500000元

  // sscanf()  从字符串中提取数据
  char str1[] = "中国队第12金来了!男双跳板龙道一王宗源夺金,446.10分折服对手!";
  int n;
  double score;
  sscanf(str1, "中国队第%d金来了!男双跳板龙道一王宗源夺金,%lf分折服对手!", &n, &score);
  printf("n = %d, score = %lf\n", n, score); // n = 12, score = 446.100000

  return 0;
}

日期相关函数

  1. time(&变量):获取当前日期值到变量中,是 time_t 类型,
  2. ctime(&时间值):将时间值转为字符串并返回,是兼职需是 time_t类型。
  3. difftime(时间值1, 时间值2) :返回两个时间值的差,返回值是double类型,时间值需是time_t类型。
  4. time_t 是c语言中用于表示时间值的数据类型,通常是一个整数类型,(int 或 long 或 long long ),用于存储时间戳。
  5. 时间戳:指从1970年1月1日(通常称为UNIX纪元)零时零秒(UTC时间)起至某一特定时间的缩进过的秒数。
#include <stdio.h>
// 引入头文件
#include <time.h>
// 日期时间相关函数

void  fn() {
  int sum = 0;
  for (int i = 1; i <= 100000000; i++) {
    for (int j = 1; j <= 100; j++) {
      sum += j;
    }
  }
}
int main() {
  // 获取当前时间
  time_t curr_time;
  // time(&变量)  获取当前时间到变量中
  time(&curr_time); 
  printf("%lld\n",curr_time); // 时间戳

  // ctime(&时间值) 将时间值转换为字符串并返回,
  printf("当前时间为:%s\n", ctime(&curr_time)); // 当前时间为:Fri Aug 02 19:10:31 2024

  //计算时间值的差  
  time_t start, end;
  time(&start);
  fn();
  time(&end);
  time_t diff = difftime(end,start ); // end - strat
  printf("fn函数运行所需时间:%lld秒\n", diff);
  return 0;
}

数学相关函数

头文件:<math.h>

  1. sprt(x):计算平方根;
  2. cbrt(x):计算立方根;
  3. pow(x, y):计算x的y次方;
  4. fabs(x):计算x的绝对值;
  5. ceil(x):向上取整;
  6. floor(x):向下取整;
  7. round(x):四舍五入取整;
  8. trunc(c):截断小数部分;

注意:以上函数的参数与返回值的类型都是double类型。

#include <stdio.h>
// 引入头文件
#include <math.h>

int main() {
  // sqrt() 计算平方根
  printf("平方根是:%lf\n", sqrt(4)); // 2.000000

  // cbrt() 计算立方根
  printf("立方根是:%lf\n", cbrt(8)); // 2.000000

  // pow() 计算x的y次方
  printf("2的3次方是:%lf\n", pow(2, 3)); // 8.000000

  // fabs() 计算x的绝对值
  printf("-13的绝对值是:%lf\n", fabs(-13)); //13.000000

  // ceil(x) 向上取整
  printf("3.25向上取整是:%lf\n", ceil(3.25)); // 4.000000

  // floor(x) 向下取整
  printf("3.25向下取整是:%lf\n", floor(3.25)); // 3.000000

  // round(x) 四舍五入取整
  printf("3.25向上取整是:%lf\n", round(3.25)); // 3.000000

  // trunc(x) 截断小数部分
  printf("12.25截断小数部分是:%lf\n", trunc(12.25)); // 12.000000

  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值