函数的基础知识与应用

📅 2026/7/18 3:40:02
函数的基础知识与应用
函数基本用法1.1 定义和三要素函数是完成特定功能的代码模块其程序代码独立可以有返回值也可以为空值。函数三要素功能函数要实现的功能。参数函数声明和函数调用时定义的变量用于传递信息给函数。参数分为实参和形参形参函数定义时声明的参数只是一个形式上的符号名称。实参函数调用时实际传递给函数的参数值。函数的调用过程就是用形参接收实参的过程。返回值函数调用后留下的右值右值只能放在运算符右边。1.2 函数声明和定义1.2.1 函数声明存储类型 数据类型 函数名(数据类型 形参1, 数据类型 形参2, ...);1.2.2 函数定义格式存储类型 数据类型 函数名(数据类型 形参1, 数据类型 形参2, ...) { 函数要执行的代码; }其中函数名称是一个标识符要符合标识符的命名规则。数据类型是整个函数的返回值类型如果无返回值应该写为 void 类型。形式参数是逗号分隔的多个变量的形式说明通常简称为形参。因为形参只有在函数调用的过程中才实例化才分配内存单元所以就叫形式参数。函数体大括号对 {执行的语句}里面语句序列是大于等于零个语句构成的。注意在函数体中表达式语句里面使用的变量必须事先已有说明前面定义了。return 后面加表达式语句中表达式的值和函数的数据类型保持一致。总结函数的数据没有参数参数列表可以省略也可以用 void。没有返回值数据类型为 void函数内没有 return 语句。有返回值要根据返回值的数据类型定义函数的数据类型返回值可以通过 return 语句返回。定义位置定义函数时可以直接在主函数上面定义如果在主函数下面的话需要在上面提前声明。void 函数类型为 void 可以用 return; 来结束函数。1.3 函数调用没有返回值直接调用即可函数名(实参);有返回值如果需要接受返回值就定义和返回值同类型的变量来接受函数内肯定是通过 return 语句返回返回值的。如果不需要接受返回值则直接调用即可。实参在函数调用时传递的参数函数名后面括号中的数据称为实参是我们真实传递给函数的数值实参可以是常量、变量、表达式、函数调用结果等。#include stdio.h // 无参数无返回值 void fun() { printf(hello word\n); } // 无返回值有参数 void add(int a, int b) { printf(%d\n, a b); } // 有参数也有返回值 int j(int a, int b) { return a b; } int main(int argc, char const *argv[]) { int a 10, b 30; fun(); // 遇见函数的调用程序会进入函数内执行函数内的代码结束后再回到调用的位置往后执行后面代码 add(a, b); // 40将a里面的10和b里面的30传递给函数的形参了 add(a 2, b 3); // 把表达式的值传递给函数 int n j(a, b); printf(%d\n, n); printf(%d\n, j(a, b)); printf(%d\n, j(a 2, b * 3)); return 0; }1.4 函数传参1.4.1 值传递单向传递将实参传递给形参使用改变形参实参不会收到影响形参和实参本身就是不同的空间。#include stdio.h void fun(int a) // a 1 { a 100; // 修改形参a不会影响到主函数的n } int main(int argc, char const *argv[]) { int n 1; fun(n); /* 函数调用逻辑就类似于 int a n; a 100; */ printf(%d\n, n); // 输出1 return 0; }1.4.2 地址传递双向传递在函数通过地址修改地址所指向的空间中的内容实参就会随之变化。#include stdio.h void fun(int* a) // a n { *a 100; // *a *n n } int main(int argc, char const *argv[]) { int n 1; fun(n); /* 函数调用的逻辑类似于: int *a n; *a 100; // 相当于 n 100 */ printf(%d\n, n); // 输出100 return 0; }1.4.3 数组传递和地址传递一样参数中存在数组的地址也是指针。#include stdio.h void fun(int *p) { p[2] 100; // *(p 2) 100 } int main(int argc, char const *argv[]) { int a[5] {0}; int *p a; fun(p); for (int i 0; i 5; i) printf(%d , a[i]); // 输出0 0 100 0 0 printf(\n); return 0; }1.5 函数和栈区1.5.1 栈区的概念栈用来存储函数内部的变量包括 main() 函数。它是一个 FILOFirst In Last Out先进后出的结构。每当一个函数声明一个新的变量它将被压入栈中。当一个函数运行结束后这个函数所有在栈中相关的变量都将被删除而且它们所占用的内存将会被释放。这就产生了函数内部的局部变量。栈区是一段非常特殊的内存区它由 CPU 自动管理所以你不必手动申请和释放内存。1.5.2 栈区(stack)的总结栈由 CPU 管理无法修改变量自动地分配和释放栈并非没有限制大部分栈都有一个上边界栈随着变量地产生和销毁生长和收缩栈区变量只有在函数创建它们的时候存在堆区(heap)空间2.1 堆区概念申请的空间分为五种栈区、堆区、全局区、常量区、代码区。堆区特点由我们也就是程序员手动的申请和释放。堆和栈的主要区别有栈由系统自动分配而堆是人为申请开辟栈获得的空间较小而堆获得的空间较大栈由系统自动分配速度较快而堆一般速度比较慢栈是连续的空间而堆是不连续的空间是随机分配的。2.2 malloc 函数2.2.1 定义用 man 手册查看#include stdlib.h void *malloc(size_t size); 功能在堆区开辟大小为 size 的空间 参数size: 开辟空间的大小单位字节 返回值 成功返回开辟空间的首地址 失败NULL; 注意malloc() 要和 free() 搭配使用#include stdio.h #include stdlib.h int main(int argc, char const *argv[]) { int *p (int *)malloc(sizeof(int) * 5); if (p NULL) printf(开辟失败\n); else printf(开辟成功\n); for (int i 0; i 5; i) scanf(%d, pi); for (int i 0; i 5; i) printf(%d , p[i]); putchar(10); return 0; }注意malloc内参数是动态分配的字节数不是元素个数。2.3 free函数定义#include stdlib.h void free(void *ptr); 功能释放之前调用 calloc、malloc 或 realloc 所分配的内存空间。 参数ptr:堆区空间首地址 返回值无可以释放完堆区空间之后赋值为控制指针free(p);pNULL#include stdio.h #include stdlib.h int main(int argc, char const *argv[]) { int *p (int *)malloc(sizeof(int) * 5); if (p NULL) printf(开辟失败\n); else printf(开辟成功\n); for (int i 0; i 5; i) scanf(%d, pi); for (int i 0; i 5; i) printf(%d , p[i]); putchar(10); free(p); p NULL; return 0; }注意1.手动开辟堆区空间要注意内存泄漏当指针指向开辟堆区空间后又对指针重新赋值则没有指针指向开辟的堆区空间就会造成内存泄漏。2.使用完堆区空间后及时释放空间例如char *p (char *)malloc(32 * sizeof(char)); // p hello; //成了又指向了常量区堆区找不到了输入常量区会段错误 scanf(%s, p); printf(%s\n, p); free(p); p NULL;修改去掉p hello;直接写入到开辟的堆区空间2.4在函数中开辟堆区空间思考如下代码输出结果#include stdio.h #include stdlib.h #include string.h void fun(char *p) //pNULL { p (char *)malloc(32); //修改p不会影响到主函数的m strcpy(p, hello); } int main(int argc, char const *argv[]) { char *m NULL; fun(m); //函数调用后,m还是NULL /* 函数调用逻辑类似于 char *pm; pmalloc(); */ printf(%s\n, m); return 0; }会报段错误原因是函数执行完栈区会被释放函数内修改形参p不会影响到主函数的m的所以函数调用后m还是指向空。解决方法1通过返回值通过返回值保存开辟空间的首地址#include stdio.h #include stdlib.h #include string.h char *fun() { char *p (char *)malloc(32); strcpy(p, hello); return p; } int main(int argc, char const *argv[]) { char *a fun(); printf(%s\n, a); free(a); a NULL; return 0; }方法2通过传递二级指针#include stdio.h #include stdlib.h #include string.h void fun(char **p) //pm { *p (char *)malloc(32); //*p*mm strcpy(*p, hello); } int main(int argc, char const *argv[]) { char *m NULL; fun(m); /* 函数调用的逻辑相当于: char **pm; *pmalloc(); */ printf(%s\n, m); return 0; }