概要
- 关键字: return
- 运算符: *(一元), &(一元)
- 函数及其定义方式
- 如何使用参数和返回值
- 如何把指针变量用作函数参数
- 函数类型
- ANSI C原型
- 递归
复习函数
/*FuXinFunc.c -- 复习函数*/
#include "stdio.h"
int sum(int a,int b);
int main(){
int a = 10,b = 50;
printf("%d",sum(a,b));
return 0;
}
int sum(int a,int b){
return a + b;
}
函数参数
/*lethead2.c -- 函数参数*/
#include "stdio.h"
#include "string.h" //为strlen()提供原型
#define NAME "chen"
void hello(const char ch[]);
void main(){
hello(NAME);
}
void hello(const char ch[]){
printf("%s\n",ch);
}
带形式参数的函数
//错误写法
void hello(int a,b,c);
//正确写法
void hello(int a,int b,int c);
声明带形式参数函数的原型
//一般写法
int sum(int a,int b);
int sum(int,int);
调用实际参数的函数
#include "stdio.h"
#include "lethead1.h"
#define SUM 10
// int sum(int a,int b); /*函数原型*/
void main(){
const char ch[] = NAME;
printf("%s\n",ch);
printf("%d\n",sum(2,3+SUM/2));
}
int sum(int a, int b){
return a + b;
}
黑盒视角
黑盒里面发生了什么对主调函数是不可见的。
return从函数中返回值
int sum(int a, int b){
return a + b;
}
ANSI C原型对象
缺点
#include "stdio.h"
#include "string.h" //为strlen()提供原型
#define NAME "chen"
void hello1();//声明没有形参
void main(){
}
void hello1(int a){ //定义函数有形参
printf("%d",a);
}
问题所在
我们看
hello1()
函数相关的一些示例,用过去声明函数的方式声明了hello1()
函数,然后错误的使用该函数
ANSI 解决方案
/*proto.c -- 使用函数原型*/
#include "stdio.h"
int sum(int,int); /*函数原型*/
void main(){
printf("%d\n",sum(10,20));
}
int sum(int a,int b){
return a + b;
}
/* int sum(int f,int e){
return f + e;
}
*/
#include "stdio.h"
int sum(int a,int b){ //既是函数原型,又是函数定义
return a + b;
}
void main(){
printf("%d\n",sum(10,20));
}
递归
/*recur.c -- 递归*/
#include "stdio.h"
int hello(int); /*函数原型*/
void main(){
printf("%d",hello(100));
}
int hello(int i){
if(i <= 0){
return 0;
}
else{
return hello(i - 1) + 1;
}
}
递归优点是省去了一部分重复代码的时间,缺点是不容易阅读与维护
递归常见错误: 栈溢出(stack overflow)
- 栈区
- 局部变量
- 函数形参
- 堆区
- 动态开辟的内存
- 内存
- malloc
- calloc
- 方法区
- 全局变量
- static静态变量
Linux
gcc file1.c file2.c
生成的是.out
文件
使用头文件
#ifndef __LETHEAD1_H
#define __LETHEAD1_H
#define NAME "chen"
// int sum(int a,int b);
int sum(int,int);
#endif
/*lethead1.c -- 创建并使用简单函数*/
#include "stdio.h"
#include "lethead1.h"
#define SUM 10
// int sum(int a,int b); /*函数原型*/
void main(){
const char ch[] = NAME;
printf("%s\n",ch);
printf("%d\n",sum(2,3+SUM/2));
}
int sum(int a, int b){
return a + b;
}
查询地址: &运算符
/*loccheck.c -- 查看变量存储在何处*/
#include "stdio.h"
int sum(int,int); /*函数原型*/
void main(){
int i = 10;
int* p = sum(2,3);
printf("i=%d,地址=%p\n",p,&p);
printf("i=%d,地址=%p\n",i,i = &p);
}
int sum(int a,int b){
return a + b;
}
&运算符目前得出的结论是只对变量有用
指针介绍
指针(pointer)值为内存地址的变量(或数据对象)
定义指针:
基本数据类型* 变量名;
指针赋值
指针变量名 = & + 变量/常量/函数
间接运算符: *
假设已知ptr指向barch:
ptr = &barch
然后使用间接运算符(indirection operator)找出barch中的值,该运算符有时也称为引用运算符(dereferencing operator)。不要把间接运算符和乘法运算符()混淆
指针在函数间通讯
/*swap3.c -- 指针*/
#include "stdio.h"
int sum(int*,int*);/*函数原型*/
void main(){
sum(5,9);
}
int sum(int* a,int* b){
printf("a的地址=%p,b的地址=%p\n",&a,&b);
return a;
}
strcpy()
#include "string.h"
int main(){
char arr1[] = "bit";
char arr2[20] = "##########";
//拷贝后 "bit\0#######"
strcpy(arr2,arr1);
printf("%s\n",arr2);//printf发现'\0'所以后面就不打印输出了
return 0;
}
memory(记忆,计算机指令叫内存
)
#include "string.h"
int main(){
char arr[] = "hello world";
memset(arr,'*',5);//'*'存储的是ASCI码值
printf("%s\n",arr);
return 0;
}
自定义函数
自定义函数与库函数一样,有函数名,返回类型和函数参数
函数的组成
ret_type fun_name(paral, *){
statement; //语句项
}
//ret_type : 返回值类型
//fun_name : 函数名称
//paral : 函数参数
传指针变量
我们可能变量在变,但是我们确定是不是同一个变量就可以传入指针
/*prointerFun1.c -- 指针函数1*/
#include "stdio.h"
int* fun1(int* p);
void swap1(int*,int*);
void main(){
int* p1;
p1 = (int)100;
printf("%p\n",fun1(p1));
int* a = 10;
int* b = 20;
printf("a=%p,b=%p\n",&a,&b);
printf("a=%d,b=%d\n",a,b);
swap1(&a,&b);
printf("a=%p,b=%p\n",&a,&b);
printf("a=%d,b=%d\n",a,b);
}
int* fun1(int* p){
return p + 1;
}
void swap1(int* a, int* b){
int tmp = *a;
*a = *b;
*b = tmp;
}
结果为:
0000000000000068
//从下面开始
a=000000000061FE10,b=000000000061FE08
a=10,b=20
a=000000000061FE10,b=000000000061FE08
a=20,b=10
得知: 内存地址没有被更换里面的值就已经更换了
函数声明和定义
函数声明
- 告诉编译器有一个函数叫什么,参数是什么,返回类型是什么,但是具体是不是存在,无关紧要。
- 函数的声明一般出现在函数的使用之前,要先满足先声明后使用。
- 函数的声明一般要放在头文件中的。
```c
ifndef __HANSHUMING_H
define __HANSHUMING_H
//函数声明 int sum(int a , int b);
endif
```
如果你在工程里面自己引入了一个头文件比方说stdio.h
别人为了打印也引用了这份头文件;大家都引入stdio.h
的时候,这样就重复了,这样同样的代码就重复了好多次,为了避免同一个头文件被很多人引用多次,我们的做法是**#ifndef(if:如果;n:not; def:定义) __根据每个头文件的名字_H__(如果成立则执行以下代码直到包含结束)**
#endif(包含结束)
所以这样就避免了同一个文件被定义多次
函数定义
函数的定义是指函数的具体实现,交待函数的功能实现