相关文章链接 :
1.【嵌入式开发】C语言 指针数组 多维数组
2.【嵌入式开发】C语言 命令行参数 函数指针 gdb调试
3.【嵌入式开发】C语言 结构体相关 的 函数 指针 数组
4.【嵌入式开发】gcc 学习笔记(一) - 编译C程序 及 编译过程
5.【C语言】 C 语言 关键字分析 ( 属性关键字 | 常量关键字 | 结构体关键字 | 联合体关键字 | 枚举关键字 | 命名关键字 | 杂项关键字)
6.【C 语言】编译过程 分析 ( 预处理 | 编译 | 汇编 | 链接 | 宏定义 | 条件编译 | 编译器指示字 )
7.【C 语言】指针 与 数组 ( 指针 | 数组 | 指针运算 | 数组访问方式 | 字符串 | 指针数组 | 数组指针 | 多维数组 | 多维指针 | 数组参数 | 函数指针 | 复杂指针解读)

  • 一. 函数本质

    • 1. 函数意义

      • (1) 函数来源
      • (2) 模块化程序设计
    • 2. 面向过程的程序设计
      • (1) 程序结构
    • 3. 函数的声明和定义
      • (1) 声明 和 定义 的区别
      • (2) 代码示例 ( 函数 声明 和 定义区别 )
  • 二. 参数 可变参数 顺序点 类型缺省认定
    • 1. 函数参数

      • (1) 参数分析
      • (2) 代码示例 ( 函数参数 求值顺序 )
    • 2. 程序中的顺序点
      • (1) 顺序点简介
    • 3. C 语言 函数 的 缺省认定
      • (n) 标题3
    • 4.可变参数 的 定义 和 使用
      • (1) 简介
      • (2) 代码示例 ( 定义 使用 可变参数 )
  • 三. 函数 与 宏
    • 1. 函数 与 宏 对比案例

      • (1) 函数 和 宏 的案例
    • 2. 函数 和 宏 的分析
      • (1) 函数 和 宏 分析
    • 3. 函数 与 宏 的 利弊
      • (1) 宏 优势 和 弊端
      • (2) 函数 的 优势 和 弊端
      • (3) 宏的无可替代性
    • 4. 总结
      • (1) 宏 定义 和 函数 总结
  • 四. 函数的调用约定
    • 1. 函数的活动记录 分析

      • (1) 函数的活动记录
    • 2. 函数的调用约定概述
      • (1) 参数入栈 问题描述
      • (2) 参数传递顺序的调用约定
  • 五. 函数设计技巧

一. 函数本质

1. 函数意义

(1) 函数来源


C 程序结构 由 数据 和 函数 组成;

函数是由汇编跳转发展而来的 :

  • 1.汇编操作 : 汇编语言中由一系列的指令组成, 这些指令从上到下顺序执行,
  • 2.跳转操作 : 汇编中需要做分支循环操作的时候, 就是使用跳转指令;
  • 3.指令代码模块 : 在汇编中有一组指令代码, 总是需要执行这一组代码, 需要时跳转到该代码处执行, 执行完毕后在跳转回去, 这就是一个函数的雏形;
  • 4.发展 : 跳转过来 和 跳转回去 相当于函数的 入栈 和 出栈;

(2) 模块化程序设计


模块化程序设计 :

  • 1.思想 : 复杂问题拆解, 将一个复杂问题拆解成一个个的简单问题, 这些简单问题就可以作为一个个的函数来编写;
  • 2.C语言程序 : 将一个复杂的程序拆解成一个个模块 和 库函数;

一个复杂的 C 语言程序有几十上百万行代码, 这些代码可以分解成若干模块来实现, 即分解成一个个的函数来实现.


2. 面向过程的程序设计

(1) 程序结构


面向过程程序设计思想 :

  • 1.中心 : 整体的设计 以 过程 为中心;
  • 2.问题分解 : 将复杂问题分解为若干容易解决的问题;
  • 3.函数体现 : 面向过程 的思想在 C 语言 中的核心就是 函数;
  • 4.分解函数 : 复杂问题 分解后的过程可以分为一个个函数一步步实现;

3. 函数的声明和定义

(1) 声明 和 定义 的区别


