当前位置: 首页 > news >正文

C语言:函数

函数


函数的概述

  • 函数:实现一定功能的,独立的代码模块,对于函数的使用,一定是先定义,后使用。

  • 使用函数的优势:

    ① 我们可以通过函数提供功能给别人使用。当然我们也可以使用别人提供的函数,减少代码量。

    ② 借助函数可以减少重复性的代码。

    ③ 实现结构化(模块化:C语言中的模块化其实就是多文件+函数)程序设计思想。

    关于结构化设计思想:将大型的任务功能划分为相互独立的小型的任务模块来设计(多文件 + 函数)

  • 函数的作用: (1) 代码复用:避免重复编写相同功能的代码。 (2) 模块化设计:将复杂程序拆分成多个小功能模块,每个函数负责一个独立任务,使代码逻辑结构更加清晰。 (3) 便于维护和调试:单个函数功能单一,出现问题容易定位和修改,不需要改动整个程序。 (4) 提高开发效率:便于多人协同开发时,分工明确,编写不同函数,最终组合成完整程序

  • 函数是C语言程序的基本组成单元:

    C语言程序必须包含一个main函数,可以包含零个或多个其他函数。

函数的分类

  • 按来源分

    • 库函数:C语言标准库实现的并提供使用的函数,如:scanf()、printf()、fgets()、fputs()、strlen()...

    • 自定义函数:需要程序员自行实现,开发中大部分函数都是自定义函数。

  • 按参数分:

    • 无参函数:函数调用时,无需传递参数,可有可无返回值,如:show_all();

    • 有参函数:函数调用时,需要参数传递数据,经常需要配套返回值来使用,如:printf("%d\n", 12);

  • 按返回值分:

    • 有返回值函数:函数执行后返回一个值,如: if (scanf("%d", &num) != 1)

    • 无返回值函数(void):函数仅执行操作,不返回值

  • 从函数调用的角度分:

    • 主调函数:主动去调用其他函数的函数。(main函数只能作为主调函数)

    • 被调函数:被其他函数调用的函数。

    • 举例:

       // 主调函数int main(){// 被调函数printf("hello world!\n");}

      注意:很多时候,尤其是对于自定义函数,一个函数有可能既是主调函数,又是被调函数。

       int fun_b(){printf("函数B\n");}​// fun_a是主调函数int fun_a(){printf("函数A\n");// fun_b是背调函数fun_b();}​int main(){// fun_a是被调函数fun_a();}

      以上案例中,fun_a()相对fun_b()来说是主调函数,同时对于main()函数来说,他又是被调函数。

函数的定义

定义

语法:

 [返回类型] 函数名([形参列表])       -- 函数头 | 函数首部{函数体语句;                   -- 函数体:整个{}包裹的内容都属于函数体,函数的{}不能省略}

