目录
一、函数
数学中我们常见到函数的概念。但是你了解C语言中的函数吗?
维基百科中对函数的定义:子程序
在计算机科学中,子程序(英语:Subroutine, procedure, function, routine, method, subprogram, callable unit),是一个大型程序中的某部分代码, 由一个或多个语句块组成。它负责完成某项特定任务,而且相较于其他代 码,具备相对的独立性。(比如strlen只负责计算计算字符串的长度)
一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。
二、C语言中函数的分类:
1. 库函数
2. 自定义函数
1.库函数
为什么会有库函数?
1. 我们知道在我们学习C语言编程的时候,总是在一个代码编写完成之后迫不及待的想知道结果,想把这个结果打印到我们的屏幕上看看。这个时候我们会频繁的使用一个功能:将信息按照一定的格式打印到屏幕上(printf)。
2. 在编程的过程中我们会频繁的做一些字符串的拷贝工作(strcpy)。
3. 在编程是我们也计算,总是会计算n的k次方这样的运算(pow)。 像上面我们描述的基础功能,它们不是业务性的代码。我们在开发的过程中每个程序员都可能用的到, 为了支持可移植性和提高程序的效率,所以C语言的基础库中提供了一系列类似的库函数,方便程序员进行软件开发。
像上面我们描述的基础功能,它们不是业务性的代码。我们在开发的过程中每个程序员都可能用的到, 为了支持可移植性和提高程序的效率,所以C语言的基础库中提供了一系列类似的库函数,方便程序员进行软件开发。
那怎么学习库函数呢?
这里我们简单的看看:www.cplusplus.com
简单的总结,C语言常用的库函数都有:
1)IO函数 (与输入输出相关的函数,它的头文件是<stdio.h>)
2)字符串操作函数(<string.h>)
3)字符操作函数
4)内存操作函数
5)时间/日期函数
6)数学函数
7)其他库函数
如何学习这些函数?
1)strcpy 复制字符串
char * strcpy ( char * destination, const char * source );
//strcpy 复制字符串
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = { 0 };
char arr2[] = "hello world";
//目的地 //来源
strcpy(arr1, arr2);//将arr2中的字符串拷贝到arr1中
printf("%s\n", arr1);
printf("%s", arr1);
return 0;
}
打印的结果是:
2)memset 设置内存
void * memset ( void * ptr, int value, size_t num );
将 ptr 指向的内存块的从第一个字节数开始的num个设置为指定的值(value)
//menset 设置内存
#include<stdio.h>
#include<string.h>
int main()
{
char arr[20] = "hello world";
memset(arr,'x',5);
printf("%s\n", arr);
return 0;
}
打印的结果是:
//menset 设置内存
#include<stdio.h>
#include<string.h>
int main()
{
char arr[20] = "hello world";
memset(arr+6,'y',3);//arr+6表示从'w'这个字符开始
printf("%s\n", arr);
return 0;
}
打印的结果是:
注: 但是库函数必须知道的一个秘密就是:使用库函数,必须包含 #include 对应的头文件。
如何学会使用库函数?
需要学会查询工具的使用:
MSDN(Microsoft Developer Network)
www.cplusplus.com
http://en.cppreference.com(英文版)
http://zh.cppreference.com(中文版)
2.自定义函数
自定义函数和库函数一样,有函数名,返回值类型和函数参数。 但是不一样的是这些都是我们自己来设计。
函数的组成:
{ }里面的是函数体。
举个例子: (1)写一个函数可以找出两个整数中的最大值。
#include<stdio.h>
//返回值的类型为int型
int get_max(int x, int y) //函数的定义
{
return(x > y ? x : y);
//函数(get_max)相当于一个工厂,输入的a,b相当于原材料,输出的产品是a,b中的最大值。
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
//求较大值
int m = get_max(a, b);//函数的调用
printf("%d\n", m);
return 0;
}
函数(get_max)相当于一个工厂,输入的a,b相当于原材料,输出的产品是a,b中的最大值。
输出的结果是:
(2)写一个函数可以交换两个整形变量的内容。
两个变量交换,需要再定义一个变量辅助交换。
//写一个函数可以交换两个整形变量的内容
#include<stdio.h>
void Swap(int x, int y)//x和y是形式参数
{
int z = 0;
z = x;
x = y;
z = y;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
//交换
printf("交换前:a=%d b=%d\n", a, b);//a和b是实参
Swap(a, b);//只需要交换,不需要返回值,故不用设置一个变量来接收它的返回值
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
如果代码像上面那么写的话,输出的结果是:
我们会发现a和b并没有实现内容的互换,这是为什么呢?
如图所示:
从上面地址可以看出a和x,b和y的地址是不一样的。
说明a和b是两个完全独立的变量,上面的x和y也是两个完全独立的变量。
调用Swap函数后,再借助z,确实将x和y的值互换了,但是这并不影响a和b的值,因为它们都有自己独立的空间。
a和b叫实参,x和y叫形式参数;实参a和b将值传给x和y后,形参是实参的临时拷贝,形参有自己独立的空间。因为有独立的空间,所以修改形参不会影响实参。
//写一个函数可以交换两个整形变量的内容
#include<stdio.h>
void Swap(int x, int y)//x和y是形式参数
{
int z = 0;
z = x;
x = y;
z = y;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
//交换
printf("交换前:a=%d b=%d\n", a, b);
//a和b叫实参,x和y叫形式参数;实参a和b将值传给x和y后,形参是实参的临时拷贝,形参有自己独立的空间。
//因为有独立的空间,所以修改形参不会影响实参。
Swap(a, b);//只需要交换,不需要返回值,故不用设置一个变量来接收它的返回值
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
那我们怎么做能使a,b和x,y建立关系呢?
int mian()
{
int a = 10;
int* p = &a;
//当我们想改变a的值,有两种方法
a = 20;//直接改
*p = 30;//间接改
return 0;
}
所以我们可以借助地址,将地址指向内容的值交换。
#include<stdio.h>
void Swap(int* px, int* py)
{
//不用交换地址,直接将地址指向内容的值交换就行了
int z = *px;//z相当于a z=a
*px = *py;//a=b
*py = z;//b=a
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
//交换
printf("交换前:a=%d b=%d\n", a, b);
//a和b叫实参,x和y叫形式参数;实参a和b将值传给x和y后,形参是实参的临时拷贝,形参有自己独立的空间。
//因为有独立的空间,所以修改形参不会影响实参。
Swap(&a,&b);//只需要交换,不需要返回值,故不用设置一个变量来接收它的返回值
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
上面代码的输出结果是:
这样就可以实现a和b值的交换了。
三、关于一个工程中有多个main函数的问题
四、函数的调用: 传值调用 , 传址调用
1.传值调用
函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。
2.传址调用
传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。 这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。
答:如果Swap想改变外部变量a和b的值,就需要把a和b的地址过去;如果不想改它们的值,比如add()函数,只想得到得到它们相加的值,那就不需要传地址,只需要把它们的值传过去就可以。
五、函数的参数
实际参数(实参): 真实传给函数的参数,叫实参。 实参可以是:常量、变量、表达式、函数等。 无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。
形式参数(形参): 形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
如上图中main函数内的add()内的a和b,Swap()中的&a和&b是实参,而add()函数内的x和y,Swap()函数内的*px和*py是形参。