声明和定义的区别 :

  • 1.声明 : 程序中 声明 只是告诉编译器 某个 实体 存在, 这个实体可以是 变量 或者 函数 等;
  • 2.定义 : 程序中定义 指的就是 某个实体 ( 函数 或 变量 ) 的实际意义;

在 test_1.c 中定义变量 int i = 10; 这是定义了 int 类型的变量, 需要为该变量分配内存空间;
在 test_2.c 中声明变量 extern int i; 这是声明了 int 类型的变量, 变量定义在了别的文件中, 不必为该变量分配内存空间;


(2) 代码示例 ( 函数 声明 和 定义区别 )


代码示例 :

  • 1.代码 test_1.c :
#include <stdio.h>//声明 : 声明外部变量, 该值是在其它文件中定义的
extern int global_int;//声明 : 声明函数 plus, 该函数定义在下面
int plus(int i, int j);int main()
{//声明 : 声明函数 square, 如果不声明编译时会报错, 该声明只在 main 函数中有效果, 在main函数之外使用该方法就会报错int square(int i);//使用函数 square, 如果没有声明, 编译会报错global_int = 3;printf("%d\n", square(global_int));//使用函数 plus, 如果没有声明编译会报错printf("%d\n", plus(1, 2));return 0;
}//定义 : 定义函数 plus
int plus(int i, int j)
{return i + j;
}//定义 : 定义函数 square
int square(int i)
{return i * i;
}
  • 2.代码test_2.c :
//定义 : 定义变量, 在这里需要为变量分配内存空间
int global_int;
  • 3.编译运行结果 :

二. 参数 可变参数 顺序点 类型缺省认定

1. 函数参数

(1) 参数分析


函数参数分析 :

  • 1.本质 : 函数参数的本质 与 局部变量 基本相同, 这两种数据都存放在栈空间中 ( 中间隔着 返回地址 寄存器 EBP 数据 ) 详情参考上一篇博客内存管理 ;
  • 2.参数值 : 函数调用的 初始值 是 函数调用时的实参值 ;

函数参数的求值顺序 (盲点) :

  • 1.实现 : 函数参数的求值顺序 依赖 编译器的实现;
  • 2.操作数顺序没有在规范中 : C 语言规范中没有规定函数参数必须从左到右进行计算赋值;
  • 3.运算符编程注意点 : C语言中大多数的运算符的操作数求值顺序也是不固定的, 依赖于编译器的实现;
  • 4.示例 : 如 int ret = fun1() * fun2(); fun1 和 fun2 函数哪个先执行, 哪个后执行 不一定;

编程时尽量不要编写的代码依赖于操作数的实现顺序;


(2) 代码示例 ( 函数参数 求值顺序 )


代码示例 :

  • 1.代码 :
#include <stdio.h>int fun(int i, int j)
{printf("%d, %d\n", i, j);
}int main()
{int m = 1;fun(m, m ++);printf("%d\n", i);/*打印出来的结果是 2, 1 \n 2分析 : 函数的参数的求值顺序 不是 从左到右的, 是不固定的这个顺序是编译器制定的, 不同编译器该顺序不同*/return 0;
}
  • 2.编译运行结果 :

分析 :
函数参数计算说明 : fun(m, m ++); 进入函数体之前先计算 m 和 m++ 的值, m 和 m++ 是实参, 在计算完成之后才赋值给 i 和 j 形参;
顺序点 : 在进入函数体前是一个顺序点, 需要将计算完毕的实参 赋值给形参;
实参 m 赋值 : 赋值给 形参 i, 此处已经到达顺序点, m 自增操作已经反映到内存中, 因此 从 内存中获取的 i 的值是 2;
实参 m++ 赋值 : 赋值给 形参 j, m++ 表达式的计算结果是 1, 因此 j 的值是1;


2. 程序中的顺序点

(1) 顺序点简介


顺序点介绍 :

  • 1.顺序点位置 : 顺序点存在于程序之中;
  • 2.顺序点定义 : 顺序点是 代码 执行过程中, 修改变量值 的 最晚时刻 ;
  • 3.顺序点操作 : 程序运行到顺序点时, 之前的代码操作 都要反映到后续访问中 ;

