C语言自定义函数

函数 / 方法(面向对象语言),将功能重复的代码段(原始的方式是cv)提取抽象出main方法外,将其放入一个新的函数中,从而在main中只需要调用该函数就可完成一项复杂的工作,代码会更清晰简洁。之前我们使用的printf、scanf等都是库函数(linux系统使用man命令可以查看函数如何使用,windows系统可以网络查询),我们自己也可以自定义函数。初学者可以把函数想像成数学中的y=f(x),但其实在编程中还是有区别的。

补充说明一点:函数在C语言中默认是外部的,跨文件调用函数只需要声明即可,或者声明在一个头文件中,main文件声明调用该头文件也行。(具体演示见下文)需要函数只在内部起作用加static修饰。

1. 变量作用域(有点类似定义域)

局部 / 本地(local)或自动(生存期、作用域) 变量:写在一对大括号内——块(函数块、语句块),需要注意变量的块内外重定义和同名问题(外面的在里面仍有效,里面的重定义同名的会掩盖外面的,即变量在生存期内不一定起作用)。
不同块中可以定义同名变量,同一个块中不能重复定义。

全局(global)变量:与main并列的。不做初始化默认被初始化为0或NULL。优先级低于局部变量。
全局变量的初始化在main之前,因此必须用编译它时已知的量(常量)初始化!

关键字 extern (外部external链接属性)用于声明同一个项目不同源文件的全局变量(外部变量)。关键字 static 静态本地变量-则使全局变量不能跨文件调用,但static可以使局部变量出了局部块不被销毁(可以保留变量的值,重新进入函数后用上一次的结果计算)【内存的栈、堆、静态区】。(生存期、作用域可以不一致,注意区别)

【局部变量(生命伴随当前函数终始)存储在栈区。
全局变量、静态变量(全局静态当前源文件可访问,局部静态当前函数可访问)存储在全局区(生命伴随一个程序终始)。】

java中的{}表示优先执行,static{}表示静态代码块;全局变量是定义在类内方法外,局部变量是定义在方法内,访问权限(可见性) +public -private #protected default


  dev创建项目——分为空项目(手动搭建)、控制台(自带main函数)、窗口应用(窗体)等,此处创建空项目。新建源文件、头文件等,头文件用来存放所有对外公开的函数原型和全局变量的声明
注意不同的头文件定义的宏名称要保证不同,因此需采用一定的规范。

调用test1.c的变量a:


具体细节需要了解编译过程中链接环节的属性(外部、内部)等。

2. 自定义函数

函数用于接收一个或多个参数,做一件事,并返回零个或一个值。比如:int main(int argc, char *argv[]) —— 第一个参数存放参数个数,第二个参数存放参数,并且argv[0]是可执行文件路径或符号链接,命令行中执行时可以在后面增添新的参数。main函数最后return 0 表示程序正常退出(Windows借助main返回值不同做批处理;Unix Bash: echo $?、Csh: echo $status查看return值)。
C语言不允许重复定义同名函数(哪怕参数不同);C++、java等面向对象语言支持方法的重载。【因为函数名代表了一块指定的内存空间的首地址】

2.1. 函数定义和调用

定义(函数头+体):<返回类型> <函数名> (入参表, <参数类型> (形式)参数名) {函数体(最后可能需要返回值);}

调用:
函数名(按照类型顺序和数量给出参数值, ); 【()必须加,即使函数不需要入参。不加()表示的是什么?可以联系指针的知识思考】
函数入参值可以是字面量、变量、函数返回值、 计算结果【(a, b) 与 ((a, b))】。
函数return返回的是调用位置的下一处语句。(return讲解参见C语言学习笔记07)

注意:
(1)函数的参数类型和所附值需要匹配。C语言最大的漏洞就是在此处会悄悄帮你把不匹配的类型自动转换好(田螺姑娘)造成数据损失,导致结果可能非你所望。后续的C++/java在这方面则很严格。
(2)传入函数的参数值是一个单纯的值(C语言调用函数时永远只能传值给函数)。
(3)每个函数有自己的变量空间,参数也位于该独立空间中(本地变量),和其它函数没有关系。【除非运用数组、指针】
(4)函数声明使用()表示入参未知,使用(void)真正表示无入参。