函数头:

  • 返回类型:函数返回值的类型

  • 函数名:函数的名称,遵循标识符命名(不能以数字开头,只能包含大小写字母、下换线、数字。建议:小写+下划线,举例:showAll(),或者小驼峰命名法,第一个单词首字母小写,其他单词首字母大写,举例:showAll()

  • 形参列表:用于接收主调函数传递的数据,如果有多个参数,使用,分隔,切每一个形参都需要指明类型。

小贴士:

① 形参:主调函数给被调函数传递数据:主调函数 → 被调函数

② 返回值:被调函数给主调函数返回数据:被调函数 → 主调函数

通过生活中的案例理解函数调用:

假设:饮料店的工作人员通过榨汁机榨取新鲜果汁

理解:

工作人员:主调函数

榨汁机: 被调函数

水果: 传递的参数

果汁: 函数的返回值

工作人员向榨汁机放入一个水果:主调函数调用被调函数,并传递数据

工作人员用杯子接收榨汁机榨出的果汁:主调函数接收被调函数返回的数据

说明:

函数的返回值:就是返回值的类型,两个类型可以不同,但是必须能够进行转换,举例:

 double fun_a()  // 函数的返回类型是:double{return 12;  // 函数的返回值是:int}// 分析:此时需要转换,函数在执行的时候,会自动提升int的类型为double,此时属于隐式转换,正常转换,以上正确int[] fun_b()   // 函数的返回类型是:int[]{return 12;  // 函数的返回值是:int}// 分析:此时需要提升int的类型为int[],int不能转换为int[],以上错误!int fun_c()     // 函数的返回类型是:int{return 12.5;// 函数的返回值是:double}// 分析:此时需要将double类型转换为int类型,浮点型转整型,会丢失小数部分,保留整数位,以上正确

大家可以这样理解(非官方):

大家可以将函数的返回类型理解为 变量的类型,将函数的返回值理解为 变量的值。

范例:

 /*************************************************************************> File Name:    demo01.c> Author:       久念昕> Description:  > Created Time: 2025年03月14日 星期五 11时02分55秒************************************************************************/​#include <stdio.h>​double fun_a(){return 12;// 就是将int类型的12赋值给double类型的匿名变量 int --> double}​int fun_b(){return 12.5;// 就是将double类型的12.5赋值给int类型的匿名变量 double --> int 此时会舍弃掉小数部分}​double fun_c(){return 12.5;  // 就是将double类型的12.5赋值给double类型的匿名变量 double --> double}​​int main(int argc,char *argv[]){// 接收函数返回值,函数返回什么类型,就用什么类型接收double result1 = fun_a();// 主调函数使用double来接收被调函数返回的double,double --> doubleprintf("%lf\n",result1);​int result2 = fun_b();  // 主调函数使用int来接收被调函数返回的int,int --> intprintf("%d\n",result2);​int result3 = (int)fun_c();  // 主调函数使用int来接收被调函数返回的double,int  --> (int)doubleprintf("%d\n",result3);​return 0;}
  • 在C语言中无返回值时应明确使用void类型(空类型/无类型),举例:
 void test() // 此时这个函数,没有返回值,如果需要提前结束函数,写法:return;{printf("hello world!\n");}​// 下面写法等价于上面写法void test(){printf("hello world!\n");return; // 一般,这个return;省略不写}
  • 在C语言中,C89标准允许函数的返回类型标识符可以省略,如果省略,默认返回int。C99/C11标准要求必须明确指定返回类型,不再支持默认int类型,举例:
 // 写法1:(C89标准),main的返回类型是int类型,默认返回值是0,等价于写法2   不推荐main(){...}​// 写法2:(C99后推荐),等价于上面写法int main(){return 0;}
  • 函数中返回语句的形式为return(表达式)或者return 表达式
 // 写法1int main(){return(0);}​// 写法2int main(){return 0;}
  • 如果参数列表中有多个参数,则它们之间要用,分隔;即使它们的类型相同,在形式参数中只能逐个进行说明,举例:

 // 正确举例int avg(int x, int y, int z){...}​// 错误举例int avg(int x, y, z){...}
  • 如果形参列表中没有参数,我们可以不写,也可以用void标识,举例:

 // 写法1:推荐int main(){...}​// 写法2:int main(void){...}
  • C89开始,提供了变长参数,也就是一个函数的参数个数可以是不确定的。需要引入 <stdarg.h>,扩展:

语法:

 [返回类型] 函数名(参数列表, ...){...}

举例:

 #include <stdio.h>#include <stdarg.h>​// 计算n个整数的平均值double average(int n, ...) { // ...只能放在 具体的参数列表的后面va_list args;       // 声明参数列表对象int sum = 0;va_start(args, n);  // 初始化参数列表,n是最后一个固定参数// 遍历所有可变参数for (int i = 0; i < n; i++) {// 获取一个int类型的参数sum += va_arg(args, int);}va_end(args);       // 清理参数列表return (double)sum / n;}​int main() {printf("平均值: %.2f\n", average(3, 10, 20, 30));   // 20.00printf("平均值: %.2f\n", average(5, 1, 2, 3, 4, 5)); // 3.00return 0;}

案例

案例1
  • 需求:计算1~n之间自然数的阶乘值

  • 代码:

     /*************************************************************************> File Name:    demo02.c> Author:       久念昕> Description:  > Created Time: 2025年07月22日 星期二 11时01分36秒************************************************************************/​#include <stdio.h>​/*** 定义一个函数,实现1~n之间的阶乘计算* @param n:阶乘上限* @return n的阶乘值*/ size_t fun_1(int n){int i;  // 循环变量size_t s = 1; // 阶乘值,初始值是1​for (i = 1; i <= n; i++) s *= i;​return s;}​int main(int argc,char *argv[]){printf("1~12的阶乘结果是:%lu\n", fun_1(12));printf("1~20的阶乘结果是:%lu\n", fun_1(20));printf("1~30的阶乘结果是:%lu\n", fun_1(30));printf("1~40的阶乘结果是:%lu\n", fun_1(40));​return 0;}​

    运行结果:

注意:这里计算结果为0,是因为数据太大,超过int存储范围,高位数据丢失,低位数据转出来为0,建议使用unsigned long类型。

案例2
  • 需求:计算一个圆台两个面的面积之和。

  • 代码:
 /*************************************************************************> File Name:    demo03.c> Author:       久念昕> Description:  > Created Time: 2025年07月22日 星期二 11时24分18秒************************************************************************/​#include <stdio.h>#include <math.h>​#define PI 3.1415926​/*** 定义一个函数:实现圆的面积计算* @param r:圆的半径* @return 圆的面积*/ double cicle_area(double r){// return PI * r * r;return PI * pow(r,2.0); // pow(底数,指数);编译需要加 -lm}​int main(int argc,char *argv[]){// 定义两个半径,两个面积double r1,r2,area1,area2;​printf("请输入两个圆的半径:\n");scanf("%lf,%lf", &r1, &r2);​// 计算面积area1 = cicle_area(r1);area2 = cicle_area(r2);​printf("一个圆台两个面的面积之和是%lf\n", area1 + area2);return 0;}​
  • 编译命令
gcc demo03.c -lm

形参和实参

形参(形式参数)

定义

函数定义时指定的参数,形参是用来接收数据的。函数定义时,系统不会为形参申请内存,只有当函数调用时,系统才会为形参申请内存。主要用于存储实际参数,并且当函数返回时(执行return),系统会自动回收为形参申请的内存资源。

  • C语言中所有的参数传递都是值传递

  • 若要修改实参,需要传递指针,指针传递本质上也是值传递(后续章节讲)。

案例
  • 需求:判断一个数是偶数还是奇数

  • 代码:

/*************************************************************************> File Name:    demo04.c> Author:       久念昕> Description:  > Created Time: 2025年07月22日 星期二 14时17分13秒************************************************************************/#include <stdio.h>/*** 方式1*/ 
void fun1(int n) // 这里的n就是形参
{if (n % 2 == 0){printf("%d是偶数!\n", n);return; // 提前结束函数,后续代码不再执行}printf("%d是奇数!\n", n);
}/*** 方式2*/ 
int fun2(int n)
{if (n % 2 == 0){printf("%d是偶数!\n", n);return -1;}printf("%d是奇数!\n", n);return 0;
}int main(int argc,char *argv[])
{fun1(5);fun2(5);return 0;
}

实参(实际参数)

定义

实参是函数调用时由主调函数传递给被调函数的具体的数据。实参可以是常量、变量、表达式、带有返回值的函数等。

关键特性
  1. 类型多样性:

    • 实参可以是常量、变量或者表达式...。

    • 例如:

      fun(12);      // 常量作为实参
      fun(a);       // 变量作为实参
      fun(a + 12);  // 表达式作为实参
      fun(func());  // 带有返回值的函数作为实参

  2. 类型转换:

    • 当实参和形参类型不同时,会按照赋值规则进行类型转换。

    • 类型转换可能导致精度丢失。

    • 例如:

      #include <stdio.h>/*** 求一个数的绝对值*/
      double fabs(double a)
      {return a < 0 ? -a : a;
      }int main()
      {int x = 12, y = -12;int x1 = (int)fabs(x);  // x会被隐式转换为double,fabs返回的是double类型数据int y1 = (int)fabs(y);
      }

      注意:函数调用的时候,通过实参给形参赋值。形参类似于变量,实参类似于变量的值。

      函数调用时:

      主调函数通过实参给被调函数的形参赋值,可理解为:将主调函数的值赋值给被调函数的变量。

      函数返回时:

      被调函数通过返回值给主调函数赋值,可理解为:将被调函数的值赋值给主调函数的变量。

  3. 单向值传递:

    • C语言采用单向值传递机制(赋值的方向:实参 → 形参)

    • 实参仅将其值赋值给形参,不传递实参本身。

    • 形参值的改变不会影响实参。

    • 案例:

      int modify(int n) // n的变量地址:0x11
      {n = 20;  // 修改 0x11这个空间的数据位20  n = 20return n;
      }int main()
      {int n = 10;   // n的变量地址:0x21modify(n);    // 将0x21中的数据赋值给0x11这个空间printf("%d\n", n); // 10
      }

  4. 内存独立性

    • 实参和形参在内存中占据不同的空间

    • 形参拥有独立的内存地址

演示

#include <stdio.h>int fun(int n)  // n是形参
{printf("形参n的值:%d\n", n);n += 5; // 修改形参的数据return n;
}int main()
{int a = 10;printf("调用前实参a的值:%d\n", a); // 10// 变量作为实参int res = fun(a); // a 是实参printf("调用前实参a的值:%d\n", a); // 10printf("函数返回值:%d\n", res);   // 15// 常量作为实参fun(12);   //字面量12作为实参// 表达式作为实参fun(a + 12); // 表达式作为实参return 0;
}

上述示例程序会输出:

  调用前实参a的值: 10形参n的值: 10调用后实参a的值: 10函数返回值: 15形参n的值: 12形参n的值: 22
案例
  • 需求:输入4个整数,要求用一个函数求出最大数。

  • 分析:

    • 设计一个函数,这个函数只求2个数的最大数

    • 多次复用这个函数实现最终的求值

  • 代码:

/*************************************************************************> File Name:    demo05.c> Author:       久念昕> Description:  > Created Time: 2025年07月22日 星期二 15时35分40秒************************************************************************/#include <stdio.h>/*** 定义一个函数,求2个数的最大值* @param x,y:参与比较的整数* @return 返回最大值*/ 
int get_max(int x, int y)
{return x > y ? x : y;
}int main(int argc,char *argv[])
{// 定义4个变量,用来接收控制台输入int a,b,c,d;// 定义一个变量,存储最大值int max;printf("请输入4个整数:\n");scanf("%d%d%d%d", &a, &b, &c, &d);// 求a,b最大值max = get_max(a,b);// 求a,b,c最大值max = get_max(max,c);// 求a,b,c,d最大值max = get_max(max,d);printf("%d,%d,%d,%d中的最大值是%d\n",a,b,c,d,max);return 0;
}
  • 运行结果:

函数的返回值

定义

  • 若不需要返回值,函数可以没有return语句;

// 如果返回类型是void,return关键字可以省略
void fun1()
{...  // return;
}// 这种写法,return关键字也可以省略,但是此时默认返回是 return 0
int fun2()
{...  // return 0;
}// 这种写法,return关键字也可以省略,但是此时默认返回是 return 0
fun3() // 如果不写返回类型,默认返回int,C99/C11之后不再支持省略返回类型
{... // return 0;
}
  • 一个函数中可以有多个return语句,但是同一时刻只有一个return语句被执行。

#include <stdio.h>int eq(int num)
{if (num % 2 == 0) return 0;return 1;
}int main()
{int num = 5;printf("%d是一个%s\n", num, eq(num) == 0 ? "偶数" : "奇数"); // 5是一个奇数
}
  • 返回类型一般情况下要和函数中return语句返回的数据类型一致,如果不一致,要符合C语言中的隐式转换规则。

double add(int a, int b) // 返回类型是double
{return a + b;  // 返回值的类型是int
}// 简化理解:  double add = a + b;

案例

  • 需求:输入两个整数,要求用一个函数求出最大值

  • 实现1:不涉及类型转换

#include <stdio.h>int get_max(int x, int y)
{if (x > y) return x;return y;
}int main()
{int a,b,max;printf("请输入两个整数:\n");scanf("%d%d",&a,&b);max = get_max(a,b);printf("%d,%d中的最大值是%d\n",a,b,max);
}
  • 实现2:设计类型转换-隐式转换

#include <stdio.h>double get_max(int x, int y)  // int隐身转换为double
{if (x > y) return x;return y;
}int main()
{int a,b,max;printf("请输入两个整数:\n");scanf("%d%d",&a,&b);max = (int)get_max(a,b);  // 显示转换printf("%d,%d中的最大值是%d\n",a,b,max);
}
  • 实现3:涉及类型转换-显示转换

#include <stdio.h>int get_max(int x, int y)  // 将double类型转换为int类型,可以隐式转换,也可以显示转换
{double z;z = x > y ? x : y;return (int)z; // 显示转换
}int main()
{int a,b,max;printf("请输入两个整数:\n");scanf("%d%d",&a,&b);max = get_max(a,b);printf("%d,%d中的最大值是%d\n",a,b,max);
}

函数的调用

调用方式

① 函数语句:

test();             // 对于无返回值的函数,直接调用
int res = max(2,4); // 对于有返回值的函数,一般需要在主调函数中接收被调函数的返回值

② 函数表达式:

4 + max(2,4)
scanf("%d", &num) != 1
(c = getchar()) != '\0'

③ 函数参数:

printf("%d", (int)fabs(number)); // 函数作为实参

注意:函数可以作为函数的实参,如果要作为形参,必须使用函数指针。

在一个函数中调用另一个函数具备以下条件:

  • 被调用的函数必须是已经定义的函数。

  • 若使用库函数,应在本文件开头用#include包含其对应的头文件。

  • 若使用自定义函数,自定义函数又在主调函数的后面,则应在主调函数中对被调函数进行声明。声明的作用是把函数名、函数参数的个数和类型等信息通知编译系统,以便于在遇到函数时,编译系统能正确识别函数,并检查函数调用的合法性。

函数的声明

函数调用时,往往要遵循先定义,后使用,但如果我们对函数的调用操作出现在函数定义之前,则需要对函数进行声明。

定义

完整的函数使用分为三部分:

  • [函数声明]

    int max(int x, int y, double z);     // 函数声明只保留函数头,便于编译系统进行检查
    int max(int, int, double);           // 函数声明的时候,可以省略形参名称

    函数声明如果是在同一个文件,一定要定义在文件中所有函数定义的最前面。如果有对应的.h文件,可以将函数的声明抽取到.h中。

  • 函数定义

    int max(int x, int y, double z)     // 函数定义时,一定不能省略形参名称
    {return x > y ? x : y > z ? y : (int)z;
    }

    函数定义的时候,不能省略形参的数据类型、参数个数、参数名称,位置要和函数声明完全一致。

    注意:函数定义时参数列表要和函数声明时的参数列表完全对应,同时函数定义要保留形参名称

  • 函数调用      

int main()
{printf("%d\n", max(4,5,6));
}

作用

C语言的函数声明时为了提前告诉编译系统函数的名称、返回类型和参数,这样在函数实际定义之前就能安全调用它,避免编译错误,同时检查参数和返回值是否正确。相当于给编译器一个“预告”,确保代码正确编译和运行。

使用

  • 错误示例:被调函数写在主调函数之后

// 主调函数
int main()
{printf("%d\n", add(12,13));// 编译报错,因为函数未经过声明,编译系统无法检查函数的合法性
}// 被调函数
int add(int x, int y)
{return x + y;
}
  • 正确示例:主调函数写在被调函数之后

    // 被调函数
    int add(int x, int y)
    {return x + y;
    }// 主调函数
    int main()
    {printf("%d\n", add(12,13));
    }

    注意:如果函数的调用比较简单,如a函数调用b函数,b函数定义在a函数之前,此时是可以省略函数声明的。

  • 正确演示:被调函数和主调函数无法区分前后,必须要增加函数声明

    // 函数声明
    void funa(int, int);
    void funb(int, int);// 函数定义
    void funb(int a, int b)
    {...// 函数调用funa();
    }void funa(int a, int b)
    {...// 函数调用funb();
    }int main()
    {// 函数调用funa(12,13);
    }

    声明的方式

    • 函数头加上分号

      int add(int a, int b);
    • 函数头加上分号,可省略形参名称,但不能省略参数类型

      int add(int, int);

变量和函数底层工作原理【扩展】


变量的底层执行机制

变量本质是内存中的一块存储空间,其底层处理涉及编译期的符号解析运行时的内存分配与访问

  1. 编译阶段:符号表与地址映射

    • 编译器在编译时会为每个变量创建符号表条目,记录变量名、类型、作用域和内存偏移量(而非实际地址)。

    • 对于全局变量和静态变量,编译器会将其分配到数据段(已初始化)或BSS 段(未初始化),并计算其在段内的偏移量。

    • 对于局部变量,编译器会记录其在栈帧中的相对位置(基于栈指针的偏移量)。

  2. 运行阶段:内存分配与访问

    • 全局 / 静态变量:程序加载时,操作系统会将数据段和 BSS 段加载到内存的固定位置,变量的实际地址 = 段起始地址 + 编译期计算的偏移量。

    • 局部变量:函数调用时,CPU 会为函数创建栈帧,局部变量的地址 = 栈指针(SP) + 编译期确定的偏移量(通常为负数,因为栈向下生长)。

    • 动态变量(malloc):通过系统调用在中分配内存,返回的指针是堆中实际地址,由内存管理模块(如 glibc 的 ptmalloc)维护。

  3. 访问变量的底层指令

    • 访问变量时,CPU 通过地址计算得到内存地址,再执行加载(load)或存储(store)指令。

    • 例如,int a = 5; 会被编译为:计算a的地址,然后执行store 5 到该地址

函数的底层执行机制

函数的执行本质是指令流的跳转与栈帧管理,涉及函数调用、栈帧创建、参数传递和返回值处理。

  1. 编译阶段:函数地址与指令生成

    • 编译器将函数体编译为一系列机器指令,存储在代码段(只读),并在符号表中记录函数名与起始地址。

    • 函数参数和返回值的传递方式(如栈传递、寄存器传递)由调用约定(如 cdecl、stdcall)决定,编译器会按约定生成对应指令。

  2. 函数调用的底层步骤

    • 步骤 1:参数入栈 调用者将参数按约定顺序(通常从右到左)压入栈中,或放入指定寄存器(如 x86-64 的部分参数用寄存器传递)。

    • 步骤 2:保存返回地址 CPU 将下一条指令的地址(函数调用后的执行点)压入栈中,供函数返回时使用。

    • 步骤 3:跳转至函数入口 执行call指令,将程序计数器(PC)设置为函数的起始地址,开始执行函数指令。

    • 步骤 4:创建栈帧 函数执行的第一条指令通常是:asm

      push ebp       ; 保存调用者的栈帧基址
      mov  ebp, esp  ; 用当前栈指针作为新栈帧的基址
      sub  esp, N    ; 为局部变量分配N字节的栈空间

      此时栈帧包含:参数、返回地址、上一个栈帧基址(ebp)、局部变量。

    • 步骤 5:执行函数体 按编译生成的指令执行逻辑,访问局部变量(通过ebp偏移)、操作参数(通过ebp正偏移)。

    • 步骤 6:返回结果 返回值通常存入指定寄存器(如 x86 的eax,x86-64 的rax),或通过栈传递(大型结构体)。

    • 步骤 7:恢复栈帧并返回 执行:asm

      mov  esp, ebp  ; 释放局部变量的栈空间
      pop  ebp       ; 恢复调用者的栈帧基址
      ret            ; 弹出返回地址到PC,跳转回调用者

关键底层概念

  • 内存分段:代码段(指令)、数据段(全局变量)、BSS 段(未初始化全局变量)、栈(局部变量 / 函数调用)、堆(动态内存)。

  • 栈帧:每个函数调用对应一个栈帧,包含参数、返回地址、局部变量,由 ebp(基址指针)和 esp(栈指针)界定。

  • 地址绑定:变量和函数的地址在编译期(静态绑定)或加载 / 运行期(动态绑定,如共享库)确定。

总结

  • 变量:通过编译期符号表记录偏移量,运行时映射到实际内存地址,通过 CPU 的加载 / 存储指令访问。

  • 函数:通过call指令跳转至代码段执行,借助栈帧管理参数、局部变量和返回地址,最终通过ret指令返回。

http://www.dtcms.com/a/300923.html

相关文章:

  • AI大模型前沿:Muyan-TTS开源零样本语音合成技术解析
  • 力扣129. 求根节点到叶节点数字之和
  • Python day26
  • 基于 KNN 算法的手写数字识别项目实践
  • OpenLayers 综合案例-点位聚合
  • Java Ai(day04)
  • Android CameraX 使用指南:简化相机开发
  • 7.25 C/C++蓝桥杯 |排序算法【下】
  • git删除远程分支和本地分支
  • Windows10+WSL2+Docker相关整理
  • IP--MGER综合实验报告
  • git 修改 更新
  • Red靶机攻略
  • 洛谷P2880 [USACO07JAN] Balanced Lineup G
  • Java面试新趋势:云原生与新兴框架实战解析
  • 计算机网络:(十二)传输层(上)运输层协议概述
  • Docmost:一款开源的Wiki和文档协作软件
  • 【Linux | 网络】传输层(UDP和TCP)
  • 电动汽车转向系统及其工作原理
  • 深入理解Linux网络-读书笔记(一)
  • 新手开发 App,容易陷入哪些误区?
  • 北京-4年功能测试2年空窗-报培训班学测开-第六十一天-模拟面试第一次
  • 数据结构基础内容(第二篇:线性结构)
  • 智谱AI GLM大模型 GLM-4-Plus的快速使用 ChatOpenAI类来调用GLM-4模型
  • 2025第15届上海生物发酵展将于8月7号启幕
  • HBuilder X打包发布微信小程序
  • PDF转图片实用指南:如何批量高效转换?
  • cuda编程笔记(10)--memory access 优化
  • 《P4568 [JLOI2011] 飞行路线》
  • Flutter开发实战之性能优化与调试