顺序点列举 :

  • 1.表达式结束 : 每个表达式结束都是顺序点, 以分号 “;” 结尾, 每个分号的位置都是顺序点;
  • 2.某些表达式的运算对象计算 : &&, || (逻辑运算), ? :(三目运算符), 逗号 表达式 中每个 运算对象计算后 是顺序点;
  • 3.函数运行前 : 函数调用并且在执行函数体之前, 所有实际参数求值完之后是一个顺序点, 如参数是表达式, 需要将表达式计算出结果;

顺序点代码示例 :

#include <stdio.h>int fun(int i, int j)
{printf("%d, %d\n", i, j);
}//注意 : 这个知识点可能过时, k = k++ + k++; 在 Ubuntu 中执行结果是 5int main()
{//顺序点 : 在 k = 2; 表达式以分号结束, 这是一个顺序点int k = 2;int a = 1;/*顺序点 : 分号结尾处是顺序点, 该顺序点第 1 个 k++, 计算时 k 先是 2, 自增操作到顺序点时执行; 第 2 个 k++, 计算时 k 还是 2, 自增操作到顺序点时执行;加法计算完毕后 k 变成 4, 两次自增后变为 6*/k = k++ + k++;printf("k = %d\n", k);/*a-- && a 进行逻辑运算, 其中 && 是顺序点, a-- 在 && 时执行 自减操作, 然后 a-- 结果变成了 0, a 的值也变成了 0, 进行逻辑与操作结果为 0 */printf("a--&&a = %d\n",a--&&a);return 0;
}

3. C 语言 函数 的 缺省认定

(n) 标题3


函数缺省认定简介 :

  • 1.描述 : C 语言中 默认 没有类型的 参数 和 返回值 为 int 类型;
  • 2.举例 :
fun(i)
{return i
}

等价于

int fun(int i)
{return i;
}
  • 3.代码示例 :
#include <stdio.h>//函数缺省认定 : 没有类型的 参数 和 返回值 为 int 类型
fun(i, j)
{return i + j;
}int main()
{printf("fun(i, j) = %d\n",fun(3, 3));return 0;
}


4.可变参数 的 定义 和 使用

(1) 简介


可变参数简介 :

  • 1.描述 : 函数可以接收的参数个数是不定的, 根据调用的需求决定有几个参数;
  • 2.依赖头文件 : 如果要使用可变参数, 需要导入 stdarg.h 头文件;
  • 3.核心用法 : va_list, va_start, va_end, va_arg 配合使用, 访问可变参数值;

可变参数示例 :

  • 1.函数名相同, 参数个数不同 : open 函数, 有两种用法, 一个有 2 个参数 int open(const char *pathname, int flags) , 一个有三个参数 int open(const char *pathname, int flags, mode_t mode) , C 语言中明显没有重载, 这里是用可变参数来实现的 ; 使用 man 2 open 命令查看 open 函数的文档;

可变参数的注意点 :

  • 1.取值必须顺序进行 : 读取可变参数的值时, 必须从头到尾按照前后顺序读取, 不能跳过任何一个参数;
  • 2.必须确定1个参数 : 参数列表中必须有一个命名确定的参数;
  • 3.可变参数数量无法确定 : 使用 va_arg 获取 va_list 中的值时, 无法判断实际有多少个参数;
  • 4.可变参数类型无法确定 : 使用 va_arg 获取 va_list 中的值时, 无法判断某个参数是什么类型的;

依次读取可变参数时, 注意 可变参数 的 数量 和 类型, 每个位置的参数 是 什么类型, 一定不要读取错误, 否则会产生不可预测的后果;


(2) 代码示例 ( 定义 使用 可变参数 )


代码示例 :

  • 1.代码 :