2.2. 函数的使用

函数使用前必须先声明函数原型(函数头 加 ;)(声明可以在main上方或main中调用函数前;声明可以不指定函数入参名字,编译器只判断类型是否一致,但为保持可读性最好与定义时的参名一致)或写在主函数上面(C编译器是自上而下顺序分析代码),否则能否编译具体看编译器。
return可以停止函数并送回一个值:return; 或 return 表达式; 。一个函数可以使用多个return语句,不必在最后使用(if),但不符合单一出口。

函数返回值可以赋值给变量。也可以给函数(嵌套),甚至可以丢弃(使用函数附带作用而非结果)

函数的定义不能嵌套!!!

2.3. 标准样例

统计素数并求和——

#include <stdio.h>//自定义函数声明
void swap(int *a, int *b); //swap(&a, &b)进行两数交换 C语言函数只能值传递
int isPrime(int n); //判断 素数/质数 函数 return 0 1/* ***主函数*** */
int main() {int x, y;printf("输入两个自然数,统计两数间(含这两个数)的素数个数并求和。\n");scanf("%d %d", &x, &y);while (getchar() != '\n') {;}if (x > y) {swap(&x, &y);}int cnt = 0, sum = 0;int i;for (i = x; i <= y; i ++) {if (isPrime(i)) {cnt ++;sum += i;}}printf("[%d,%d]内素数个数是%d,这些素数的和是%d。\n", x, y, cnt, sum);return 0;
}/*
* *自定义函数功能定义*
*///形参(x, y)使用实参值副本,实参值不会变 利用指针值交换(地址交换)实现真正交换
//int *p = &i 将i的地址赋给指针p p指向整型
//int* p,q与int *p,q意义一样:声明指针p和普通整型q
void swap(int *a, int *b) {// * 取出内容  *a是值int t = *a;*a = *b;*b = t;
}//素数或质数:指在大于1的自然数中,除了1和本身外没有其它因数的数。
int isPrime(int n) {int flag = 1;int i;if (n < 2) flag = 0;for (i = 2; i < n; i ++) {if (n % i == 0) {flag = 0;break;}}return flag;
}

自定义函数声明和定义写在下面例子的地方也可以,总之需要先声明或定义了才能调用:

#include <stdio.h>void cheer() {printf("Cheers!\n");
}/* Main */
int main() {//cheer(); //cheer;int max(int a, int b);int a, b, c, m;a = 5, b = 6, c = 2;m = max(max(a, b), c);printf("%d\n", m);return 0;
}int max(int a, int b) {int ret; //单一出口if (a > b) {ret = a; //return a;}else {ret = b; //return b;}return ret;
}

3. C语言函数定义的补充说明

如果没有预先声明或定义函数就调用,C语言编译器是会根据函数调用值的类型先猜测函数的样子。如main中调用未知的sum(1,10),C语言会猜测在后面可能会存在有sum的定义如下: int sum(int , int) ,如果后面实际定义不匹配编译器不会完成编译同时会报错。
因此还需要注意定义时不要采用void swap(),而使用void swap(void)(确定函数不需要参数)或void swap(double , double)(确定函数所需参数类型)。

