函数
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace m1w3d1_function_parm_overload_oop { class Program { static void Main(string[] args) { #region 函数的参数 //为什么我们给一个变量给到方法,方法的确没有去改变这个变量的值? //方法使用的是 形参 //方法本质上是把你传给他的参数,行进一份拷贝(复制)一份在方法体里进行运算 //所以这个复制的参数,叫做形参,并不是你传进的参数本体,叫做实参,形参并不是实参 //如果我需要改实参,我们应该怎么做 //对象我,你,在计算机中数据是存放在内存,这一块数据实际存放的内存地址就是他的实体 //如果我们方法中能拷贝实际内存地址我们就可以正常改变实参的值 #endregion #region ref关键字 //在定义方法时 使用 参数修饰 ref 我们可以传递一个地址 //1,定义方法参数使用ref关键字,调用时同时也可使用 //2,调用时,实际参数必须有被赋值 #endregion #region ref关键字的练习 //给圆赋值 Circle circle = new Circle(); circle.r = 5; GetCircle(ref circle); Console.WriteLine("周长是:{0}", circle.p); Console.WriteLine("面积是:{0}", circle.a); //交换钱数 int myMoney = 10; int yourMoney = 50; ChangeMoney1(yourMoney, myMoney); Console.WriteLine("我的钱:{0}", myMoney); Console.WriteLine("你的钱:{0}", yourMoney); ChangeMoney2(ref yourMoney, ref myMoney); Console.WriteLine("我的钱:{0}", myMoney); Console.WriteLine("你的钱:{0}", yourMoney); //战士攻击减血 Fighter attacker = new Fighter(); Fighter defender = new Fighter(); attacker.attack = 4; defender.health = 10; Attack(ref attacker, ref defender); Console.WriteLine("血:{0}", defender.health); #endregion #region 函数的重载 //函数允许我们重名,重名函数在重载的情况下是允许的 //参数列表不一样时构成重载 //重载函数有助我们统一理解 //1、参数个数不一样 //2、类型和顺序不一样 Console.WriteLine(SumOverload(1, 2.0f)); Console.WriteLine(SumOverload(1.0f, 2)); Console.WriteLine(SumOverload("aaa", "bbb")); #endregion #region 递归的调用 //函数递归 指 函数自身 调用自身的 一种算法 //在算法没有写错的情况 所以他有可能会造成 堆栈溢出异常 //一般用递归解决子问题就是父问题的问题 //边界 在递归过程中,我们必须得有一种已知情况 //边界参数要交给自己 //边界参数要无尽的趋向边界 //求阶乘 6!。 1 * 2 * 3 *4 *5 * 6 * ... * n; //n! = n * n - 1! Console.WriteLine(Factorial(6)); //求1!+2!+3!+... + 10!(两个递归) Console.WriteLine(Sum(10)); //一根竹竿长100m,每天砍掉一半,问第10天它的长度是多少。 //long = f(day,n) //f(10)=f(9)*0.5f; //f(9)=f(8)*0.5f; //f(n)=f(n-1)*0.5f; //f(n)=f(n+1)*2; //n<=1 long=100m Console.WriteLine(GetBamboo(10)); //一根绳子长100m,每天减断一半,问第1天它是多长,问第20天它是多长 Console.WriteLine(Cut(1)); Console.WriteLine(Cut(10)); Console.WriteLine(Cut(20)); #endregion #region 函数复习 //语句 ; //代码块 {} //计算两个数字的和 int a = 20; int b = 10; //容易产生重复,产生代码冗余 int c = Add(a, b); Console.WriteLine(c); Add(-10, 9.0f); Console.WriteLine("1111"); int x = 6; int y = 9; Swap(6, 9); Console.WriteLine("传进来的变量a:{0},b:{1}", x, y); //传给ref的实参必须初始化 int x1 = 6; int y1 = 9; //值类型与引用类型的存储方式: //引用类型:引用类型存储在堆中。类型实例化的时候,会在堆中开辟一部分空间存储类的实 //例。类对象的引用还是存储在栈中。 //值类型:值类型总是分配在它声明的地方,做为局部变量时,存储在栈上;类对象的字段时, //则跟随此类存储在堆中。 //https://www.cnblogs.com/zd1994/p/4424329.html int[] nums = { 1, 2, 3 }; Swap(nums); foreach (var item in nums) { Console.WriteLine(item); } #endregion } #region 函数复习 //函数定义的位置 //返回类型 方法名(参数列表){方法体} //为什么要加static,静态的函数只能调用静态的函数 static int Add(int a, int b) { return a + b;//结束当前函数,有返回值 } //函数重载 //参数个数不同 //参数个数相同,类型不同 //参数类型不同 //重载跟返回类型无关 //void没有返回值 static void Add(int a, float b) { if (a + b < 0) return;//结束当前函数,没有返回值 Console.WriteLine(a + b); } static void Swap(int a, int b)//交换的是形式参数 { Console.WriteLine("传进来的变量a:{0},b:{1}", a, b); int temp = a; a = b; b = temp; Console.WriteLine("传进来的变量a:{0},b:{1}", a, b); } static void Swap(int[] array)//交换的是 { int temp = array[0]; array[0] = array[1]; array[1] = temp; } public struct Circle { public float r; public float p; public float a; } #endregion #region ref关键字的练习 //给圆赋值 static void GetCircle(ref Circle circle) { var PI = 3.14f; var r = circle.r; circle.p = r * 2 * PI; circle.a = r * r * PI; } //交换钱数(形参) static void ChangeMoney1(int myMoney, int yourMoney) { int temp = 0; temp = myMoney; myMoney = yourMoney; yourMoney = temp; } //交换钱数(实参) static void ChangeMoney2(ref int myMoney, ref int yourMoney) { int temp = 0; temp = myMoney; myMoney = yourMoney; yourMoney = temp; } //战士属性 struct Fighter { public int attack; public int health; } //攻击减血 static void Attack(ref Fighter attaker, ref Fighter defender) { defender.health -= attaker.attack; } #endregion #region 函数的重载 static int SumOverload(int a, float b) { Console.WriteLine("这是浮点和整型的重载"); return (int)(a + b); } static float SumOverload(float a, int b) { Console.WriteLine("这是浮点的重载"); return a + b; } static string SumOverload(string a, string b) { return a + b; } #endregion #region 递归的函数 //6!。 1 * 2 * 3 *4 *5 * 6 * ... * n; static long Factorial(long sum1) { if (sum1 <= 1) return 1;//边界 return sum1 * Factorial(sum1 - 1); } //求1!+2!+3!+... + 10!(两个递归) static long Sum(long sum) { long sum1 = 0; for (int i = 1; i <= sum; i++) { sum1 = sum1 + Factorial(i); } return sum1; } //一根竹竿长100m,每天砍掉一半,问第10天它的长度是多少。 static float GetBamboo(int day) { if (day <= 0) return 100; return GetBamboo(day - 1) * 0.5f; } //一根绳子第十天长100m,每天减断一半,问第1天它是多长,问第20天它是多长 static float Cut(int day) { if (day < 1) return Cut(1); if (day == 10) return 100; if (day > 10) return Cut(day - 1) * 0.5f; return Cut(day + 1) * 2; } #endregion } }
#region out 参数修饰符 //用来修饰函数的参数 //一般情况下我们用out来返回一个检测结果 //因为out要求在函数体内一定要给参数赋值(原有的值不可用) #endregion #region params 参数修饰符 //可变参数修饰符,将一个 数组参数 变成允许调用者直接用数组元素传参的形式 //在定义时必须params,调用时直接填数组元素 //params参数必须是最后一个参数 //不用定义数组变量,直接调用函数时传参 #endregion
函数复习
变量名,存在栈里
数组名,存在栈里(保存的是数组元素首字母的地址)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _2_函数 { class Program { static void Main(string[] args) { // 语句 ; // 代码块 { } // 计算两个数字的和 // int a = 20; // int b = 10; //int c = Add(a, b); // Console.WriteLine(c); //Add(-10, 9.0f); //Console.WriteLine("1111"); //int a = 10; //int b = 20; //// 传给ref的实参必须初始化 //Swap(ref a, ref b); ////Console.WriteLine("变量a:{0}, b:{1}", a, b); //int[] nums = { 1, 2, 3 }; //Swap(nums); //foreach (var item in nums) //{ // Console.WriteLine(item); //} string num = "123"; int result; //int a = int.Parse(num); if (int.TryParse(num, out result)) { Console.WriteLine("转换成功 :" + result); } //else //{ // Console.WriteLine("转换失败 :" + result); //} } // out 参数 --- 输出型参数 // ref 参数 --- 叫 引用型参数 static void Swap(ref int a, ref int b) // 形式参数 值传递 加ref变成 传引用 { Console.WriteLine("传进来的变量a:{0}, b:{1}", a, b); int tmp = a; a = b; b = tmp; Console.WriteLine("交换后的变量a:{0}, b:{1}", a, b); } static void Swap(int[] array) // 引用传递 { int tmp = array[0]; array[0] = array[1]; array[1] = tmp; } // 参数个数不同 // 参数个数相同,类型不同 // 参数类型不同 // 重载跟返回类型无关 // 定义的位置 // 返回类型 方法名(参数列表) { 方法体} static int Add(int a, int b) { return a + b; // 结束当前函数 } static void Add(int array, float b) { if (array + b < 0) return; // 结束当前函数 Console.WriteLine(array + b); } } }
out练习
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _1_out练习 { class Program { /* 1. 返回给用户一个登录结果,并且还要单独的返回给用户一个登录信息。 如果用户名错误,除了返回登录结果之外,还要返回一个“用户名错误”、“密码错误” 2. 写一个方法,返回一个数组的总和、最大值、最小值、平均值 */ static void Main(string[] args) { #region 练习1 //UserInfo userInfo = new UserInfo(); //string loginInfo; //Console.WriteLine("请输入用户名:"); //userInfo.usr = Console.ReadLine(); //Console.WriteLine("请输入密码"); //userInfo.pwd = Console.ReadLine(); //TryLogin(userInfo, out loginInfo); //Console.WriteLine(loginInfo); #endregion #region 练习2 var nums = new[] { 2, 4, 9, 4, 6, 3 }; //// 解法1调用 ResultInfo result = GetResult(nums); Console.WriteLine($"** 和:{result.sum}, 最大值:{result.max}, 最小值:{result.min},平均值:{result.average}");//$符号,{}里可以直接填变量 // 解法2调用 //int sum, max, min, average; //GetResult(nums, out sum, out max, out min, out average); //Console.WriteLine($"## 和:{sum}, 最大值:{max}, 最小值:{min},平均值:{average}"); // 解法3 int[] array = GetResult1(nums); Console.WriteLine($"** 和:{array[0]}, 最大值:{array[1]}, 最小值:{array[2]},平均值:{array[3]}"); #endregion } #region 练习1 /* * 1. 返回给用户一个登录结果,并且还要单独的返回给用户一个登录信息。 如果用户名错误,除了返回登录结果之外,还要返回一个“用户名错误”、“密码错误” */ struct UserInfo { public string usr; public string pwd; } static bool TryLogin(UserInfo user, out string loginInfo) { if (user.usr == "user" && user.pwd == "1234") { loginInfo = "登录成功"; return true; } else { if(user.usr == "user") { loginInfo = "密码错误"; } else if(user.pwd == "1234") { loginInfo = "用户名错误"; } else { loginInfo = "用户名和密码错误"; } return false; } } #endregion #region 练习2 /* 2. 写一个方法,返回一个数组的总和、最大值、最小值、平均值 */ struct ResultInfo { public int sum; public int max; public int min; public int average; } // 解法1 static ResultInfo GetResult(int[] arr) { ResultInfo result = new ResultInfo(); result.max = result.min = arr[0]; foreach (var item in arr) { result.sum += item; if (result.max < item) result.max = item; if (result.min > item) result.min = item; } result.average = result.sum / arr.Length; return result; } // 解法2 static void GetResult(int[] arr, out int sum, out int max, out int min, out int average) { sum = 0; max = min = arr[0]; foreach (var item in arr) { sum += item; if (max < item) max = item; if (min > item) min = item; } average = sum / arr.Length; } static int[] GetResult1(int[] arr) { int[] nums = new int[4]; // 0 sum 1 max 2 min 3 average foreach (var item in arr) { nums[0] += item; if (nums[1] < item) nums[1] = item; if (nums[2] > item) nums[2] = item; } nums[3] = nums[0] / arr.Length; return nums; } #endregion } }
params关键字
params关键字的优点
1.数组可以单个传
2.也可以什么都不传
3.还可以给参数设置默认值
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _3_params { class Program { static void Main(string[] args) { //var nums = new[] { 1, 2, 5, 3, 6 }; //Console.WriteLine(GetSum(nums)); // 什么都不传也可以 //Console.WriteLine(GetSum()); //ShowInfo("Hello World!", "前空格", "后空格", "前空格"); ShowNum(10); } static void ShowNum(int num, int bei = 2) // 从右到左设置,必须在所有可选参数之后 { Console.WriteLine(num * bei); } static void ShowInfo(string s, params string[] operations) { string tmp = s; if(operations.Length > 0) { foreach (var item in operations) { if(item == "前空格") { tmp = "### " + tmp; } if(item == "后空格") { tmp += " ###"; } } } Console.WriteLine(tmp); } static int GetSum(params int[] nums) { int sum = 0; foreach (var item in nums) { sum += item; } return sum; } } }