#include <stdio.h>
#include <stdarg.h>/*定义可变参数 : ① 列出第一个参数 int a② 使用 ... 表明后面有 个数不定 并且 类型不定 的 参数
*/
double avg(int arg_count, ...)
{va_list args;int i = 0;      //循环控制变量double sum = 0; //统计参数之和//初始化列表, 让列表准备取值va_start(args, arg_count);for(i = 0; i < arg_count; i ++){//从可变参数列表中获取数据, 数据类型是 int 类型sum = sum + va_arg(args, int);}//结束使用可变参数列表va_end(args);return sum / arg_count;
}int main()
{//使用定义了可变参数的函数, 传入 11 个参数printf("%f\n", avg(10, 1, 2, 3, 4, 5 , 6, 7, 8, 9, 10));//使用定义了可变参数的函数, 传入 4 个参数printf("%f\n", avg(3, 444, 555, 666));return 0;
}
  • 2.编译运行结果 :

三. 函数 与 宏

1. 函数 与 宏 对比案例

(1) 函数 和 宏 的案例


代码示例 : 分别使用 函数 和 宏 将数组数据清零;

  • 1.代码 :
#include <stdio.h>/*定义宏 : 这个宏的作用是将 p 目前是 void* 类型, 转为 char* 类型, 将后将每个字节的内容都设置为 0
*/
#define RESET(p, len) while(len > 0) ((char*)p)[--len] = 0;/*定义函数 : 也是将 p 指向的 len 字节的内存置空
*/
void reset(void* p, int len)
{while(len > 0){((char*)p)[--len] = 0;}
}int main()
{//1. 定义两个数组, 用函数 和 宏 不同的方式重置数据int array1[] = {1, 2, 3};int array2[] = {4, 5, 6, 7};//2. 获取两个数组大小int len1 = sizeof(array1);int len2 = sizeof(array2);//3. 定义循环控制变量int i = 0;//4. 打印两个数组处理前的数据printf("打印array1 : \n");for( i = 0; i < 3; i ++){printf("array1[%d] = %d \n", i, array1[i]);}printf("打印array2 : \n");for( i = 0; i < 4; i ++){printf("array2[%d] = %d \n", i, array2[i]);}//5. 使用宏的方式处理数组1RESET(array1, len1);//6. 使用函数的方式处理数组2reset(array2, len2);//7. 打印处理后的数组printf("打印处理后的array1 : \n");for( i = 0; i < 3; i ++){printf("array1[%d] = %d \n", i, array1[i]);}printf("打印处理后的array2 : \n");for( i = 0; i < 4; i ++){printf("array2[%d] = %d \n", i, array2[i]);}return 0;
}
  • 2.编译运行结果 :

虽然看起来 函数 和 宏实现了相同的功能, 但是它们有很大的区别;


2. 函数 和 宏 的分析

(1) 函数 和 宏 分析


函数 和 宏 分析 :

  • 1.宏处理 : 宏定义是在预处理阶段直接进行宏替换, 代码直接复制到宏调用的位置, 由于宏在预处理阶段就被处理了, 编译器是不知道宏的存在的;
  • 2.函数处理 : 函数是需要编译器进行编译的, 编译器有决定函数调用行为的义务;
  • 3.宏的弊端 ( 代码量 ) : 每调用一次宏, 在预处理阶段都要进行一次宏替换, 会造成代码量的增加;
  • 4.函数优势 ( 代码量 ) : 函数执行是通过跳转来实现的, 代码量不会增加;
  • 5.宏的优势 ( 效率 ) : 宏 的执行效率 高于 函数, 宏定义是在预编译阶段直接进行代码替换, 没有调用开销;
  • 6.函数的弊端 ( 效率 ) : 函数执行的时候需要跳转, 以及创建对应的活动记录( 栈 ), 效率要低于宏;

3. 函数 与 宏 的 利弊

(1) 宏 优势 和 弊端


宏的优势和弊端 : 宏的执行效率要高于函数, 但是使用宏会有很大的副作用, 非常容易出错, 下面的例子说明这种弊端;

代码示例 :

  • 1.代码 :
#include <stdio.h>#define ADD(a, b) a + b
#define MUL(a, b) a * b
#define _MIN_(a, b) ((a) < (b) ? (a) : b)int main()
{int a = 1, b = 10;//宏替换的结果是 : 2 + 3 * 4 + 5, 最终打印结果是 19printf("%d\n", MUL(ADD(2, 3), ADD(4, 5)));//宏替换的结果是 ((a++) < (b) ? (a++) : b), 打印结果是 2printf("%d\n", _MIN_(a++, b));return 0;
}
  • 2.编译运行结果 :
  • 3.查看预编译文件 : 使用 gcc -E test_1.c -o test_1.i 指令, 将预编译文件输出到 test_1.i 目录中; 下面是预编译文件的一部分 ;
