解锁 C 语言 “积木术”:大一函数总结

news2026/4/1 10:26:33
大一 C 语言函数核心总结本文围绕 C 语言函数从基础认知到实战运用、从核心语法到避坑技巧展开兼顾基础考点与编程思想内容可直接用于复习和实操参考每个核心模块仅保留 2 个典型示例多余拓展示例文末有补充。一、函数的基础认知1.1函数的定义函数是编程中对一组实现特定功能的代码逻辑的封装与命名是可复用的 “代码模块”。核心特点可接收输入参数可选、执行专属逻辑、返回输出返回值可选定义后可在程序任意位置多次调用无需重复编写代码同时让程序结构更清晰、易维护。核心总结函数是封装特定功能的可复用代码块有专属唯一名称核心逻辑传参输入→ 执行操作 → 返回结果输出输入和输出均可省略核心价值减少代码冗余提升程序可读性、可维护性和可调试性。对比示例重复代码实现求和 VS 函数封装实现求和#define _CRT_SECURE_NO_WARNINGS #include stdio.h // 无函数重复书写输入和累加逻辑冗余且修改麻烦 int main() { int sum 0; int a, b, c, d; printf(请输入第1个整数); scanf(%d, a); sum a; printf(请输入第2个整数); scanf(%d, b); sum b; printf(请输入第3个整数); scanf(%d, c); sum c; printf(请输入第4个整数); scanf(%d, d); sum d; printf(所有数的和为%d\n, sum); return 0; }那如果用函数呢#define _CRT_SECURE_NO_WARNINGS #include stdio.h // 自定义加法函数封装核心累加逻辑一次定义多次调用 int add(int x, int y) { return x y; } int main() { int sum 0; int a, b, c, d; printf(请输入4个整数空格分隔); scanf(%d %d %d %d, a, b, c, d); sum add(add(add(a, b), c), d); // 多次复用add函数嵌套调用更简洁 printf(所有数的和为%d\n, sum); return 0; }1.2函数与 main () 的核心关系main()是 C 程序的唯一入口普通函数是程序的功能单元二者为「主调 - 被调」关系核心两点程序运行时操作系统仅会先找到并执行main()执行流程从main()第一行开始到main()执行结束return或正常走完为止普通函数不会主动执行必须在main()内部或main()调用的其他函数内部被 “调用”才能参与程序执行。通俗比喻main()是厂长办公室启动流程、分配任务普通函数是各个车间负责具体功能车间不会自行开工需等待厂长办公室的指令调用所有任务完成后回到厂长办公室程序结束。1.3函数的分类C 语言函数按来源分为两类是后续学习的基础分类库函数C 语言标准库提供的现成函数无需自己定义直接调用即可需引入对应头文件如printf()、strlen()自定义函数开发者根据需求自行定义的函数实现专属功能如上述的add()函数。二、自定义函数核心语法自定义函数是实现个性化功能的核心固定格式为 「函数头 {函数体}」二者缺一不可。2.1函数头组成函数头是函数的 “标识信息”必须按顺序书写返回值类型 函数名 (形参列表)返回值类型指定函数执行后返回数据的类型如int、float无返回值则写void函数名函数的唯一标识调用函数时通过函数名触发形参列表函数的输入参数无参数则写空括号()多个参数用逗号分隔。2.2函数体要求必须用大括号{}包裹即使只有一行代码也建议保留大括号规范写法内部实现函数的具体专属功能建议单一功能原则一个函数只做一件事语句不宜过多可在函数体内定义局部变量、执行业务语句、书写return语句。2.3函数名命名规范由字母、数字、下划线组成首字符不能是数字不能与 C 语言关键字如int、if、for重名不与库函数名重复见名知意如求和用add/sum求平方用square小写为主多个单词用下划线分隔如sum_square。标准示例// 函数头int(返回值类型) sum_square(函数名) (int a, int b)(形参列表) // 函数体实现两数平方和的核心逻辑 int sum_square(int a, int b) { int s1 a * a; int s2 b * b; return s1 s2; // 返回结果 }三、函数的参数和返回值参数是函数的 “输入”返回值是函数的 “输出”二者是函数与主调程序交互的核心。3.1函数的参数参数分为形参和实参传参方式为大一核心重点值传递。形参形式参数定义在函数头中声明的参数如add(int x, int y)中的x、y特点属于函数的局部变量仅在函数体内有效函数调用时才分配内存调用结束后内存立即释放多个形参需分别指定类型如int x, int y不能写int x, y。实参实际参数定义调用函数时传递给形参的具体值如add(1, 2)中的1、2要求实参的类型、个数、顺序必须与形参一一对应实参可以是常量、变量、合法表达式如add(ab, 3*4)。传参方式值传递核心逻辑将实参的数值拷贝给形参形参与实参在内存中是两个独立的空间关键结论函数内对形参的修改不会影响原实参的数值大一需牢记与数组传参区分。值传递示例#include stdio.h void change(int n) { n 100; // 修改形参n } int main() { int a 10; change(a); // 实参a传递给形参n printf(a %d, a); // 输出a10形参修改不影响实参 return 0; }3.2函数的返回值返回值通过return语句实现是函数给主调程序的 “执行结果”核心规则围绕return语句展开。return 语句的核心作用终止当前函数的执行函数内return后的代码不再执行将指定结果返回给主调函数一个函数可有多条return语句但仅会执行第一条满足条件的return。返回值类型的匹配要求return语句后的值的类型必须与函数头声明的返回值类型一致允许低精度向高精度隐式转换如int转float不建议高精度转低精度会丢失数据。无返回值的情况void 关键字函数头用void声明返回值类型表示函数无返回值可省略return语句若手动书写则仅能写return;不能跟任何数值。返回值示例#include stdio.h // 有返回值int类型return后必须跟int值 int getMax(int a, int b) { if (a b) return a; // 第一条满足的return执行后续代码不运行 return b; } // 无返回值void类型仅执行功能不返回结果 void printMsg() { printf(Hello C\n); return; // 可省略仅写return;不能跟值 } int main() { int max getMax(5, 8); // 接收返回值 printMsg(); // 直接调用无需接收 printf(max %d, max); return 0; }四、函数的调用函数定义后需通过调用才能执行调用语法简单但需区分有 / 无返回值的调用方式是实操的基础。4.1函数调用的基本语法// 有参函数函数名 (实参列表)多个实参用逗号分隔 函数名(实参1, 实参2, ...); // 无参函数函数名 空括号括号不能省略 函数名();4.2函数调用的常见类型普通调用主调函数直接调用被调函数执行完被调函数后返回主调函数的调用位置继续执行后续代码嵌套调用一个函数内部调用另一个函数C 语言允许多层嵌套调用套娃核心规则只准嵌套调用不准嵌套定义不能在一个函数内定义另一个函数。4.3不同返回值类型的调用方式4.3.1有返回值函数非 void有两种调用方式核心是接收或使用函数的返回值赋值调用将函数返回值赋值给同类型变量最常用int res add(1, 2); // add返回3赋值给res表达式调用将函数调用作为表达式的一部分直接使用返回值printf(和为%d, add(1, 2)); // add返回值直接作为printf的参数 if (getMax(5, 8) 6) { ... } // getMax返回值参与条件判断4.3.2无返回值函数void仅有一种调用方式直接调用单独作为一条语句无需赋值赋值也无意义仅执行函数内的功能printMsg(); // 直接调用执行打印功能 change(a); // 直接调用执行修改形参的功能五、函数的嵌套调用 链式访问二者是 C 语言函数调用的进阶方式实际开发中经常混用核心区别嵌套调用侧重执行流程的嵌套链式访问侧重返回值的直接传递各保留 2 个典型示例。一、函数的嵌套调用5.1.1核心定义在一个函数的执行过程中调用另一个函数执行完被调函数的全部代码后再回到原函数的调用位置继续执行后续代码。核心禁忌禁止函数嵌套定义如在main()内定义add()只能在函数外定义、函数内调用。5.1.2核心特点层层调用、逐层返回函数 A 调函数 B → 先执行 B 的全部代码 → B 执行完返回到 A 的调用位置 → 继续执行 A 的后续代码。5.1.2示例示例 1基础嵌套调用#include stdio.h // 被调用函数求一个数的平方 int square(int n) { return n * n; } // 主调函数求两数平方和嵌套调用square int sumSquare(int a, int b) { int s1 square(a); int s2 square(b); return s1 s2; } int main() { int res sumSquare(3, 4); // main调用sumSquare printf(3²4²%d, res); // 输出25 return 0; }执行流程main → sumSquare → square (3) → 返回 sumSquare → square (4) → 返回 sumSquare → 求和 → 返回 main → 打印。示例 2多层嵌套调用#include stdio.h // 步骤1求两数之和 int add(int a, int b) { return a b; } // 步骤2求和的2倍嵌套调用add int doubleNum(int a, int b) { return add(a, b) * 2; } // 步骤3求最终结果嵌套调用doubleNum int getResult(int x, int y, int z) { return doubleNum(x, y) - z; } int main() { printf(结果%d, getResult(1,2,3)); // 输出3 return 0; }执行流程main → getResult → doubleNum → add → 逐层返回计算 → 输出结果。二、函数的链式访问5.2.1核心定义把一个函数的返回值直接作为另一个函数的参数来使用无需用临时变量接收返回值让代码更简洁像 “链条” 一样把函数串起来。5.2.2核心特点返回值直接传参无临时变量函数调用作为另一个函数的实参前提条件被调用函数的返回值类型必须和另一个函数的对应形参类型一致否则编译器报错或出现逻辑错误。5.2.3示例示例 1基础链式访问自定义函数#include stdio.h int add(int a, int b) { return a b; } int main() { // add(1,2)返回3直接作为第二个add的第一个参数 int res add(add(1, 2), 3); printf(123%d, res); // 输出6 return 0; }示例 2经典库函数链式访问#include stdio.h #include string.h // 引入strlen的头文件 int main() { // strlen(hello)返回5unsigned int直接作为printf的%d参数 printf(字符串长度%d, strlen(hello)); // 输出5 return 0; }三、避坑注意点嵌套调用禁止嵌套定义多层嵌套不要过多否则代码可读性差、调试困难链式访问严格保证返回值类型与形参类型一致如strlen返回unsigned int避免传给需要int的形参多层链式不要过度二者可混用实际开发中嵌套调用里可以用链式访问链式访问的底层也可能是嵌套调用根据需求灵活使用即可。二者核心总结嵌套调用函数里调函数核心是流程嵌套记住「只准嵌套调用不准嵌套定义」链式访问函数返回值直接当另一个函数的参数核心是返回值传参记住「类型匹配按需简化」。六、函数的声明与定义函数的定义是实现函数功能的完整代码声明是告诉编译器函数的 “标识信息”返回值类型、函数名、形参列表二者是多文件开发的基础也是解决 “函数调用在前定义在后” 报错的关键保留 2 个典型场景示例。我们拿之前例子下⾯代码中上半的部分是函数的定义下半的部分有函数的调⽤。 这种场景下是函数的定义在函数调⽤之前没啥问题。如果颠倒位置呢这是因为C语⾔编译器对源代码进⾏编译的时候从第⼀⾏往下扫描的当遇到函数调⽤的时候并没有发现前⾯有它的定义就报出了上述的警告。 把怎么解决这个问题呢就是函数调⽤之前先声明⼀下add这个函数声明函数只要交代清楚函数名函数的返回类型和函数的参数。函数声明中参数只保留类型省略掉名字也是可以的代码变成这样就能正常编译了6.1. 声明的必要性C 语言编译器从上到下扫描编译源代码若函数调用在前定义在后编译器遇到调用时未找到函数定义会报 “隐式声明” 警告或直接报错。解决方法在函数调用之前先对函数进行声明。6.2. 函数声明的语法声明只需交代函数的核心标识信息无需写函数体有两种写法均合法推荐写法 1// 写法1推荐清晰保留形参名和类型 返回值类型 函数名(形参类型1 形参名1, 形参类型2 形参名2, ...); // 写法2简洁仅保留形参类型省略形参名 返回值类型 函数名(形参类型1, 形参类型2, ...); // 示例add函数的两种声明方式 int add(int a, int b); // 写法1 int add(int, int); // 写法26.3. 声明与定义的位置示例2 个典型场景示例 1单文件场景调用在前定义在后#define _CRT_SECURE_NO_WARNINGS #include stdio.h // 函数声明调用前声明解决“调用在前定义在后”问题 int add(int a, int b); int main() { int res add(1, 2); // 函数调用在前 printf(和为%d, res); return 0; } // 函数定义实现功能在后 int add(int a, int b) { return a b; }示例 2多文件场景企业标准声明 / 定义分离3 文件结构add.h声明、add.c实现、main.c调用add.h头文件仅声明int add(int a, int b); // 函数声明add.c源文件仅实现#include add.h // 引入声明校验一致性 int add(int a, int b) { // 函数定义 return a b; }main.c主文件调用函数#define _CRT_SECURE_NO_WARNINGS #include stdio.h #include add.h // 引入声明 int main() { printf(34%d, add(3,4)); // 输出7 return 0; }GCC 编译命令gcc main.c add.c -o test ./test像之前写过的扫雷程序就是如此C语言旅程之扫雷游戏基础版讲解-CSDN博客七、static 与 extern跨文件作用域控制static和extern是控制全局变量 / 函数跨文件作用域的核心关键字二者一 “藏” 一 “联”是多文件开发的基础标配各保留 2 个典型使用示例。核心结论先记死extern跨文件访问的 “钥匙”声明其他.c 文件定义的全局变量 / 函数实现跨文件复用static多文件封装的 “屏障”限制全局变量 / 函数的作用域仅当前.c 文件实现私有隔离、避免命名冲突。一、extern实现跨文件访问7.1.1核心作用extern的唯一作用是声明外部符号C 语言中全局变量、函数的名字称为 “符号”告诉编译器该变量 / 函数并非当前文件定义需到其他.c 文件查找实际定义。关键特性extern只有声明作用无定义作用不能给extern变量赋值赋值即定义会报错。7.1.2多文件使用示例2 个典型基于上述 3 文件结构示例 1extern 修饰函数最常用可省略函数默认具有全局作用域跨文件调用时extern可直接省略头文件中直接写函数声明就是企业标准写法即上述add.h中的int add(int a, int b);无需加extern。示例 2extern 修饰全局变量必须显式写全局变量默认全局作用域但跨文件访问时必须用extern显式声明且声明与定义严格分离声明放.h定义放唯一的.c 文件。add.h头文件extern 声明全局变量 函数声明extern int g_num; // 显式声明g_num在其他.c文件定义 int add(int a, int b);add.c源文件唯一定义全局变量 实现函数#include add.h int g_num 100; // 唯一定义分配内存并初始化 int add(int a, int b) { return a b; }main.c主文件跨文件访问 / 修改全局变量#define _CRT_SECURE_NO_WARNINGS #include stdio.h #include add.h int main() { printf(跨文件访问g_num%d\n, g_num); // 输出100 g_num 200; // 支持跨文件修改 printf(修改后g_num%d\n, g_num); // 输出200 return 0; }二、static实现多文件封装隔离7.2.1核心作用static的核心作用是限制符号的作用域为当前.c 文件专业说法内部链接用static修饰的全局变量 / 函数成为当前文件的 “私有财产”—— 其他文件即使通过extern声明也无法访问 / 调用从根源避免多文件的命名冲突。7.2.2多文件使用示例2 个典型基于上述 3 文件结构示例 1static 修饰全局变量当前文件私有修改add.c给全局变量加static#include add.h static int g_num 100; // 仅add.c可用其他文件无法访问 int add(int a, int b) { return a b; }此时编译运行main.c编译器直接报错undefined reference to g_num即使add.h有extern int g_num;也无效。示例 2static 修饰函数当前文件私有修改add.c给函数加static#include add.h int g_num 100; static int add(int a, int b) { // 仅add.c可用其他文件无法调用 return a b; }此时编译运行main.c编译器报错undefined reference to add无法跨文件调用该函数。企业应用场景如sort.c实现冒泡排序需外部调用和选择排序仅内部辅助给选择排序加static只暴露冒泡排序实现代码封装提高程序安全性。八、数组传参C 语言数组可直接作为函数参数传递是大一函数的重要实战场景核心特性与普通值传递不同函数内对数组的操作会直接修改主程序的原数组同时需注意函数无法自行获取数组的真实长度二维数组传参有固定写法要求一维 / 二维各保留 2 个典型示例。8.0.1核心前置结论一维数组传参形参写数组名[]必须同时传数组长度用arr[i]访问 / 操作元素二维数组传参形参写数组名[][列数]列数必须固定手动传行数用arr[i][j]访问 / 操作元素核心特性函数内对数组的所有操作都会直接改变主程序里的原数组与普通值传递的核心区别。一、一维数组的函数运用最常用2 个典型示例1. 传参合法写法假设主程序有数组int arr[5] {1,2,3,4,5};函数形参写以下任意一种均可括号内的数字无实际意义// 写法1推荐直观省略数组长度 void printArr(int arr[], int len); // 写法2兼容写法写原数组长度 void printArr(int arr[5], int len);2. 关键硬性要求函数内部无法计算出原数组的真实长度sizeof(arr)/sizeof(arr[0])得到的是指针长度非数组长度因此传参时必须把数组长度作为第二个参数一起传给函数否则无法正确遍历数组。3. 经典实用示例直接运行2 个典型示例 1函数打印一维数组基础遍历#include stdio.h // 形参数组长度功能打印所有元素 void printArr(int arr[], int len) { for (int i 0; i len; i) { printf(%d , arr[i]); } } int main() { int arr[5] {1,2,3,4,5}; int len 5; printArr(arr, len); // 传数组名长度输出1 2 3 4 5 return 0; }示例 2函数修改一维数组元素核心特性验证#include stdio.h // 功能将数组所有元素乘2 void updateArr(int arr[], int len) { for (int i 0; i len; i) { arr[i] * 2; // 直接修改数组元素 } } int main() { int arr[3] {10,20,30}; int len 3; updateArr(arr, len); for (int i 0; i len; i) { printf(%d , arr[i]); // 输出20 40 60原数组被修改 } return 0; }二、二维数组的函数运用二维数组传参有唯一硬性规则形参必须指定第二维列数第一维行数可以省略其他规则与一维数组一致手动传行数、用arr[i][j]访问、操作会修改原数组。1. 传参固定写法直接抄用2 种合法写法假设主程序有二维数组int arr[2][3] {{1,2,3},{4,5,6}};2 行 3 列函数形参只能写以下两种列数必须为 3与原数组一致// 写法1推荐省略行数指定列数 void print2DArr(int arr[][3], int row); // 写法2指定行数和列数行数可改列数不能改 void print2DArr(int arr[2][3], int row);2. 经典实用示例2 个场景打印 核心注意示例 1函数打印二维数组#include stdio.h // 形参二维数组指定列数3 行数row void print2DArr(int arr[][3], int row) { for (int i 0; i row; i) { // 遍历行 for (int j 0; j 3; j) { // 遍历列列数固定 printf(%d , arr[i][j]); } printf(\n); // 每行打印完换行 } } int main() { int arr[2][3] {{1,2,3}, {4,5,6}}; int row 2; print2DArr(arr, row); // 传数组名行数按行打印 return 0; }输出1 2 3 4 5 6示例 2二维数组传参错误示范避坑核心注意// 错误写法未指定列数编译器直接报错 void print2DArr(int arr[][], int row) { ... } // 错误写法列数与原数组不一致原3列写2列编译器直接报错 void print2DArr(int arr[][2], int row) { ... }核心结论二维数组列数是 “硬性指标”必须与原数组一致否则直接编译报错。三、数组传参核心注意点传参只传数组名调用函数时直接写数组名如printArr(arr, len)不要加[]或下标这是固定写法保留原数组的方法若想避免修改原数组需在函数内新建一个数组把原数组元素复制过去后再操作新手暂时了解即可二维数组列数不可省无论形参如何书写第二维列数必须与原数组一致否则编译器直接报错传参必传长度 / 行数一维传长度、二维传行数函数无法自行获取是必传参数。九、常见错误汇总大一学习函数时高频错误集中在语法、参数、返回值、调用四个方面熟记并规避这些错误能减少 80% 的编译报错。9.1语法类错误函数体遗漏大括号{}或大括号不匹配形参声明格式错误多个形参未分别指定类型如int add(int x, y)函数名与 C 语言关键字重名如int int(int a)或与库函数名重复函数嵌套定义在一个函数内定义另一个函数如在main()内定义add()。9.2参数相关错误形实参不匹配实参的类型、个数、顺序与形参不一致如add(1.5, 2)传浮点型给 int 形参传参时漏写实参、多写实参或无参函数调用时括号内写了参数试图在函数头中直接初始化形参如int add(int a1, int b2)C 语言不支持。9.3返回值相关错误void类型函数书写return 数值;如void add() { return 1; }return语句后的值类型与函数头声明的返回值类型不匹配如int add() { return 3.5; }有返回值的函数未书写return语句编译器可能警告返回随机值。9.4函数调用相关错误未声明函数就直接调用函数调用在前、定义在后且无声明调用函数时拼写错误函数名如ad(1,2)代替add(1,2)有参函数调用时括号内为空未传参如add();数组传参时未传长度 / 行数导致数组遍历越界。十、函数核心总结10.1核心要素自定义函数的完整结构函数头返回值类型 函数名 形参列表 函数体{}值传递的参数传递规则形参是实参的拷贝修改形参不影响原实参与数组传参区分return语句与返回值的正确使用终止函数 返回结果void函数无返回值函数调用的语法规范普通调用 / 嵌套调用的规则有 / 无返回值的不同调用方式。10.2核心考点能独立编写自定义函数实现简单功能求和、求最大值、数组遍历 / 修改等能正确区分并使用形参和实参规避形实参不匹配的错误能灵活调用有返回值 / 无返回值函数掌握嵌套调用和链式访问的基础用法熟记stdio.h/string.h常用库函数的使用方法会引入对应头文件掌握一维 / 二维数组的传参写法理解函数内操作原数组的核心特性了解static/extern的基本用法掌握多文件开发的声明 / 定义规范。10.3编程思想代码复用思想一次定义多次调用避免重复编写相同代码减少冗余模块化编程思想单个函数实现单一功能将复杂程序拆分为多个简单的功能模块函数让程序结构清晰、便于调试和维护。十一、寄语今天关于C语言函数的讨论总结就结束了让我们不忘初心砥砺前行补充内容主文章多余示例 拓展考点 企业级规范本部分包含主文章精简下来的多余示例、大一高频易混点、static 额外特性、企业级多文件开发规范适合拔高学习和实操拓展。一、主文章多余示例迁移1. 链式访问 - 多层链式示例#include stdio.h int add(int a, int b) { return a b; } int mul(int a, int b) { return a * b; } int main() { // 先add(2,3)5 → 再mul(5,4)20 → 直接打印20 printf(结果%d, mul(add(2, 3), 4)); // 输出20 return 0; }2. 一维数组传参 - 求和示例#include stdio.h // 功能求数组和返回int类型结果 int sumArr(int arr[], int len) { int sum 0; for (int i 0; i len; i) { sum arr[i]; } return sum; } int main() { int arr[4] {1,3,5,7}; int len 4; int total sumArr(arr, len); // 接收返回值 printf(数组和%d, total); // 输出16 return 0; }二、break 与 return 的核心区别二者都是 C 语言跳转语句但作用层级、执行结果完全不同易混淆需严格区分对比维度breakreturn作用目标针对当前层循环 /switch 语句针对整个当前函数执行后流程跳出当前循环 /switch函数继续执行后续代码直接终止当前函数返回到主调函数的调用位置函数内后续代码全不执行返回值无返回值仅做跳转可带值非 void 函数必须带void 函数仅能写return;嵌套场景仅跳出最近一层循环 /switch不影响外层无视任何嵌套循环 / 函数直接结束当前函数示例对比#include stdio.h void test_break() { for (int i 0; i 3; i) { if (i 1) break; // 跳出当前循环 printf(i %d\n, i); } printf(break后函数继续执行\n); // 会执行 } void test_return() { for (int i 0; i 3; i) { if (i 1) return; // 直接终止函数 printf(i %d\n, i); } printf(return后函数不会执行\n); // 不会执行 } int main() { test_break(); test_return(); return 0; }三、static 的额外实用特性修饰局部变量static不仅能修饰全局变量 / 函数还能修饰函数内的局部变量该用法与多文件无关但开发中高频使用核心特性内存变化局部变量从栈内存转到静态内存函数调用结束后不会销毁常驻内存初始化规则仅初始化一次第一次调用函数时执行后续调用直接使用上一次的结果作用域不变仍为函数局部只能在函数内访问外部无法使用。实用示例统计函数调用次数#include stdio.h void count() { static int cnt 0; // 静态局部变量只初始化一次常驻内存 cnt; printf(函数被调用%d次\n, cnt); } int main() { count(); // 第1次调用输出1 count(); // 第2次调用输出2 count(); // 第3次调用输出3 return 0; }关键对比去掉static后cnt为普通局部变量每次调用都会重新初始化为 0输出均为 1。四、企业级多文件开发补充规范提前接轨行业标准大一阶段主要学习单文件开发但企业开发均为多文件掌握以下规范能减少多文件错误提前接轨行业标准。1. 头文件.h保护机制多文件开发中头文件可能被多个.c 文件#include导致重复声明”错误所有自定义头文件必须加保护以下为跨编译器兼容的标准写法推荐#ifndef __ADD_H__ // 若未定义该宏__文件名_H__全大写 #define __ADD_H__ // 定义宏标记头文件已被包含 // 头文件核心内容函数声明、extern变量声明、宏定义、类型声明 extern int g_num; int add(int a, int b); #endif // 结束条件判断宏名规则__文件名_H__全大写避免与其他文件冲突如sort.h对应__SORT_H__。2. .h/.c 文件严格分工头文件.h只放声明不放定义可放函数声明、extern 变量声明、宏定义、类型声明typedef/struct禁放函数实现、全局变量定义int g_num10;、static 变量 / 函数声明。源文件.c只放定义 / 实现不重复声明用#include xxx.h引用自定义头文件校验声明与实现的一致性不需要跨文件的全局变量 / 函数一律加static封装实现私有隔离。3. 全局变量使用原则全局变量尽量少用易导致程序状态混乱多个函数修改会引发难以调试的问题若必须使用全局变量优先用static封装通过接口函数实现跨文件的读写而非直接用extern修改全局变量只能定义一次放在唯一的.c 文件中避免多文件重复定义错误。4. static/extern 核心避坑点禁止用extern定义变量extern int g_num10;是错误写法赋值即定义extern仅声明static不能修饰函数参数int add(static int a);是语法错误extern不能修饰局部变量局部变量无跨文件作用域加extern无意义且报错不同.c 文件的static全局变量 / 函数可重名因为作用域仅当前文件不会冲突。五、库函数快速参考大一阶段常用库函数集中在stdio.h输入输出和string.h字符串操作熟记函数功能和头文件无需死记参数会查手册即可。5.1stdio.h 常用库函数printf(const char *format, ...)格式化输出到控制台scanf(const char *format, ...)格式化从控制台输入getchar()从控制台读取单个字符putchar(int c)向控制台输出单个字符puts(const char *s)输出字符串自动换行fgets(char *s, int size, FILE *stream)安全的字符串输入避免缓冲区溢出。5.2string.h 常用库函数strlen(const char *s)计算字符串有效长度不含结束符\0返回unsigned intstrcpy(char *dest, const char *src)将字符串src拷贝到dest需保证dest空间足够strcmp(const char *s1, const char *s2)按 ASCII 码比较两个字符串返回 0 表示相等0 表示 s1s20 表示 s1s2strcat(char *dest, const char *src)将字符串src拼接到dest末尾需保证dest空间足够。库函数使用注意使用任意库函数前必须通过#include 头文件名引入对应头文件否则编译报错。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2419589.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…