第二週學習內容
陣列練習
練習:首先遍歷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();