int main()
{int a = 1, b = 10;printf("%d\n", 2 + 3 * 4 + 5);printf("%d\n", ((a++) < (b) ? (a++) : b));return 0;
}

(2) 函数 的 优势 和 弊端


函数的优缺点 :

  • 1.函数优势 : 函数调用需要将实参传递给形参, 没有宏替换这样的副作用;
  • 2.弊端 ( 效率低 ) : 函数执行需要跳转, 同时也需要建立活动对象对象 ( 如 函数栈 ) 来存储相关的信息, 需要牺牲一些性能;

(3) 宏的无可替代性


宏 定义 优势 :

  • 1.宏参数不限定类型 : 宏参数 可以是 任何 C 语言 的实体类型, 如 int, float, char, double 等;
  • 2.宏参数可以使类型名称 : 类型的名称也可以作为宏的参数;
//宏定义 : 实现分配 n 个 type 类型空间, 并返回 type 类型指针
#define MALLOC(type, n) (type*)malloc(n * sizeof(type))//分配 5 个 float 大小的动态空间, 并将首地址存放在 指针 p 中;
float *p = MALLOC(int, 5);

4. 总结

(1) 宏 定义 和 函数 总结


宏定义 和 函数 小结 :

  • 1.宏定义 : 宏 的 参数 可以 是 C 语言中 的 任何类型的 ( 优势 ) , 宏的执行效率 高 ( 优势 ), 但是容易出错 ( 弊端 );
  • 2.函数 : 函数 参数 的 类型是固定的, 其 执行效率低于宏, 但是不容易出错;
  • 3.宏定义 和 函数之间的关系 : 这两者不是竞争对手, 宏定义可以实现一些函数无法实现的功能;

四. 函数的调用约定

1. 函数的活动记录 分析

(1) 函数的活动记录


活动记录概述 : 函数调用时 将 下面一系列的信息 记录在 活动记录中 ;

  • 1.临时变量域 : 存放一些运算的临时变量的值, 如自增运算, 在到顺序点之前的数值是存在临时变量域中的;

    后置操作 自增 原理 : i++ 自增运算 进行的操作 :
    ( 1 ) 生成临时变量 : 在内存中生成临时变量 tmp ;
    ( 2 ) 临时变量赋值 : 将 i 的值赋值给临时变量, tmp = i ;
    ( 3 ) 进行加 1 操作 : 将 i + 1 并赋值给 i;

    示例 : 定义函数 fun(int a, int b), 传入 fun(i, i++), 传入后 获取的实参值分别是 2 和 1;
    在函数传入参数达到顺序点之后开始取值, 函数到达顺序点之后, 上面的三个步骤就执行完毕, 形参 a 从内存中取值, i 的值是2, 形参 b 从临时变量域中取值, 即 tmp 的值, 取值是 1;

  • 2.局部变量域 : 用于存放 函数 中定义 的局部变量, 该变量的生命周期是局部变量执行完毕;

  • 3.机器状态域 : 保存 函数调用 之前 机器状态 相关信息, 包括 寄存器值 和 返回地址, 如 esp 指针, ebp 指针;
  • 4.实参数域 : 保存 函数的实参信息 ;
  • 5.返回值域 : 存放 函数的返回值 ;

2. 函数的调用约定概述

(1) 参数入栈 问题描述


参数入栈问题 : 函数参数的计算次序是不固定的, 严重依赖于编译器的实现, 编译器中函数参数入栈次序;

  • 1.参数传递顺序 : 函数的参数 实参传递给形参 是从左到右传递 还是 从右到左传递;
  • 2.堆栈清理 : 是函数的调用者清理 还是 由 函数本身清理 ;

