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

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

大一 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 头文件名引入对应头文件否则编译报错。

相关文章:

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

大一 C 语言函数核心总结 本文围绕 C 语言函数从基础认知到实战运用、从核心语法到避坑技巧展开,兼顾基础考点与编程思想,内容可直接用于复习和实操参考,每个核心模块仅保留 2 个典型示例,多余拓展示例文末有补充。 一、函数的基…...

计算机毕业设计之基于Spring Boot的易家宜超市云购物系统

易家宜超市云购物系统采用B/S架构,数据库是MySQL。网站的搭建与开发采用了先进的java进行编写,使用了springboot框架。该系统从两个对象:由管理员和用户来对系统进行设计构建。主要功能包括:个人信息修改,对用户、商品…...

SpringBoot 多实现类实战:告别 if-else,拥抱策略模式

在 SpringBoot 开发中,一个接口对应多个实现类是极其常见的场景,例如支付方式(微信、支付宝、银联)、通知渠道(短信、邮件、钉钉)或登录策略(密码、验证码、第三方)。如果处理不当&a…...

公务员暂停工伤保险

登录进入办理页面 暂停工伤保险适合调出、退休人员上传附件点击提交 退休选择工伤养老保险基数 公积金医疗保险基数...

着色器multi_compile笔记

概述一句multi_compile后面写若干个关键字XXX,在代码里用#if XXX条件编译一段代码。开启、关闭关键字关键字的开启关闭在材质debug界面。在Valid Keywords填的关键字如果在某句multi_compile里会自动进入Valid Keywords,否则进入Invalid。代码开启关键字…...

【愚公系列】《剪映+DeepSeek+即梦:短视频制作》007-拍摄基础:参数设置与镜头语言解析(景别与镜头运动)

💎【行业认证权威头衔】 ✔ 华为云天团核心成员:特约编辑/云享专家/开发者专家/产品云测专家 ✔ 开发者社区全满贯:CSDN博客&商业化双料专家/阿里云签约作者/腾讯云内容共创官/掘金&亚马逊&51CTO顶级博主 ✔ 技术生态共建先锋&am…...

【愚公系列】《剪映+DeepSeek+即梦:短视频制作》006-拍摄基础:参数设置与镜头语言解析(短视频的参数设置)

💎【行业认证权威头衔】 ✔ 华为云天团核心成员:特约编辑/云享专家/开发者专家/产品云测专家 ✔ 开发者社区全满贯:CSDN博客&商业化双料专家/阿里云签约作者/腾讯云内容共创官/掘金&亚马逊&51CTO顶级博主 ✔ 技术生态共建先锋&am…...

Python爬虫实战:监听前端网络流,aiohttp 极速并发抓取淘宝直播排行榜!

㊗️本期内容已收录至专栏《Python爬虫实战》,持续完善知识体系与项目实战,建议先订阅收藏,后续查阅更方便~ ㊙️本期爬虫难度指数:⭐⭐⭐ 🉐福利: 一次订阅后,专栏内的所有文章可永…...

Python爬虫实战:构建 DeviantArt 每日精选艺术作品的增量采集流水线!

㊗️本期内容已收录至专栏《Python爬虫实战》,持续完善知识体系与项目实战,建议先订阅收藏,后续查阅更方便~ ㊙️本期爬虫难度指数:⭐⭐⭐ 🉐福利: 一次订阅后,专栏内的所有文章可永…...

基于C#的工业机器人上位机控制程序开发(搭配松下PLC + MC协议)

以下是为《基于C#的工业机器人上位机控制程序开发(搭配松下PLC MC协议)》这篇文章补充的更多实用代码示例,覆盖工业现场最常遇到的功能模块。这些代码基于 .NET 8/9 自封装 MC 协议客户端,2026年主流工业做法。 1. 完整的心跳 …...

好玩又实用:C#上位机 + YOLO 实现宠物行为识别系统

好玩又实用:C#上位机 YOLO 实现宠物行为识别系统 作为一名资深铲屎官,我曾一度被这些问题困扰: 出门上班时,猫咪是在乖乖睡觉还是在疯狂拆家?狗狗是不是又在啃咬家具?想知道宠物的日常行为,却只…...

玩转Docker | 使用Docker部署PDF工具箱BentoPDF

玩转Docker | 使用Docker部署PDF工具箱BentoPDF 前言 一、BentoPDF项目介绍 BentoPDF简介 BentoPDF主要特点 二、系统要求 环境要求 环境检查 Docker版本检查 检查操作系统版本 三、部署BentoPDF服务 下载BentoPDFr镜像 创建BentoPDF容器 检查容器状态 检查BentoPDF服务端口 安…...

C程序中隐藏的数据溢出陷阱

C程序中隐藏的数据溢出陷阱 通常的规则: 当代码中对char、short等更短的类型进行算术运算时,编译器会自动将它们提升为int再进行计算。假设16位、32位无符号数类型,分别定义为UINT16、UNIT32一.计算过程溢出对16bit机器,如以下程序…...

第八届信息科学、电气与自动化工程国际学术会议(ISEAE 2026)

第八届信息科学、电气与自动化工程国际学术会议(ISEAE 2026) 2026 8th International Conference on Information Science, Electrical and Automation Engineering 时间地点:2026年4月17-19日 黑龙江省大庆市 会议官网:http:/…...

使用RISC-V IDE MRS2进行代码开发

