目录
1️⃣.函数是什么
在维基百科中,对于函数的定义是子程序。子程序是一个大型程序中的某部分代码,由一个或多个语句块组成,他负责完成某项特定的任务,而且相较于其他的代码,具备相对的独立性。
一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。
2️⃣.c语言中函数的分类:
2.1. 库函数
把常用的一些功能实现成函数
注:但是库函数的使用必须包含对应的头文件
这里有两个推荐学习的网站:cppreference.com
cplusplus.com - The C++ Resources Network
那怎么学习库函数呢?
这里我们简单的看看:http://www.cplusplus.com
这是c的库,我们在左边的部分可以很快的找到我们曾经用过的函数,那么我将用一个例子带着你来学习库函数。
strcpy这个函数包含在string.h这个头文件里面,这个函数的参数需要两个指针,返回值是一个字符型指针,指针就是地址,
char * strcpy ( char * destination, const char * source );
Pointer to the destination array where the content is to be copied.
指向目标数组的指针,那儿目标数组的内容要被复制。
C string to be copied.
要被复制的c字符串
2.2自定义函数
如果库函数能干所有的事情,那还要程序员干什么?所以更加重要的是自定义函数。自定义函数和库函数一样,有函数名,返回值类型和函数参数。但是不一样的是这些都是我们自己来设计。这给程序员一个很大的发挥空间。
函数的组成:
ret_type fun_name(para1, * )
{
statement;//语句项
}
ret_type 返回类型
fun_name 函数名
para1 函数参数
3️⃣.函数的调用:
3.1传值调用
函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。
写一个函数可以交换两个整形变量的内容
viod swap(int p1,int p2); //1.原型
void swap(int p1, int p2) //2.声明
{
int tmp = 0;
tmp = p1;
p1 = p2;
p2 = tmp;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d%d", &a, &b);
printf("交换前,a = %d b = %d\n", a, b);
swap(a, b); //3.调用
/*int p1 = &a;
int p2 = &b;
swap(p1, p2);*/
printf("交换后,a = %d b = %d\n", a, b);
return 0;
}
3.2传址调用
传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。
void swap(int* p1 , int* p2);
void swap(int* p1 , int* p2)
{
int tmp = 0;
tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d%d", &a, &b);
printf("交换前,a = %d b = %d\n", a, b);
swap(&a, &b);
/*int p1 = &a;
int p2 = &b;
swap(p1, p2);*/
printf("交换后,a = %d b = %d\n", a, b);
return 0;
}
实参中,我将a,b的地址给传了进去,形参又用p1和p2两个指针存储了a,b的地址,接着用 * 操作符找到了a,b的地址并修改了里面的内容。
4️⃣.函数的参数
4.1实际参数(实参)
真实传给函数的参数,叫实参。实参可以是:常量、变量、表达式、函数等。无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。
4.2形式参数(形参)
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
形参和实参的名字可以一样,不影响什么。
5️⃣.函数与数组
数组的两个特殊性质
(1)不允许拷贝和赋值
不能将数组的内容拷贝给其他数组作为其初始值,也不能用数组为其他数组赋值。
(2)使用数组是通常将其转化成指针
在C++语言中,指针和数组有非常紧密的联系。使用数组的时候编译器一般会把它转换成指针。
数组的两个特殊性质对我们定义和使用作用在数组上的函数有影响。因为不能拷贝数组,所以我们无法以值传递的方式使用数组参数。因为数组会被转换成指针,所以当我们为函数传递一个数组时,实际上传递的是指向数组首元素的指针。
#include <iostream>
using namespace std;
//定义数组参数形参
void bb(int arr[],int n)
{
for (int i = 0; i < n; i++)
{
arr[i] = i + 1 ;
}
}
//定义指针参数形参
void bbs(int *arr, int n)
{
for (int i = 0; i < n; i++)
{
arr[i] = i + 2;
}
}
void show(int *arr,int n)
{
for (int i = 0; i < 10; i++)
{
cout << *(arr+i)<< " ";// 有数组:arrb[i]与(arrb+i)等价
}
}
int main()
{
int arrb[10];
//定义数组参数,传递数组首地址,指向原数组
bb(arrb,10 );
show(arrb, 10);
cout << endl;
//定义指针参数,传递数组首地址,指向原数组
bbs(arrb, 10);
show(arrb, 10);
system("pause");
return 0;
}
6️⃣.函数与二维数组
二维数组
二维数组,就是在一维数组上,多加了一个维度;二维数组定义的四种方式:
建议:使用第二种更加直观,可提高代码的可读性;
且注意第4种,可以省略行,但一定不可以省略列;
int arr[2][3] =
{
{1,2,3},
{4,5,6}
};
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
cout << arr[i][j] << " ";
}
cout << endl;
}
用二维数组名查看其所占用内存空间
cout << "二维数组占用内存空间为:" << sizeof(arr) << endl;
cout << "二维数组第一行占用内存为:" << sizeof(arr[0]) << endl;
cout << "二维数组第一个元素占用内存为:" << sizeof(arr[0][0]) << endl;
cout << "二维数组行数为:" << sizeof(arr) / sizeof(arr[0]) << endl;
cout << "二维数组列数为" << sizeof(arr[0]) / sizeof(arr[0][0]) << endl;
用二维数组名查看二维数组的首地址
cout << "二维数组首地址为:" << (int)arr << endl;
cout << "二维数组第一行首地址为:" << (int)arr[0] << endl;
cout << "二维数组第一个元素首地址:" << (int)&arr[0][0] << endl;
cout << "二维数组第二个元素首地址:" << (int)&arr[0][1] << endl;
利用函数,求数组元素的平均值:
需要注意的是在调用函数的时候,在函数有返回值的情况下,一定要注意将返回值返回到main主函数中使用。同时注意子函数中形参和主函数中实参的区别应用即可。
本题中我还是使用随机函数来给元素赋值。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void printf_arr(int arr_01[2][3],int i,int j);
float arr_avg(int arr_02[2][3],int i,int j);
void fuzhi(int arr_01[2][3],int i,int j);
int main()
{
int arr[2][3]={0};
float avg;
fuzhi(arr,2,3);
printf_arr(arr,2,3);
avg=arr_avg(arr,2,3);
printf("平均分为:%f",avg);
return 0;
}
void fuzhi(int arr_03[2][3],int i,int j)
{
int a,b;
srand(time(0));
for(a=0;a<i;a++)
for(b=0;b<j;b++)
{
arr_03[a][b]=rand()%100+1;
}
}
void printf_arr(int arr_01[2][3],int i,int j)
{
int a,b;
for(a=0;a<i;a++)
{
for(b=0;b<j;b++)
{
printf("%d ",arr_01[a][b]);
}
printf("\n");
}
}
float arr_avg(int arr_02[2][3],int i,int j)
{
int a,b;
float sum=0,avg=0;
for(a=0;a<i;a++)
for(b=0;b<j;b++)
{
sum += arr_02[a][b];
}
printf("总值为:%f\n",sum);
avg=sum/6;
return avg;
}
7️⃣.函数中使用结构体
#include<stdio.h>
#include<string.h>
void printStudent(Student s) ;
struct Student {
int age;
double height;
double weight;
char name[30];
double fun();
}Tom;
double Student::fun() {
return (double)age * 1.0 / strlen(name);
}
void printStudent(Student s) { //将结构体作为参数整体访问
printf("%d %.3f %.3f %s\n", s.age, s.height, s.weight, s.name);
}
int main() {
Tom.age = 20;
Tom.height = 170.0;
Tom.weight = 150.0;
strcpy(Tom.name, "Tom Smith"); //vs用strcpy_s
printStudent(Tom);
return 0;
}
8️⃣.函数与string对象
C风格字符串和string对象的用途几乎相同,但与数组相比,string对象可以实现传递与复制的功能。
#include<iostream>
#include<string>
using namespace std;
const int SIZE = 5;
void display(const string sa[], int n);
int main()
{
string list[SIZE];
cout << "Enter " << SIZE << " favorite food: " << endl;
for (int i = 0; i < SIZE; i++)
{
cout << i + 1<<":";
getline(cin, list[i]);//用getline函数可捕获空格
}
cout << "Your list:" << endl;
display(list,SIZE);
return 0;
}
void display(const string sa[], int n)//该函数用来显示列表内容
{
int i;
for (i = 0; i < n; i++)
{
cout << i + 1 << ":" << sa[i] << endl;
}
}
9️⃣.递归
#include <bits/stdc++.h>
using namespace std;
int sum;//全局变量 方便在count函数中使用sum
void count(int a,int b)
{
for(int i=a;i<b;i++)
{
if(b%i==0&&i<=b/i)//如果b能整除i 且i小于商
{
sum++;
count(i,b/i);//递归计算
}
if(i>b/i) break;
}
}
int main()
{
int n;
int a; //被分解的数
cin >> n; //数据组数
while(n)
{
sum = 1;
cin >> a;
count(2,a);
cout<<sum<<endl;
n--;
}
return 0;
}
1️⃣0️⃣.函数指针
函数指针,其本质是一个指针变量,该指针指向这个函数。函数指针就是指向函数的指针。声明格式如下:
类型说明符 (*函数名) (参数)
例如,
int (*myfun)(int x,int y);
把一个函数的地址赋值给函数指针变量有两种写法:
myfun = &Function;
myfun = Function;
注意:&不是必需的,因为一个函数标识符就表示了它的地址。
调用函数指针的方式也有两种:
x = (*myfun)();
x = myfun();
函数指针使用示例如下,
#include <iostream>
using namespace std;
int add(int x,int y){
return x+y;
}
int sub(int x,int y){
return x-y;
}
//函数指针
int (*myfun)(int x,int y);
int main(int argc, char *argv[])
{
//第一种写法
myfun = add;
cout << "(*myfun)(1,2) = " << (*myfun)(1,2) << endl;
//第二种写法
myfun = ⊂
cout << "(*myfun)(5,3) = " << myfun(5,3) << endl;
return 0;
}