参数入栈 栈维护 问题示例 :

  • 1.多参数函数定义 : 定义一个函数 fun(int a, int b, int c) , 其中有 3 个参数;
  • 2.函数调用 : 当发生函数调用时 fun(1, 2, 3), 传入三个 int 类型的参数, 这三个参数肯定有一个传递顺序, 这个传递顺序可以约定;
    • ( 1 ) 从左向右入栈 : 将 1, 2, 3 依次 传入 函数中 ;
    • ( 2 ) 从右向左入栈 : 将 3, 2, 1 依次 传入 函数中 ;
  • 3.栈维护 : 在 fun1() 函数中 调用 fun2() 函数, 会创建 fun2() 函数的 活动记录 (栈), 当 fun2() 函数执行完毕 返回的时候, 该 fun2 函数的栈空间是由谁 ( fun1 或 fun2 函数 ) 负责释放的;

函数参数计算次序依赖于编辑器实现, 函数参数入栈的顺序可以自己设置;


(2) 参数传递顺序的调用约定


函数参数调用约定 :

  • 1.函数调用行为 : 函数调用时 参数 传递给 被调用的 函数, 返回值被返回给 调用函数 ;
  • 2.调用约定作用 : 调用约定 是 用来规定 ① 参数 是通过什么方式 传递到 栈空间 ( 活动记录 ) 中, ② 栈 由谁来 清理 ;
  • 3.参数传递顺序 ( 右到左 ) : 从右到左入栈使用 __stdcall, __cdecl, __thiscall 关键字, 放在 函数返回值之前;
  • 4.参数传递顺序 ( 左到右 ) : 从左到右入栈使用 __pascal, __fastcall 关键字, 放在 函数返回值之前;
  • 5.调用堆栈的清理工作 : ① 调用者负责清理调用堆栈; ② 被调用的函数返回之前清理堆栈;

五. 函数设计技巧


函数设计技巧 :

  • 1.避免使用全局变量 : 在函数中尽量避免使用全局变量, 让函数形成一个独立功能模块;
  • 2.参数传递全局变量 : 如果必须使用到全局变量, 那么多设计一个参数, 用于传入全局变量;
  • 3.参数名称可读性 : 尽量不要使用无意义的字符串作为参数变量名;
  • 4.参数常量 : 如果参数是一个指针, 该指针仅用于输入作用, 尽量使用 const 修饰该指针参数, 防止该指针在函数体内被修改;
//这里第二个参数仅用于输入, 不需要修改该指针, 那么就将该参数设置成常量参数
void fun(char *dst, const char* src); 
  • 5.返回类型不能省略 : 函数的返回类型不能省略, 如果省略了返回值, 那么返回值默认 int;
  • 6.参数检测 : 在函数开始位置, 需要检测函数参数的合法性, 避免不必要的错误, 尤其是指针类型的参数;
  • 7.栈内存指针 : 返回值 绝对不能是 局部变量指针, 即 指针指向的位置是 栈内存位置, 栈内存在返回时会销毁, 不能再函数运行结束后使用 ;
  • 8.代码量 : 函数的代码量尽量控制在一定数目, 50 ~ 80 行, 符合模块化设计规则;
  • 9.输入输出固定 : 函数在输入相同的参数, 其输出也要相同, 尽量不要在函数体内使用 static 局部变量, 这样函数带记忆功能, 增加函数的复杂度;
  • 10.参数控制 : 编写函数的时候, 函数的参数尽量控制在 4 个以内, 方便使用;
  • 11.函数返回值设计 : 有时候函数不需要返回值, 或者返回值使用指针参数设置, 但是为了增加灵活性, 可以附加返回值; 如 支持 链式表达式 功能;

