数组练习
练习:首先遍历nums1,用一个变量count统计非0的个数
创建一个长度为count的新数组nums2
遍历num1,把非0的值依次填入nums2中
int[] nums1 = { 2, 3, 0, 5, 0, 6, -1 };
int count = 0;
for (int i = 0; i < nums1.Length; i++)
{
if (nums1[i] != 0)
{
count++;
}
}
//Console.WriteLine(count);
int[] nums2 = new int[count];
int newIndex = 0;//记录新数据的拷贝数据
for (int i = 0; i < nums1.Length; i++)
{
if (nums1[i] != 0)
{
nums2[newIndex] = nums1[i];
newIndex++;//新数组的位置向前挪一下
}
}
for (int i = 0; i < nums2.Length; i++)
{
Console.WriteLine(nums2[i]);
}
Console.ReadKey();
练习: 将一个字符串数组{“3”,“a”,“8”,“haha”}输出为|分割的字符串,“3|a|8|haha”
string[] strs = { "3", "a", "8", "haha" };
string s = "";//和string s;有区别
for (int i = 0; i < strs.Length - 1; i++)
{
string str = strs[i];
s = s + str + "|";//读一个变量前,这个变量必须被赋值
}
s = s + strs[strs.Length - 1];//加上最后一个
Console.WriteLine(s);
Console.ReadKey();
foreach循环
foreach(类型 变量名 in 数组名)
对数组进行逐个遍历
和for的区别:for可以不逐个遍历,比如每隔一个遍历一个,或者可以从后向前遍历
依次遍历names数组中的内容,对于每条数据都执行{}中的代码,
每次遍历的数组用in前面的变量表示,变量的类型是数组的类型
string[] names = { "tom", "jerry", "lily" };
//for (int i = 0; i < names.Length; i++)
//{
// string str = names[i];
// Console.WriteLine(str);
//}
foreach (string str in names)
{
Console.WriteLine(str);
}
遍历数组
int[] nums = { 3, 5, 9 };
foreach (int n in nums)
{
Console.WriteLine(n);
}
练习:分别打印数组中的名字
string[] names = { "tom", "jerry", "lily" };
foreach (string name in names)
{
Console.WriteLine("我的名字{0}", name);
}
Console.ReadKey();
函数
函数就是将一堆代码进行重用的一种机制;
函数就是一段代码,这段代码可能有输入的值(参数),可能会返回值。
函数:static 返回值类型 函数名(参数列表)
不用函数编写用户输入两个数,并输出它们的和。
static void Main(string[] args)
{
Console.WriteLine("请输入第一个数");
string s1 = Console.ReadLine();
int i1 = Convert.ToInt32(s1);
Console.WriteLine("请输入第二个数");
string s2 = Console.ReadLine();
int i2 = Convert.ToInt32(s2);
int i3 = i1 + i2;
Console.WriteLine(i3);
Console.ReadKey();
}
用函数编写一:
static void Main(string[] args)
{
int i1 = ReadInt("请输入第一个数");
int i2 = ReadInt("请输入第二个数");
ReadInt("请输入第一个数");//没有返回值也行,但没啥用
int i3 = i1 + i2;
Console.WriteLine(i3);
Console.ReadKey();
}
static int ReadInt(string msg)//返回值类型 函数名(参数列表)
{
Console.WriteLine(msg);
string s = Console.ReadLine();
int i = Convert.ToInt32(s);
return i;
}
练习函数编写两个数的和
static void Main(string[] args)
{
int i = Add(5, 6);
Console.WriteLine(i);
Console.ReadKey();
}
static int Add(int i1, int i2)
{
return i1 + i2;
}
没有返回值的函数用 void
static void SayHello()//表示函数没有返回值
{
Console.WriteLine("早上好");
Console.WriteLine("中午好");
Console.WriteLine("下午好");
}
练习:提供一个函数,将用户提供的一个字符串重复n遍形成一个新的字符串"abc"3,返回给调用者一个字符串"abcabcabc"
static void Main(string[] args)
{
Console.WriteLine("请输入字符串");
string s=Console.ReadLine();
int n = ReadInt("请输入次数");
string resuit= Rpeat(s, n);
//函数内部不关心参数怎么来的,也不关心返回值干什么用
Console.WriteLine(resuit);
Console.ReadKey();
}
//注意参数命名规则
//不要在函数内部帮调用者WriteLine,不要帮调用者ReadLine
//调用函数的地方的参数名字和函数声明时的名字没有对应关系
static string Rpeat(string s, int n)
{
string t= "";
for(int i=0;i<n;i++)
{
t = t + s;
}
return t;//把计算的结果返回
}
练习:编写一个函数,将用户提供的两个整数中的的最大值返回
static int mMax(int n1, int n2)
{
if (n1 > n2)
{
return n1;
}
else
{
return n2;
//return"aaa";//函数答应返回int就必须返回int
//不能不返回,不能返回其他类型
}
}
练习:return和break区别
static void Hello()
{
for (int i = 0; i < 10; i++)
{
if (i == 3)
{
//break;
return;
}
Console.WriteLine("aaaaa");
}
Console.WriteLine("Hello完成");
}
break会执行"Hello完成" return不执行
函数返回值易错点
一个函数如果“答应”返回一个非void类型的值,则函数的所有路径都要有返回值。比如将对输入年龄转换为年龄段描述的函数。
while()中赋值也不行,因为可能while一个循环都不执行。
错误一:所以路径都要有返回值,不能存在没有返回值的情况
static int DoIt(int i)
{
if (i < 0)
{
return 0 - 1;
}
else if (i>=0&&i<=10)
{
return 30;
}
}
错误二:存在没有返回值的情况
static int DoIt(int n)
{
for (int i = 0; i < n; i++)
{
return i;
}
}
练习:
static void Main(string[] args)
{
int[] nums = { 3, 6, 8 };
Console.WriteLine(Sum(nums));//函数要求提供什么数据,必须提供什么数据
Console.ReadKey();
}
static int Sum(int[] values)
{
int sum = 0;
foreach (int i in values)
{
sum = sum + i;
}
return sum;
}
练习:编写一个从百度MP3下载音乐函数需要定哪些参数,
假设http://mp3.baidu.com/***.mp3
static bool DownLoadMp3(string filename, string localfilename)
//两个,歌名,下载到哪去
{
string ur1 = "http://mp3.baidu.com/filename.mp3";
}
练习:调用者提供一个字符串数组,和一个字符串,把字符串数组用这个字符串分割起来
static void Main(string[] args)
{
string [] strs = { "a", "c", "d" };
string s = "()";
string t = FenGe(strs ,s);
Console.WriteLine(t);
Console.ReadKey();
}
static string FenGe(string[] strs, string s)
{
string t = "";
foreach (string str in strs)
{
t = t+str + s;
}
return t;
}
函数重载
构成重载的条件:
同名的两个函数的签名(参数的类型、顺序、返回值的类型)不能完全一样;和参数的名字无关;函数的重载不关返回值类型 。
例子:
static void Next(int i)
{
Console.WriteLine(i+i);
}
static void next(int i)
{
Console.WriteLine(i + i);
}
//overload重载
static void Next(string boss)
{
if (boss == "毛")
{
Console.WriteLine("邓");
}
只有参数的类型、顺序不一致才能函数重名,函数返回值类型一直与否没有关系
static int Next(string boss)//错误
{
}
可变参数(params)
参数数组:
int sum(params int[] values)
int sum(string name,params int[] values)
可变参数数组必须是在最后一个
参数默认值(C#4.0) :void SayHello(string name,int age=20)
用重载来实现参数默认值的效果,在构造函数中用的特别多。
编写一个让用户输入一个数组并输出其中的最大值,使用可变参数就可以不用定义一个数组,可以直接输入一组数。
static void Main(string[] args)
{
//int[] values = { 3,5,7,5,7,9,9};
//int i = Max(values);
//int i = Max(1, 2, 3);
int j = Max(true,"",3, 5, 7, 1, 9);
Console.WriteLine(j);
Console.ReadKey();
}
//个数不确定的可变参数以数组的形式传递
//可变参数一定要放在最后一个
static int Max(bool b,string msg,params int[] values)
{
Console.WriteLine(msg);
int max = 0;
foreach (int value in values)
{
if (value > max)
{
max = value;
}
}
return max ;
}
//设置参数默认值
static void SayHello(string name,int age=20,bool gender=true )
{
Console.WriteLine("我是{0},我芳龄{1}",name,age );
}
函数的ref、out参数
函数参数默认是值传递的,也就是“复制一份”。
ref必须先初始化,因为是引用,所以必须先“有”,才能引用;
而out则是内部为外部赋值,所以不需要初始化,而且外部初始化也没用。
ref应用场景内部对外部的值进行改变;
out则是内部为外部变量赋值,out一般用在函数有多个返回值的场所。
ref就是为了能折腾变量本身
例如:没有使用ref,变量本身的值不会变。
static void Main(string[] args)
{
int i = 1;
DotIt(i);
Console.WriteLine(i);//输出1、2、1
Console.ReadKey();
}
//int i传进来的时候是复制了一份传进来,折腾的是复制品
static void DotIt(int i)
{
Console.WriteLine (i);
i++;
Console.WriteLine(i);
i++;
}
使用ref
static void Main(string[] args)
{
int i1 = 10;
int i2 = 20;
//Swap(i1,i2 );//折腾的是复制品
//用ref之前必须给变量赋值
Swap(ref i1,ref i2);//传递引用。给ref传递参数时也要加上ref
Console.WriteLine("i1={0},i2={1}",i1,i2)
Console.ReadKey();
}
static void Swap(ref int i1, ref int i2)//reference
{
//标记为ref就是要求调用者传递变量的引用
int temp = i1;
i1 = i2;
i2 = temp;
//static void Swap(int i1, int i2)
//{
// int temp = i1;
// i1 = i2;
// i2 = temp;
}
out:就起到一个函数有两个返回值
static void Main(string[] args)
{
bool b;//不需要为out赋值
int i= Parse(Console.ReadLine(),out b);
if(b)//和if(b==true)一样
{
Console.WriteLine ("成功,i={0}",i);
}
else
{
Console.WriteLine ("错误");
}
Console.ReadKey();
}
static int Parse(string s,out bool success)
{
if(s=="一")
{
success=true;
return 1;
}
else if(s=="二")
{
success=true;
return 2;
}
else
{
success=false ;
return -1;
}
例如: 把用户输入的字符串转换成数,如果用户输入的不是数,用Convert.ToInt32()转换就会报错。可以用int.TryParse(s, out i)
static void Main(string[] args)
{
string s = Console.ReadLine();
int i=0;
if (int.TryParse(s, out i))
{
Console.WriteLine("成功" + i);
}
else
{
Console.WriteLine("输入错误" );
}
//int i = Convert.ToInt32(s);
//i++;
//Console.WriteLine(i);
Console.ReadKey();
}
字符串
char类型:用单引号包含字符,单引号中放且只能放一个字符。(‘a’)
单个字符也可以表示为字符串,还可以有长度为0的字符串。
null(表示空)和""(长度为0);‘f’(字符)和“f”(字符串)的区别。
练习:String.IsNullOrEmpty
string s = " ";//不是empty
if(s==null||s==""||s==string.Empty )
{
}
if (string.IsNullOrEmpty(s))//等价与s==null||s==""
{
Console.WriteLine("空");
}
使用s.Length属性来获得字符串中的字符个数
String s = "asadsfdfsdfdf";
Console.WriteLine(s.Length);
string可以看做是char的只读数组。char c = s[1];。
例子:遍历输出string中的每个元素。
string s = "asfadsfdf";
foreach (char c in s)
{
Console.WriteLine(c);
}
C#中字符串有一个重要的特性:不可变性,字符串一旦声明就不再可以改变。所以只能通过索引来读取指定位置的char,不能对指定位置的char进行修改。
String s = "asadsfdfsdfdf"
char c = s[3];//读取序号为0的位置的char,注意char的类型
Console.WriteLine(c);
//s[3]='1'//只能读,不能改
char[] chars = { 'a', 'b', 'c' };
chars[1] = '1';
//字符串是不可变的,所以要先生成一个chae[],再对char[]进行修改
//再根据char[]生成的新的字符串,但是原来的字符串没有改变(他就在那)
如果要对char进行修改,那么就必须创建一个新的字符串,用s. ToCharArray()方法得到字符串的char数组,对数组进行修改后,调用new string(char[])这个构造函数来创建char数组的字符串。一旦字符串被创建,那么char数组的修改也不会造成字符串的变化。
例子:将字符串中的第三位替换为w。
string s = "asfsafdafdsfsd";
char[] chars = s.ToCharArray();
chars[2] = 'w';//是直接改char[]数组
string s1 = new string(chars);
Console.WriteLine(s1);
Console.WriteLine(s);
string s=“abc”,是声明一个变量s,把s指向“abc“这个字符串
例:时间格式转换汉字大写 比如: “2009年9月5日” 转换成 “二零零九年九月五日”,输入字符串,返回字符串。写成一个函数
static void Main(string[] args)
{
string s = "2009年9月18日";
string s1 = TOCHDate(s);
Console.WriteLine(s1);
Console.ReadKey();
}
static string TOCHDate(string date)
{
//{'零','一','二'},表驱动算法
char[] chars = date.ToCharArray();
for (int i = 0; i < chars.Length; i++)
{
char ch = chars[i];
switch (ch)
{
case '1':
chars[i] = '一';
break;
case '2':
chars[i] = '二';
break;
case '3':
chars[i] = '三';
break;
case '4':
chars[i] = '四';
break;
case '5':
chars[i] = '五';
break;
case '6':
chars[i] = '六';
break;
case '7':
chars[i] = '七';
break;
case '8':
chars[i] = '八';
break;
case '9':
chars[i] = '九';
break;
case '0':
chars[i] = '零';
break;
}
}
return new string(chars);
}
要区分变量名和变量指向的值的区别。程序中可以有很多字符串,然后由字符串变量指向他们,变量可以指向其他的字符串,但是字符串本身没有变化。字符串不可变性指的是内存中的字符串不可变,而不是变量不变。
String类常用函数
ToLower():得到字符串的小写形式。
ToUpper():得到字符串的大写形式;
注意字符串是不可变的,所以这些函数都不会直接改变字符串的内容,而是把修改后的字符串的值通过函数返回值的形式返回。s.ToLower()与s=s.ToLower()
例:得到字符串小写形式
string s = "ChinaRen";
s.ToLower();//字符串是不可变的,所以转换后的值通过返回值
string s1 = s.ToLower();
Console.WriteLine(s);
Console.WriteLine(s1);
例:忽略大小写比较用户名
Console.WriteLine("请输入用户名:");
string name = Console.ReadLine();
//忽略大小写比较用户名
name = name.ToLower();//并没有改变原先的字符串,只是指向新的字符串
if (name == "admin")
{
Console.WriteLine("用户名存在");
}
else
{
Console.WriteLine("用户名不存在");
}
去空格:Trim()
Trim()去掉字符串两端的空白(不会去掉中间的)。
例:去掉两边空格
string s = " ab cd ";
Console.WriteLine(s.Length);
s = s.Trim();//去掉两边的空格,不会去掉中间的
Console.WriteLine(s.Length);
Console.WriteLine(s);
忽略大小写比较
s1.Equals(s2, StringComparison.OrdinalIgnoreCase),两个字符串进行不区分大小写的比较。
例:两个字符串比较
string s1 = "Admin";
string s2 = "admin";
Console.WriteLine(s1 == s2);
Console.WriteLine(s1.ToLower() == s2.ToLower());
//Ignore:忽略。Case:大小写(CaseSensitive:大小写敏感)
Console.WriteLine(s1.Equals(s2, StringComparison.OrdinalIgnoreCase));
string s2 = string.Format("{0}年{1}月{2}日", year, month, day);
例: 用占位符、格式生成新的字符串
// String.IsNullorEmpty()
string s1=string.Format("我叫{0},我{1}岁","sun",100);
Console.WriteLine(s1);
拼接string.Join("|", values)
拼接:string s1 = string.Join("|", values);//第一个参数是string类型分隔符
例:用"|"拼接字符串
string [] value={"aa","bb","cc"};
string s=string.Join ("|",value );//用分隔符拼接字符串数组
Console.WriteLine(s);
string[] Split(): 分割字符串
string[] Split(params char[] separator):可以用可变参数
string line = Console.ReadLine();//1,2,3,4,5,6
string[] strs = line.Split(',', '|');//因为分隔结果可能是多个,所以string数组
foreach (string str in strs)
{
Console.WriteLine(str);
}
string[] Split(char[] separator, StringSplitOptions options)按char分割符分割,不能用可变参数,可以移除结果中的空白字符串,但不能去掉空格;
string s="aaa,bbb,,cc,ddd,aaa,333, 90";
//string [] strs=s.Split(',');
//string[] strs = s.Split(',',',');
char[] seps = {',', ',' };
//移除空字符串
//因为重载中StringSplitOptions放到最后,所以不能分隔符必须用chae[]传
//不能用可变参数
string[] strs = s.Split(seps,StringSplitOptions .RemoveEmptyEntries );
foreach (string str in strs)
{
Console.WriteLine(str.Trim());//Trim去掉空格
}
string[] Split(string[] separator, StringSplitOptions options)按照string分割符分割,移除空字符串,但不能移除空格。
string s = "aaa|*bbb|*ccc";
string[] seps = { "|*"};//new string[5];
string[] seps = new string[] { "|*"};
//没必要记住Split的这么多用法,用的时候能转到Split定义用起来就行
string[] strs = s.Split(seps ,StringSplitOptions .RemoveEmptyEntries);
string[] strs = s.Split(new string[] { "|*" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string str in strs)
{
Console.WriteLine(str.Trim());
}
例子1:从日期字符串(“2008-08-08”)中分析出年、月、日;2008年08月08日
string pDate = Console.ReadLine();
string[] strs = pDate.Split ('-');
string date = string.Format("{0}年{1}月{2}日", strs[0], strs[1], strs[2]);
Console.WriteLine(date);
Console.ReadKey();
例子2:从一个记录了学生成绩的文本文档,每个学生成绩是一行,每行是用|分割的数据,用|分割的域分别是姓名、年龄、成绩,写程序取出成绩最高学生的姓名和成绩。
参考:使用string[] lines = System.IO.File.ReadAllLines(@“c:\root.ini”, Encoding.Default);从文本文件读取数据,返回值为string数组,每个元素是一行。
string[] lines = System.IO.File.ReadAllLines(@"F:\root.txt",Encoding.Default);
int score = 0;
string name="";
foreach (string line in lines )
{
string[] strs = line.Split('|');
int chenji = int.Parse(strs[2]);
if (chenji >score)
{
score = int.Parse(strs[2]);
name = strs[0];
}
}
Console.WriteLine("姓名:{0} 成绩:{1}",name,score);
Console.ReadKey();