MounRiver Studio Ⅱ(MRS2)使用了VSCode同款框架,继承VSCode代码编辑功能的基础上,还增加了一系列嵌入式开发辅助功能。【主题切换】MRS2内置多种深浅色界面配色主题,可通过工具栏快捷配置按钮来进行切换:【代码补全】在代码开发过…...

T32状态下寄存器组织、AArch32/64重要寄存器(ARM处理器架构模型——寄存器组织,中篇)

本文声明:内容来源于网络,进行整合/再创作;部分内容由AI辅助生成。T32状态下的寄存器组织Thumb状态寄存器是ARM状态的子集。注意,在Thumb状态下发生异常时,处理器自动进入ARM状态。A32与T32状态下的寄存器组织在Thumb状…...

问题整理清单

问题整理清单 请问模版匹配这个HHandle 这个句柄 序列化之前和序列化之后不一样呢 ?“HALCON error #2404: Invalid handle type in operator do_ocr_multi_class_cnnpython训练出来的结果预测之后的结果很对,但是一到C#上面就不行了什么是LinuxCNC...

【Dv3Admin】FastCRUD MD编辑器操作

富文本字段和 Markdown 字段在后台表单里的问题,本质上很像,真正麻烦的都不是“能不能挂进去”,而是挂进去以后尺寸、回显、校验和展示边界是否稳定。放到 md-editor-v3 之后,最常见的问题通常集中在编辑区高度不合适、宽度被表单…...

【C++】左值引用、右值引用

目录 一、右值引用的意义 二、基础:理解左值与右值 1. 左值(Lvalue,Locator Value) 常见的左值场景: 2. 右值(Rvalue,Read Value) 2.1 纯右值(prvalue)…...

Tower I3C Host Adapter 使用范例 (20)

Easyi3C是一家领先的嵌入式系统工具供应商,可简化各种通信协议的开发和调试。公司提供一系列产品,旨在帮助工程师和开发人员更高效地使用 I3C、I2C等协议。 基于Tower I3C Host Adapter 测试DDR5 RCD (4) 一 DDR5 RCD I3C背景介绍 在高性能计算和服务器…...

Qt进程间通信

QSharedMemory 共享内存(Shared Memory)是一种进程间通信(Inter-Process Communication, IPC)机制,允许多个进程共享同一块内存区域。共享内存提供了高效的数据交换方式,适用于需要频繁传递大量数据的场景。…...

Hive数仓分区设计与更新操作指南

目录 一、Hive 分区概述 1.1 分区的核心作用 1.2 分区的本质示例 二、分区设计原则 2.1 分区字段选择原则 2.2 分区粒度与数量控制 2.3 分区设计常见误区 三、分区表的创建 3.1 静态分区表 3.1.1 创建静态分区表 3.1.2 向静态分区表插入数据 3.2 动态分区表 3.2.1 …...

2026年最新免费5S管理系统盘点!盘点10个免费的5S系统!

在2026年制造业数字化转型的关键节点,寻找一套高效且低成本的5S管理系统已成为众多中小企业的迫切需求。面对市场上繁杂的软件选择,如何精准定位到真正的免费5S系统?本文为您带来2026年最新免费5S管理系统盘点,深度剖析当前市场格…...

一、STM32入门

用的是正点原子STM32F103MINI、JLINK v8 1.准备工作 1.1手册 1.1.1数据手册 STM32F103RCT6 开发板各个元件的特性。 1.1.2参考手册 在逻辑层面上,如何利用STM32F10X开发板各个部位的特性实现各种功能。 1.1.3厂家的学习开发手册 具体厂家设计的代码层面的如何学…...

《UNIX高级环境编程》第十三章 守护进程(一文读懂UNIX下守护进程)

一、守护进程的特征守护进程是一种生命周期较长的进程,常常在系统启动时被运行,在系统关闭时终止,并且没有关联的终端设备,是一个后台进程。一个系统中,父进程ID为0的一般是内核进程。进程1通常是init进程,…...

杰理AC695N/AC696N歌词回调

想要连接蓝牙播放音乐显示歌词杰理的SDK已经做好封装了, 等待我们去调用就可以了, ac695n和ac696n的sdk调用方法都一样下面开始还有一点最重要的是下面这个宏必须要打开, 最后连接蓝牙播放音乐就能在日志打印中看到歌词的回调了还有一个做法是可以把A2DP的这个宏关掉, 然后就可…...

配置中心的作用?Nacos 配置中心原理?

一句话回答:配置中心的作用,就是把分散在各个服务里的配置统一集中管理,并支持动态推送和环境隔离,避免每次改配置都去改代码、重启服务。 Nacos 官方也把自己定位成“动态配置服务”,强调配置的中心化、外部化和动态化…...

NPM Script 实战:常用命令设计与封装|Vue 工程化篇

【NPM Script】Vue 前端工程化实操:从核心封装逻辑到落地,彻底搞懂 npm run 常用命令最佳写法,避开端口占用、环境变量、多环境构建高频坑! 📑 文章目录 开篇一、NPM Script 是什么?为什么用它&#xff1f…...

KMP算法之 next 数组的计算

/*** brief 计算模式串的next数组(部分匹配表),并可视化计算过程* param pattern 模式串(待查找的基因片段)* param next 输出参数:存储next数组(长度需≥模式串长度)*/ void kmp_ge…...

发电机组并网技术研究

一、概述在现代电力供应体系中,柴发机组作为应急电源或后备电源,是应对市电中断、用电高峰负荷及特殊场景电力需求,保障电力持续、稳定供应的关键核心设备,其典型应用系统如下图1所示(图1:柴发机组典型供电…...