【C 语言】C 语言 函数 详解 ( 函数本质 | 顺序点 | 可变参数 | 函数调用 | 函数活动记录 | 函数设计 ) [ C语言核心概念 ]相关推荐

  1. python什么是可变参数_详解Python的三种可变参数

    可变参数 可变参数应该最简单,在C/C++和Java等语言中都有,就是用*号来表示,例如 def testArg(*arg) 你可以传入任意多个元素(包括0)到参数中,在函数内部会自动认为是一个元组或 ...

  2. python中什么是可变参数_详解Python的三种可变参数

    详解Python的三种可变参数 可变参数 可变参数应该最简单,在C/C++和Java等语言中都有,就是用*号来表示,例如 def testArg(*arg) 你可以传入任意多个元素(包括0)到参数中, ...

  3. execvp函数详解_如何在C / C ++中使用execvp()函数

    execvp函数详解 In this article, we'll take a look at using the execvp() function in C / C++. 在本文中,我们将介绍如 ...

  4. php7 $_files函数,***PHP $_FILES函数详解 + PHP文件上传 move_uploaded_file() 参数的正确写法...

    PHP $_FILES函数详解 在PHP中上传一个文件建一个表单要比ASP中灵活得多.具体的看代码. 如: 复制代码代码如下: 然后upload.php中可以直接用 $_FILES $_POST $_ ...

  5. python可变参数的实验性_详解Python的三种可变参数

    可变参数 可变参数应该最简单,在C/C++和Java等语言中都有,就是用*号来表示,例如 def testArg(*arg) 你可以传入任意多个元素(包括0)到参数中,在函数内部会自动认为是一个元组或 ...

  6. python求和函数详解_关于python:对多个数字求和的函数

    本问题已经有最佳答案,请猛点这里访问. 我刚接触到Python,开始学习执行函数.我开始添加数字,但我只能求和两个数字,如果我想求和更多,就需要编辑程序.这是我的密码 1 2 3 4 5 6 7def ...

  7. 【C库函数】strncpy函数详解

    目录 strncpy 函数原型 参数讲解 返回值讲解 函数讲解 (1)一般使用场景 (2)特殊使用场景(错误) strncpy         拷贝n个字符到目标字符串中 函数原型 char *str ...

  8. python中减法运算函数_OpenCV-Python图像的减法运算cv2.subtract函数详解以及和矩阵减...

    OpenCV-Python图像的减法运算cv2.subtract函数详解以及和矩阵减 OpenCV-Python图像的减法运算cv2.subtract函数详解以及和矩阵减法的差异对比 ? ? 前往老猿 ...

  9. c++ memset 语言_C/C++ 中memset() 函数详解及其作用介绍

    memset 函数是内存赋值函数,用来给某一块内存空间进行赋值的: 包含在头文件中,可以用它对一片内存空间逐字节进行初始化: 原型为 : void *memset(void *s, int v, si ...

最新文章

  1. CentOS 7系统启动后怎么从命令行模式切换到图形界面模式
  2. Uliweb多人博客教程demo站点
  3. 内存管理范围和@property
  4. 23种设计模式之组合模式
  5. 计算机网络 多个站点共享信道的方式图
  6. 职业经理人必读知识:36页SWOT全面解读,有效提升分析能力
  7. 在Google App Engine中使用hash和marshal持久化模块,快速判断数据库条目是否已经存在...
  8. 基于springboot的贫困帮扶系统
  9. linux 海思hi3798m_海思Hi3798模块芯片,Hi3798处理器参数介绍
  10. NTP时间服务器安装配置详解
  11. 浅浅总结一下HTML吧
  12. Java实现对PDF文件添加水印
  13. shellcode加载器--从入门到放弃
  14. 堡垒机-百百堡垒机-基于WEB的VNC、RDP、SSH远程控制。无须任何插件,随时随地远程。
  15. 利用smtp协议实现命令行发送邮件
  16. 西南科技大学 计算机学院 张伟,信息工程学院综合测评公示第二稿-西南科技大学信息工程学院.DOC...
  17. 信息系统项目管理师必背核心考点(四十九)合同法
  18. 手持式尘埃粒子测试仪价格,尘埃粒子一般一个点测量几次
  19. android usb gadget分析
  20. C++: 随机生成一个 RxC 列联表(附完整源码)

热门文章

  1. 第一个dotnetcore程序,Hello World
  2. input type=file change事件只触发一次
  3. OSI模型和TCP/IP模型
  4. 2015总结 2016展望
  5. php socket
  6. Compmgmtlauncher.exe问题解决方法
  7. 15个非常棒的jQuery无限滚动插件【瀑布流效果】
  8. Python(17)_urllib下的parse的编码解码函数
  9. POJ 3237.Tree -树链剖分(边权)(边值更新、路径边权最值、区间标记)贴个板子备忘...
  10. 洛谷 2953 [USACO09OPEN]牛的数字游戏Cow Digit Game