其他路径:
CSDN: https://blog.csdn.net/wodehao0808
微信公众号:程序喵星人
更多资源和视频教程,QQ:1902686547
6 函数
6.1 函数的定义和使用
函数也叫方法。
函数的定义:
<Access Specifier> <Return Type> <Method Name>(Parameter List)
{
Method Body
return <returnValue>
}
以下是方法中的各种元素:
访问说明符:它用于从一个类中确定一个变量或方法的可见性。
返回类型:方法可能会返回一个值。返回类型是方法返回值的数据类型。如果该方法不返回任何值,那么返回类型是 void。
方法名称:方法名称是唯一的标识符,并区分大小写。它不能与在类中声明的任何其他标识符相同。
参数列表:括号括起来,使用参数从方法中传递和接收数据。参数列表是指类型、顺序和方法的参数数目。参数是可选的;方法可能包含任何参数。
方法主体:它包含的一组指令完成所需要的活动所需。
<returnValue>:如果返回类型<Return Type>为void,则可以不使用return;否则,需要时用return返回,并且<returnValue>的类型必须跟返回类型一致。
在参数数目不确定时,使用关键字params声明一个数组来传递参数,叫做参数数组。
例如:
// 数组参数
void Add(int[] array)
{
...
}
Add(new int[] {1, 2, 3, 4}); // 调用函数时,实参是一个数组
// 参数数组 // params关键字
void Add2(params int[] array)
{
...
}
Add2(1, 2, 3, 4, 5, 9, 6); // 调用函数时,实参是不确定数目的离散的值,params声明后,编译器会自动将这些参数合并成一个数组传递给函数。
Add2(new int[] {1, 2, 3, 4}); // 当然也可以直接使用数组做实参调用。
6.1.1 Example:函数的定义和使用
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 函数的定义和使用
namespace Lesson_5_1
{
class Program
{
// 返回类型为void的函数
static void Write()
{
Console.WriteLine("这是一个自定义的Write函数");
// return; 这里return可以不加上
}
// 两个数相加
static int Add(int p_iNum1, int p_iNum2) // 定义方法时的参数,我们称之为形式参数(即形参)
{
return p_iNum1 + p_iNum2; // 返回类型是int,这里必须使用return,且返回值是int类型的值
}
// 取得数字的所有因子,并返回所有因子
static int[] getFactor(int p_iNum)
{
int iCount = 0;
for (int i = 1; i <= p_iNum; ++i)
{
if (p_iNum % i == 0)
{
++iCount;
}
}
int[] arr = new int[iCount];
int index = 0;
for (int i = 1; i <= p_iNum; ++i)
{
if (p_iNum % i == 0)
{
arr[index] = i;
++index;
}
}
return arr;
}
// 获得数组中的最大的数,数组参数
static int getMax(int[] p_iArray)
{
int iMax = p_iArray[0];
foreach (int v in p_iArray)
{
if (iMax < v)
{
iMax = v;
}
}
return iMax;
}
// 参数数组,params关键字
static int getMax2(params int[] p_iArray)
{
int iMax = p_iArray[0];
foreach (int v in p_iArray)
{
if (iMax < v)
{
iMax = v;
}
}
return iMax;
}
static void Main(string[] args)
{
Write();
int sum = Add(10, 20); // 调用方法时的参数,我们称之为实际参数(即,实参)
Console.WriteLine("调用Add方法的结果是:" + sum);
int[] arr = getFactor(10);
foreach (int v in arr)
{
Console.WriteLine("调用getFactor方法的结果是:" + v);
}
int iMax = getMax(new int[] { 16, 2, 8, 9, 32, 26 });
Console.WriteLine("调用getMax方法的结果是:" + iMax);
// 参数数组
int iMax2 = getMax2(16, 2, 8, 9, 32, 26); // params声明, 使用离散实参,编译器会自动将离散的值转换成一个数组传递给函数
Console.WriteLine("离散实参 调用 getMax2 方法的结果是:" + iMax2);
int iMax3 = getMax2(new int[] { 16, 2, 8, 9, 32, 26 }); // params声明,也可以直接使用数组实参传递给函数
Console.WriteLine("数组实参 调用 getMax2 方法的结果是:" + iMax3);
Console.ReadKey();
}
}
}
6.2 结构体的函数
在结构体中定义函数。
当我们在结构体中定义一个函数的时候,这个函数就可以通过结构体声明的变量来调用。这个函数可以带有参数,那么调用的时候必须传递参数。这个函数,可以使用结构体中的属性。
6.2.1 Example:结构函数
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 结构函数
namespace Lesson_5_2
{
struct CustomerName
{
public string firstName;
public string secondName;
public string getName()
{
return firstName + "-" + secondName;
}
}
class Program
{
static void Main(string[] args)
{
CustomerName name1, name2;
name1.firstName = "name";
name1.secondName = "1";
name2.firstName = "name";
name2.secondName = "2";
Console.WriteLine("name1的姓名是:" + name1.firstName + " " + name1.secondName);
Console.WriteLine("name2的姓名是:" + name2.firstName + " " + name2.secondName);
// 可以发现,上面的输出,有一部分是重复的,如果名字很多,重复的次数就超级多;
// 而如果有一天需求改了,让firstName 和 secondName 使用 '-'(不再使用 ' ')连接起来,那么所有使用的地方,都要修改一遍,维护起来麻烦和繁琐;
// 针对这种情况,我们使用函数封装,这样需求改变是,只需要修改函数里面的内容,使用的地方不需要改动;即只需要改一个地方(函数定义的地方)
// 需求修改为:使用'-'连接名。这里使用结构函数。
Console.WriteLine("使用结构函数name1的姓名是:" + name1.getName());
Console.WriteLine("使用结构函数name2的姓名是:" + name2.getName());
}
}
}
6.3 函数的重载
重载(overload):同一个函数名,多个实现。
函数重载必须满足以下条件:
1.函数名相同;
2.参数类型 或者 参数个数不同;
编译器会根据传递的实参的类型和个数,来确定调用的是哪个函数。
例如:
int d(int a, int b);
string d(double a, double b);
d(1, 2); // 根据实参类型,调用的是d(int, int) 方法
d(22.5, 556.554); // 根据实参类型,调用的是 d(double, double) 方法
6.3.1 Example:函数的重载
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 函数的重载
namespace Lesson_5_3
{
class Program
{
static int getMax(int[] array)
{
int iMax = array[0];
for (int i = 1; i < array.Length; ++i)
{
if (iMax < array[i])
{
iMax = array[i];
}
}
return iMax;
}
// 重载
static double getMax(double[] array)
{
double iMax = array[0];
for (int i = 1; i < array.Length; ++i)
{
if (iMax < array[i])
{
iMax = array[i];
}
}
return iMax;
}
static void Main(string[] args)
{
int iMax = getMax(new int[] { 2, 98, 65, 12}); // 会根据实参类型,自动判断调用的函数 getMax(int[]);
Console.WriteLine("int的最大值是 = " + iMax);
double dMax = getMax(new double[] { 2.23, 98.63, 65, 12.52 }); // 会根据实参类型,自动判断调用的函数 getMax(double[]);
Console.WriteLine("double的最大值是 = " + dMax);
}
}
}
6.4 委托
委托(delegate)是一种存储函数引用的类型。
委托的定义指定了一个返回类型和一个参数列表。
定义了委托之后,就可以声明该委托类型的变量,接着就可以把一个 返回类型跟参数列表跟委托一样的函数 赋值给这个变量。
6.4.1 Example:委托
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 委托
namespace Lesson_5_4
{
// 委托定义:使用 delegate 关键字
// 委托没有函数体
public delegate double MyDelegate(double param1, double param2);
class Program
{
static double Multipy(double a, double b)
{
return a * b;
}
static double Divide(double a, double b)
{
return a / b;
}
static void Main(string[] args)
{
MyDelegate dl; // 声明一个委托变量
dl = Multipy; // 给委托变量赋值,必须返回类型和函数参数一致
Console.WriteLine("dl = Multipy 调用结果是 = " + dl(10, 3)); // dl(10, 3)使用委托调用方法 Multipy
dl = Divide;
Console.WriteLine("dl = Divide 调用结果是 = " + dl(10, 3)); // dl(10, 3)使用委托调用方法 Divide
Console.ReadKey();
}
}
}
6.5 练习
练习1.
下列常量中,不是字符常量的是()。
A.' ' B."y" C.'x'
练习2.
f(n)=f(n-1)+f(n-2) f(0)=2 f(1)=3 ,用程序求得f(40)
练习5.
一球从100米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在第10次落地时,共经过多少米?第10次反弹多高?
练习6.
求1+2!+3!+...+20!的和?
练习7.
利用递归方法求5!。 f(n)=n*f(n-1)
练习8.
编一个程序,定义结构类型(有学号、姓名、性别和程序设计成绩四个字段),声明该结构类型变量,用赋值语句对该变量赋值以后再输出。
练习9.
编一个程序,输入一个正数,对该数进行四舍五入到个位数的运算。例如,实数12.56经过四舍五入运算,得到结果13;而12.46经过四舍五入运算,得到结果12
练习10.
有关系式1*1+2*2+3*3+...+k*k<2000,编一个程序,求出满足此关系式的k的最大值
练习11.
编一个程序,解决百钱买百鸡问题。某人有100元钱,要买100只鸡。公鸡5元钱一只,母鸡3元钱一只,小鸡一元钱3只。问可买到公鸡,母鸡,小鸡各为多少只。把所有的可能性打印出来。
6.5.1 Example:练习1、2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 练习1、2
namespace Lesson_5_5
{
class Program
{
static int F(int n)
{
// 终止函数递归调用
if (0 == n) return 2;
if (1 == n) return 3;
return F(n - 1) + F(n - 2); // 函数调用自身,即称为递归调用
}
static void Main(string[] args)
{
// example_1:
// 答案是B
// example_2: f(n)=f(n-1)+f(n-2) f(0)=2 f(1)=3 ,用程序求得f(40)
int iResult = F(40);
Console.WriteLine("F(40)的结果是 = " + iResult);
int iResult2 = F(3);
Console.WriteLine("F(3)的结果是 = " + iResult2);
Console.ReadKey();
}
}
}
6.5.2 Example:练习5、6
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 练习5、6
namespace Lesson_5_6
{
class Program
{
static int F(int n)
{
int iResult = 1;
for (int i = 1; i <= n; ++i)
{
iResult *= i;
}
return iResult;
}
static void Main(string[] args)
{
// example_5: 一球从100米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在第10次落地时,共经过多少米?第10次反弹多高?
float iHeight = 100;
float iDistance = 0;
for (int i = 1; i <= 10; ++i)
{
iDistance += iHeight;
iHeight /= 2;
}
Console.WriteLine("第10次落地时,经过 {0} 米,反弹高度是 {1} 米。", iDistance, (iHeight / 2));
Console.WriteLine("example_5 finish ------------------------------");
// example_6: 求1+2!+3!+...+20!的和
long lngSum = 0;
for (int i = 1; i <= 20; ++i)
{
lngSum += F(i);
}
Console.WriteLine("和为:" + lngSum);
Console.WriteLine("example_6 finish -----------------------------");
Console.ReadKey();
}
}
}
6.5.3 Example:练习7、8、9
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 练习7、8、9
namespace Lesson_5_7
{
class Program
{
static int F(int n)
{
if (1 == n) return 1;
return n * F(n - 1);
}
struct Student
{
public int number;
public string name;
public string sex;
public float score;
public void Show()
{
Console.WriteLine("学号:{0}, 姓名:{1},性别:{2}, 成绩:{3}", number, name, sex, score);
}
}
static void Main(string[] args)
{
// example_7: 利用递归方法求5!。 f(n)=n*f(n-1)
Console.WriteLine("5! = " + F(5));
Console.WriteLine("example_7 finish ---------------------------");
// example_8: 编一个程序,定义结构类型(有学号、姓名、性别和程序设计成绩四个字段),声明该结构类型变量,用赋值语句对该变量赋值以后再输出。
Student stu;
stu.number = 100001;
stu.name = "张三";
stu.sex = "男";
stu.score = 565.5f;
stu.Show();
Console.WriteLine("example_8 finish ---------------------------");
// example_9:
// 编一个程序,输入一个正数,对该数进行四舍五入到个位数的运算。例如,实数12.56经过四舍五入运算,得到结果13;而12.46经过四舍五入运算,得到结果12
Console.WriteLine("请输入一个数字:");
double dNum = Convert.ToDouble(Console.ReadLine());
int iNum = (int)(dNum + 0.5);
Console.WriteLine("四舍五入后的值是 = " + iNum);
Console.WriteLine("example_9 finish ---------------------------");
Console.ReadKey();
}
}
}
6.5.4 Example:练习10、11
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 练习10、11
namespace Lesson_5_8
{
class Program
{
static void Main(string[] args)
{
// example_10: 有关系式1*1+2*2+3*3+...+k*k<2000,编一个程序,求出满足此关系式的k的最大值
int k = 1;
int sum = 0;
while (true)
{
sum += k * k;
if (sum >= 2000)
{
break;
}
++k;
}
Console.WriteLine("满足条件的 k = " + (k - 1));
Console.WriteLine("example_10 finish --------------------------------");
// example_11:
// 某人有100元钱,要买100只鸡。公鸡5元钱一只,母鸡3元钱一只,小鸡一元钱3只。问可买到公鸡,母鸡,小鸡各为多少只。把所有的可能性打印出来。
for (int i = 0; i <= (100 / 5); ++i)
{
for (int j = 0; j <= (100 - i * 5) / 3; ++j)
{
int iLast = (100 - 5 * i - 3 * j) * 3;
if (100 == (i + j + iLast))
{
Console.WriteLine("买了公鸡{0}只,买了母鸡{1}只,买了小鸡{2}只。", i, j, iLast);
}
}
}
Console.WriteLine("example_11 finish ----------------------------------");
Console.ReadKey();
}
}
}
C#初级教程学习笔记到此结束。