C语言学习笔记08-函数、变量作用域{}相关推荐

  1. C语言学习笔记-7.函数

    一.函数的使用 1.每个函数在使用之前必须先定义 例:void function();       //有分号 int main() {-} void add() {-}       //无分号 2. ...

  2. C语言学习笔记---断言函数assert()

      在C语言库函数中提供了一个辅助调试程序的小型库,它是由assert()宏组成,接收一个整形表达式作为参数.如果表达式的值为假(非零),则assert()宏就在标准错误流(stderr)中写入一条错 ...

  3. C语言学习笔记---指向函数的指针

      在内存中函数的存放也是一段连续的内存,函数名就是指向改内存中的首地址,所以也可以将这个函数的首地址赋给一个指针变量,这样通过指针变量就可以访问改函数.   那么为什么要通过指针来访问函数呢?下面通 ...

  4. C语言学习笔记---打印函数printf()和sprintf()函数

    printf()函数   在C语言中使用最多的打印函数就是printf(),它可以将各种类型的数据转换为字符串输出. int main(int argc, char *argv[]) {char na ...

  5. C语言学习笔记---浮点函数modf()和fmod()

      modf函数可以提取出浮点数的整数部分和小数部分.fmod函数可以返回两个浮点数相除的余数.它们的函数原型如下: double __cdecl modf(double _X,double *_Y) ...

  6. C语言学习笔记---时间函数strftime()

    strftime函数主要用于时间格式化,它的函数原型如下: size_t __cdecl strftime(char * __restrict__ _Buf,size_t _SizeInBytes,c ...

  7. C语言学习笔记---时间函数asctime()和localtime()

      这两个时间函数原型如下: char *__cdecl asctime(const struct tm *_Tm);__CRT_INLINE struct tm *__cdecl localtime ...

  8. C语言学习笔记---abs()函数和div()函数

      C语言库中提供了许多函数,这样需要计算的时候,可以直接借助库函数,而不用自己重新编写函数.今天就来看一下C语言标准库函数里面的整型函数. int __cdecl abs(int _X);long ...

  9. C语言学习笔记---向函数传递结构信息

    传递值   在向函数传递参数的时候,可以直接将结构体成员的值传递给函数.如下面的例子: int sum(int x,int y,int z) {return (x + y + z); }int mai ...

  10. C语言学习笔记——调用函数时提示警告

    [代码] int main() { abc(); abc3(); return 0; } void abc() { int a=65135; double i=8256.67; a=(int)i+a; ...

最新文章

  1. ​2012年至今,细数深度学习领域这些年取得的经典成果
  2. 脑机接口和卷积神经网络的初学者指南(二)
  3. 【编程之美】24点游戏
  4. 常见网络游戏同步方式
  5. MySql数据库操作遇到的蛋疼二三事
  6. 页式存储管理程序模拟_ADAS/AD开发12 - 数据存储管理
  7. Codeforces 765F. Souvenirs
  8. java环境变量_Java的下载及环境变量的配置
  9. 自定义广播增加权限控制
  10. Q91:真实地模拟透明材质(Realistic Transparency)
  11. C++重载运算符的规则详解
  12. ORA-12514: TNS:listener does not currently know of service requested in connect descriptor
  13. LEACH算法改进 SEP算法源代码
  14. minidump详细介绍
  15. 【超图+CESIUM】【基础API使用示例】40、超图|CESIUM - 特效-雨景设置
  16. (保姆式教程:从下数据到画图)python如何利用EOF分析SSTA海温异常现象并画图
  17. 简账(开源记账软件)-数据库设计
  18. ubuntu防火墙安装arm架构说明
  19. 社科院与杜兰大学金融管理硕士——在自己的领域努力拼搏,终将遇到专属的光芒
  20. 计算机ms一级分数分配,计算机一级六大MS题型介绍

热门文章

  1. 自古深情留不住,总是套路得人心!带你吊打面试官...
  2. MATLAB给信号添加白噪声
  3. 语音信号处理(四):生成语音信号的语谱图
  4. 关于蕴含真值表的解释<韦恩图><C代码>
  5. 有关shift的6大快捷键,同事绝对不会告诉你!
  6. 江苏大学计算机专业江苏排名,江苏大学算名校吗?江苏大学排名为啥这么高?...
  7. unity-shader-屏幕空间反射
  8. 如何注册个人邮箱?又应该如何选择邮箱呢?
  9. metascape没有输出通路图
  10. spring boot 使用 javax.mail发送邮件常见错误Authentication failed、Mail server connection failed