C#基础入门学习笔记

49 阅读24分钟

1、C# 程序文件基础结构

using System;

namespace myNameSpace    //命名空间,类似于工具包
{
    class Program        //类,类似于工具
    {

        static void function()             //函数,类似于工具能做的事情
        {
            Console.WriteLine("你好,世界");
        }

        static void Main(string[] args)    //主函数,程序的入口
        {
            function();                   //函数调用
        }
    }
}

转存失败,建议直接上传图片文件

输入
ReadLine() 读取整行输入(直到按下回车),返回 string 类型
ReadKey()  读取单个按键(立即响应,不需要回车),返回 ConsoleKeyInfo 结构体

--------------------------------------------------------------------------

输出
WriteLine() 打印一行,结尾自动换行
Write()     打印一行,但是结尾不自动换行

  语言         打印 你好世界
|-----|------------------------------------|
| C#  | Console.WriteLine("Hello,World!"); |
|-----|------------------------------------|
| C   | printf("Hello,World!\n");          |   //C语言必须手动添加\n
|-----|------------------------------------|
| C++ | cout<<"Hello,World!"<<endl;        |
|-----|------------------------------------|

转存失败,建议直接上传图片文件

2、C# 变量

using System;

namespace my_第一个程序
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("变量");

            //折叠代码
            //主要作用是方便代码的阅读
            //它是通过 #region 和 #endregion 来实现的
            //只在编辑状态下有效,编译时不会被编译
            #region 如何折叠代码
            Console.Write("被折叠代码");

                        //C# 的变量类型

            //1. 有符号的整形变量,能存储一定范围的正整数和负整数
            //  1.1 sbyte 有符号的8位整数,范围是-128~127
            sbyte a = 1;
            //  1.2 short 有符号的16位整数,范围是-32768~32767
            short b = 2;
            //  1.3 int 有符号的32位整数,范围是-21亿~21亿
            int c = 3;
            //  1.4 long 有符号的64位整数,范围是-9百万兆~9百万兆
            long d = 4;

            //2. 无符号的整形变量,只能存储正整数
            //  2.1 byte 无符号的8位整数,范围是0~255
            byte e = 5;
            //  2.2 ushort 无符号的16位整数,范围是0~65535
            ushort f = 6;
            //  2.3 uint 无符号的32位整数,范围是0~42亿
            uint g = 7;
            //  2.4 ulong 无符号的64位整数,范围是0~18百万兆
            ulong h = 8;
            //3. 浮点数(小数)
            //  3.1 float 单精度浮点数,有效位数为6~8位(根据电脑的不同,有效位数可能不同)
            float i = 9.1f; //加f表示这是一个float类型的变量,不加f会被认为是double类型的变量
            //  3.2 double 双精度浮点数,有效位数为15~17位
            double j = 9.2;
            //  3.3 decimal 高精度浮点数,有效位数为28~29位,一般不使用
            decimal k = 9.3m; //加m表示这是一个decimal类型的变量,不加m会被认为是double类型的变量

            //4. 特殊类型 
            //  4.1 bool 布尔类型,只能存储true或false
            bool l = true;
            //  4.2 char 字符类型,只能存储一个字符,用单引号括起来
            char m = 'a';
            //  4.3 string 字符串类型,只能存储字符串,用双引号括起来
            string n = "hello world";
            //  4.4 object 通用类型,任何类型都可以存储在object类型的变量中
            object o = 1; //可以存储任何类型的变量,但是在使用时需要进行类型转换

            #endregion
        }
    }
}

转存失败,建议直接上传图片文件

3、C# 运算符  

1、赋值运算符

    等于: =

2、算术运算符

    加:  +
    减:  -
    乘:  *
    除:  /
    取余: %

3、算术运算符的优先级

    乘除取余 优先级高于 加减
    有括号,括号优先

4、复合运算符

    加等于: +=
    减等于: -=
    乘等于: *=
    除等于: /=
    余等于: %=

5、算数运算符自增减

    int i = 0 , a = 0;

    自增: ++
    i++;    先用后加    例如i = 0; a = i++; 那么结果 a 为 0 ,i 为 1。
    ++i;    先加后用    例如i = 0; a = i++; 那么结果 a 为 1 ,i 为 1。

    自减: --
    i++;    先用后减
    --i;    先减后用

6、条件运算符

    用于比较两个变量或常量
    大于:    >
    小于:    <
    等于:    ==
    不等于:  !=  
    大于等于: >=   
    小于等于: <=   

7、逻辑运算符

    逻辑与:&&   同真为真,有假为假
    逻辑或:||   有真为真,同假为假
    逻辑非: !    真变假,假变真

8、位运算符

    位与: &               //对位运算,有 0 则 0
        int a = 1;        //001
        int b = 5;        //101
        int c = a & b;    //001 因此 c 为 1

    位或: |               //对位运算,有 1 则 1
        int a = 1;        //001
        int b = 5;        //101
        int c = a | b;    //101 因此 c 为 5
     
    异或: ^               //对位运算,相同为0,不同为1
        int a = 1;        //001
        int b = 5;        //101
        int c = a ^ b;    //100 因此 c 为 4

    位取反: ~              // 1 变 0,0 变 1
        int a = 5;        // int型 4个字节,共32位 最高位为符号位
        int b = ~a;       
        |--------------------------------------------------------------------------------
        |   在计算机中,负数是以补码形式存储的,补码的计算方法是将原码取反后加1
        |   而正数的补码反码都是自己本身。
        |    a为: 0000 0000 0000 0000 0000 0000 0000 0101
        |   ~a为: 1111 1111 1111 1111 1111 1111 1111 1010   首位符号位为1表面是一个负数,
        |                                                   因此这是一个负数的补码
        | 反码为: 1111 1111 1111 1111 1111 1111 1111 1001    补码-1是反码                                                                                                                    
        | 原码为: 1000 0000 0000 0000 0000 0000 0000 0110    源码为补码取反(除了符号位)   
        |                                                                                  
        | 结果就是-6                                                                        
        |--------------------------------------------------------------------------------
    
    左移: <<  左移几位,右侧加几个0
        int a = 5;      //   101
        a << 2;         // 10100  所以 a 为 20
    
    右移: >>  右移几位,右侧去掉几个数
        int a = 5;      // 101
        a >> 2;         //   1  所以 a 为 1

9、三目运算符

    固定语法    判断条件 ? 条件为真  :  条件为假 ;
    三目运算符有返回值,返回值必须与类型一致。
    
    例如:艾伦问三笠

    {
        Console.WriteLine("对你来说,我是你的什么人?");
        string str = Console.ReadLine();
        Console.WriteLine((str=="我是你的优乐美") ? "地鸣是什么?和她私奔" : "发动地鸣");
    }

    三笠没有回答她是艾伦的优乐美,所以艾伦发动了地鸣  ╥﹏╥

转存失败,建议直接上传图片文件

 4、C# 字符串拼接

string 字符串拼接是特别的

字符串拼接方式 1

    之前的算数运算符只是用来数值类型变量进行数学运算的
    而 string 不存在算数运算符,不能计算,但是可以通过 + 来进行字符串拼接

    string str = "把他们驱逐出去,";
    str = str + "一匹不留!";
    Console.WriteLine(str);    //结果是 "把他们驱逐出去,一匹不留!" 

字符串拼接方式 2

    固定写法:string.Format("待拼接的内容",内容1,内容2,内容3,....);
    待拼接的内容固定规则:想要拼接的内容用占位符替代 {数字0~n}

    string str = string.Format("我{0},他{1},你跟我们走,{3}","铠","超","啥事没有");
    Console.WriteLine(str);  // "我铠,他超,你跟我们走,啥事没有"

打印拼接
    Console.WriteLine("我是{0},扣{1},{2}地鸣","艾伦.耶格尔",1,"带你一起");  
    // "我是艾伦.耶格尔,扣1,带你一起地鸣"
    

转存失败,建议直接上传图片文件

 5、C# 隐式转换和显示转换

隐式转换
1、大范围存小范围
2、double --> float --> 整形(无符号、有符号) --> char
3、decimal --> 整型(无符号、有符号) --> char
4、long --> int --> short --> sbyte
5、ulong --> uint --> ushort --> byte
6、无符号 没法 隐式转换 有符号
7、有符号的 可以 隐式转换 无符号的(范围大小)

---------------------------------------------------------------------

显示转换
1、括号强转  数据之间的转换  高精度转低精度
    int i = 1;
    long lg = 2;
    i = (int)lg;

2、Parse法  把字符串转成对应的类型  变量类型.Parse(字符串)
    int i;
    i = int.Parse("123");

3、Convert法 任意转换
    int i;
    i = Convert.ToInt32(12.345);
    i = Convert.ToInt32("12345");

4、toString法 转换为字符串类型
    string str = 1.ToString();  //直接把数字转换位string是可以的

转存失败,建议直接上传图片文件

6、C# 异常捕获

通过异常捕获可以在代码运行出错时避免代码卡死

基本语法:

    //必备部分
    try    
    {
        /*
        try:一个 try 块标识了一个将被激活的特定的异常的代码块。后跟一个或多个 catch 块。
        希望进行异常捕获的代码块
        */
    }
    catch
    {
        /*
        catch:程序通过异常处理程序捕获异常。catch 关键字表示异常的捕获。
        如果程序运行出错了,会执行 catch 中的代码块来捕获异常
        */
    }
    catch(Exception e) //和上面的catch块一样,不过Exception会携带try中出错的原因进入catch块
    {
    
    }
    //可选部分
    finally
    {
        /*
        finallyfinally 块用于执行给定的语句,不管异常是否被抛出都会执行。
        例如,如果打开一个文件,不管是否出现异常文件都要被关闭。
        */
    }

转存失败,建议直接上传图片文件

 7、C# 条件分支语句

1if 语句
    基本语法:
    
    if( /*判断条件*/ )
    {
        //如果条件为真,则执行此代码块
    }

--------------------------------------------------------------------------------

2if ... else 语句
    基本语法:
    
    if( /*判断条件*/ )
    {
        //如果条件为真,则执行此代码块
    }
    else
    {
        //如果条件为假,则执行此代码块
    }

----------------------------------------------------------------------------------

3if ... else if ... else 语句
    基本语法:
    其中,else if 可以有 1 ~ n 个。
    并且最后的 else 可以省略
    
    if( /*判断条件 1 */ )
    {
        //如果条件 1 为真,则执行此代码块
    }
    else if( /*判断条件 2 */  )
    {
        //如果条件 2 为真,则执行此代码块
    }
    .
    .
    . 
    else if( /*判断条件 n */ )
    {
        //如果条件 n 为真,则执行此代码块
    }
    else
    {
        //如果都不满足,则执行此代码块
        //如果不需要这段代码也可以不写最后这个 else 代码块
    }

-----------------------------------------------------------------------------------

4switch 语句  (一般配合枚举使用)
    基本语法:
    case 可以有 1 ~ n 个
    break 的作用是跳出,他之后的代码就不在执行了
    
    switch( /*变量*/ )
    {
        //当 变量 == 常量 的时候执行 case 和 break 之间的代码逻辑
        case  常量1:
            满足条件执行此代码逻辑;
            break;
        case 常量2:
            {
                也可以写成代码块的方式,满足条件执行此代码块;
            }
            break;
        .
        .
        .
        case 常量n:
            满足条件执行此代码逻辑;
            break;
        default:
            如果上面的 case 的条件都不满足就会执行这里;
            break;
    }

转存失败,建议直接上传图片文件

8、C# 循环语句 

1while 语句
    基本语法:

    while( /*条件判断*/)
    {
        //当满足条件时开始执行 while 代码块的内容
        //...
        //...
        //...
        //当代码块逻辑执行完会回到 while 循环开头再次进行判定,
        //因此 while 的判断条件不能写成永远为真,死循环系统除外,例如单片机
    }

--------------------------------------------------------------------------------------

2do  while 语句
    基本语法:
    它与while的区别是,他会先执行一次do的内容后在判断,如果满足则再次执行do   

    do
    {
        //代码块逻辑
    }
    while( /*条件判断*/ );

    例如:
    do
    {
        Console.WriteLine("艾伦是...家人");
    }
    while(false);
    
    结果是: "艾伦是...家人"

---------------------------------------------------------------------------------------

3for 语句
    基本语法:

    for( /*初始表达式*/ ; /*条件表达式*/ ; /*增量表达式*/ )
    {
        //循环代码逻辑
    }

    初始表达式:一般声明一个临时变量用来计数
    条件表达式:进入循环条件判断
    增量表达式:用初始表达式定义的变量进行自增减运算

    例如:
    for(int i = 0; i < 10 ; i++)
    {        
        Console.WriteLine(i);
    }
    结果是打印输出 0~9

    如果for循环中不屑内容,就是for循环的死循环写法,如:
    for(;;)
    {
        Console.WritLine("死循环");
    }

---------------------------------------------------------------------------------------


    break    跳出循环 
    continue 结束本次循环开启下一循环
    这两个搭配循环也是很好用也经常用的,例如

    1.break 用法
    {
        int i = 0;
        while(true)    //死循环
        {
            i++;
            // if 中的判断 i 是否已经为10了,如果是就直接跳出循环
            if( 10 == i )  // 10 == i 和 i == 10 其实效果一样,前者是尤达表达式,
            {              //是一种防止出错的写法,因为 1 == 10 不小心会写为 i=10
                           //而这种情况编译器不会报错,10 = i 编译器会报错
                break;     //跳出死循环,不再执行while循环
            }
            Console.WriteLine(i);
        }
    }
    执行结果是是输出0~9,等于10的时候跳出死循环了,就没有打印


    2.continue 用法
    {
        for(int i = 0; i < 10 ; i++)
        {
            if(5 == i || 7 == i)
            {
                continue;
            }
            Console.WriteLine(i);
        }
    }
    执行结果是是输出0 1 2 3 4 6 8 9。因为57被取消本次循环开始下一循环

转存失败,建议直接上传图片文件

9、C# 枚举

枚举( enum )是一个被命名的整形常量的集合,一般用它来表示状态、类型等。
枚举一般声明在 namespace 语句块(常用)或者class语句块中。

声明枚举:     创建一个自定义的枚举类型
声明枚举变量: 使用声明的自定义枚举类型创建一个枚举变量

    基本语法:

    声明枚举:
    enum E_自定义枚举名
    {
        自定义枚举项名字1//枚举中第一个默认值是0,下面的枚举项会在上
        自定义枚举项名字2//一个枚举项基础上依次累加,当然也可以指定当前值是多少
        .
        .
        .
        自定义枚举项名字n,
    }

    声明枚举变量:
    E_自定义枚举名 变量名 = 默认值;(自定义的枚举类型.枚举项)


    例如:
    using System;

    namespace MyNamespace
    {
        enum E_AOT
        {
            Mikasa_Ackerman,
            Eren_Jaeger,
            Armin_Arlert,
            Levi_Ackerman,
        }

        class Program
        {
            static void Main(string[] args)
            {
                E_AOT player = E_AOT.Levi_Ackerman;

                if( player == E_AOT.Levi_Ackerman)
                {
                    Console.WriteLine("执行兵长的代码逻辑块");
                }
                else if( player == E_AOT.Mikasa_Ackerman)
                {
                    Console.WriteLine("执行三笠的代码逻辑块");
                }
                //等等,以此类推


                //其中,枚举配合 switch 语句很常用,所以我们一般很少使用if,更多是switch
                switch(player)
                {
                    case E_AOT.Mikasa_Ackerman:
                        Console.WriteLine("执行三笠的代码逻辑");
                        break;
                    case E_AOT.Eren_Jaeger:
                        Console.WriteLine("执行艾伦的代码逻辑");
                        break;
                    case E_AOT.Armin_Arlert:
                        Console.WriteLine("执行阿明的代码逻辑");
                        break;
                    case E_AOT.Levi_Ackerman:
                        Console.WriteLine("执行兵长的代码逻辑");
                        break;
                    default:
                        break;
                }
            
            }
        }
    }

转存失败,建议直接上传图片文件

10、C# 数组

        10.1 一维数组

数组是存储一组相同类型数据的集合,分为一维、多维、交错数组

    数组声明:
    
    //只是声明一个数组,但是没有开房间
    1、变量类型[] 数组名;
        int[] array;    

    //声明一个长度为 n 的数组,数据默认为0
    2、变量类型[] 数组名 = new 变量类型[n];
        int[] array = new int[5];

    //声明一个长度为 n 的数组,数据为{}中的内容,并且内容个数要是声明的个数
    3、变量类型[] 数组名 = new 变量类型[n]{内容1,内容2,内容3, ..... , 内容n};
        int[] array = new int[5]{1,2,3,4,5};

    //声明一个数组,数据为{}中的内容,数据内容的个数决定了大小
    4、变量类型[] 数组名 = new 变量类型[]{内容1,内容2,内容3, ..... , 内容n};
        int[] array = new int[]{1,2,3,4,5};

    //声明一个数组,数据为{}中的内容,,数据内容的个数决定了大小
    5、变量类型[] 数组名 = {内容1,内容2,内容3, ..... , 内容n};
        int[] array = {1,2,3,4,5};


    数组使用:
    int[] array = {1,2,3,4,5};

    1、获取数组的长度    
        数组名.Length
        Console.WriteLine(array.Length);    //长度是 5

    2、获取数组中的元素
        数组名[下标]     //下标是从0开始的,不能越界访问,如果数组长度是5,你不能访问第6个元素
        Console.WriteLine(array[0]);    //1
        Console.WriteLine(array[1]);    //2
        Console.WriteLine(array[4]);    //5

    3、修改数组中的元素
        数组名[下标] = 新值;   
        array[0] = 114514;
        Console.WriteLine(array[0]);    //114514

    4、遍历数组
        通过循环来输出数组所有内容
        for(int i = 0 ; i < array.Lenth ; i++ )
        {
            Console.WriteLine(array[i]); 
        }

    5、查找数组中的元素
        通过循环来查找输出数组中某个元素的位置

        int a = 3;

        for(int i = 0 ; i < array.Lenth ; i++ )
        {
            if(a == array[i])
                Console.WriteLine("和a相等的元素在数组的{0}位上",i); 
        }

转存失败,建议直接上传图片文件

         10.2 二维数组

二维数组是两个下标来确定元素位置,可以理解位行标和列标

    二维数组声明:
    
    //只是声明一个二维数组,但是没有开房间
    1、变量类型[,] 二维数组名; 
        int[2,3] array;   

    //声明一个长度为 n*m 个元素的二维数组,数据默认为0
    2、变量类型[,] 二维数组名 = new 变量类型[n,m];
        int[2,3] array = new int[2,3];  

    //声明一个长度为 n 的二维数组,数据为{}中的内容,并且内容个数要是声明的个数
    3、变量类型[,] 二维数组名 = new 变量类型[n,m]{{1行内容1,1行内容2, ... ,1行内容m},
                                                {...},
                                                {...},
                                                {...},
                                                {n行内容1,n行内容2, ... ,n行内容m}};
        int[3,3] array = new int[3,3]{{ 1 , 2 , 3 },
                                      { 4 , 5 , 6 },
                                      { 7 , 8 , 9 }};   

    //声明一个二维数组,数据为{}中的内容,数据内容的个数决定了大小
    4、变量类型[,] 二维数组名 = new 变量类型[,]{{1行内容1,1行内容2, ... ,1行内容m},
                                             {...},
                                             {...},
                                             {...},
                                             {n行内容1,n行内容2, ... ,n行内容m}};
        int[3,3] array = new int[,]{{ 1 , 2 , 3 },
                                    { 4 , 5 , 6 },
                                    { 7 , 8 , 9 }};

    //声明一个二维数组,数据为{}中的内容,,数据内容的个数决定了大小
    5、变量类型[,] 二维数组名 = {{1行内容1,1行内容2, ... ,1行内容m},
                              {...},
                              {...},
                              {...},
                              {n行内容1,n行内容2, ... ,n行内容m}};
        int[3,3] array = {{ 1 , 2 , 3 },
                          { 4 , 5 , 6 },
                          { 7 , 8 , 9 }};

    二维数组使用:
    int[,] array = {{1,2,3},{4,5,6}};

    1、获取二维数组的长度 
        
        得到全部个数
        二维数组名.Length;
        Console.WriteLine(array.Length);    //行长度是 6

        得到多少行
        二维数组名.GetLength(0);
        Console.WriteLine(array.GetLength(0);    //行长度是 2

        得到多少列   
        二维数组名.GetLength(1);
        Console.WriteLine(array.GetLength(1);    //列长度是 3

    2、获取二维数组中的元素
        二维数组名[行下标,列下标]            //下标是从0开始的,不能越界访问
        Console.WriteLine(array[0,0]);    //1
        Console.WriteLine(array[0,1]);    //2
        Console.WriteLine(array[1,0]);    //4
        Console.WriteLine(array[1,2]);    //6

    3、修改二维数组中的元素
        二维数组名[行下标,列下标] = 新值;   
        array[0,0] = 114514;
        Console.WriteLine(array[0,0]);    //114514

    4、遍历二维数组
        通过循环来输出二维数组所有内容
        for(int i = 0 ; i < array.GetLenth(0) ; i++ )
        {
                for(int j = 0 ; j < array.GetLenth(1) ; j++ )
                {          
                   Console.WriteLine(array[i,j]); 
                } 
        }

    5、查找二维数组中的元素
        通过循环来查找输出二维数组中某个元素的位置

        int a = 3;

        for(int i = 0 ; i < array.GetLenth(0) ; i++ )
        {
                for(int j = 0 ; j < array.GetLenth(1) ; j++ )
                {   
                    if(a == array[i,j])
                    {      
                        Console.WriteLine(array[i,j]);
                        break;
                    }
                } 
        }

转存失败,建议直接上传图片文件

         10.3 交错数组

交错数组是数组的数组,每个维度的数量可以不同

    交错数组声明:
    
    //只是声明一个交错数组,但是没有开房间
    1、变量类型[][] 交错数组名; 
        int[][] array;   

    //声明一个行数长度为 n 的交错数组,列数是不同的,要空着,这个交错数组的数据默认为0
    2、变量类型[][] 交错数组名 = new 变量类型[n][];
        int[][] array = new int[3][];     //3行

    //声明一个行数长度为 n 的交错数组
    3、变量类型[][] 交错数组名 = new 变量类型[n][]{一维数组1,
                                                一维数组2,
                                                .
                                                .
                                                .
                                                一维数组n};
        int[][] array = new int[3][]{new int[]{ 1 , 2 , 3 },
                                     new int[]{ 4 , 5 },
                                     new int[]{ 6 }};

    //声明一个行数长度为 n 的交错数组,数据内容的个数决定了大小
    4、变量类型[][] 交错数组名 = new 变量类型[][]{一维数组1,
                                                一维数组2,
                                                .
                                                .
                                                .
                                                一维数组n};
        int[][] array = new int[][]{new int[]{ 1 , 2 , 3 },
                                    new int[]{ 4 , 5 },
                                    new int[]{ 6 }};

    //声明一个行数长度为 n 的交错数组,数据内容的个数决定了大小
    5、变量类型[][] 交错数组名 = {一维数组1,
                               一维数组2,
                               .
                               .
                               .
                               一维数组n};
        int[][] array = {new int[]{ 1 , 2 , 3 },
                         new int[]{ 4 , 5 },
                         new int[]{ 6 }};

    交错数组使用:
    int[][] array = {new int[]{ 1 , 2 },
                     new int[]{ 3 }};

    1、获取交错数组的长度 
        
        得到全部个数
        交错数组名.Length;
        Console.WriteLine(array.Length);        //长度是 3

        得到多少行
        交错数组名.GetLength(0);
        Console.WriteLine(array.GetLength(0);   //行长度是 2

        得到第 n 行有多少列   
        交错数组名[n-1].Length;
        Console.WriteLine(array[1].Length;      //第二行的列长度是 1

    2、获取交错数组中的元素
        交错数组名[行下标][列下标]            //下标是从0开始的,不能越界访问
        Console.WriteLine(array[0][0]);    //1
        Console.WriteLine(array[0][1]);    //2
        Console.WriteLine(array[1][0]);    //3

    3、修改交错数组中的元素
        交错数组名[行下标][列下标] = 新值;   
        array[0][0] = 114514;
        Console.WriteLine(array[0][0]);    //114514

    4、遍历交错数组
        通过循环来输出交错数组所有内容
        for(int i = 0 ; i < array.GetLenth(0) ; i++ )
        {
                for(int j = 0 ; j < array[i].Lenth ; j++ )
                {          
                   Console.WriteLine(array[i][j]); 
                } 
        }

    5、查找交错数组中的元素
        通过循环来查找输出交错数组中某个元素的位置

        int a = 3;

        for(int i = 0 ; i < array.GetLenth(0) ; i++ )
        {
                for(int j = 0 ; j < array[i].Lenth ; j++ )
                {   
                    if(a == array[i][j])
                    {      
                        Console.WriteLine(array[i][j]);
                        break;
                    }
                } 
        }

转存失败,建议直接上传图片文件

11、 C# 引用

引用类型:string ,数组 ,类。其他类型基本属于值类型
值类型在赋值时把内容拷贝给对方,他变我不变,
引用类型是让两者指向同一个值,变化时都会改变
值类型 和 引用类型 存储在内存的不同区域,值类型存在栈空间,引用类型在堆空间。

    //值类型
    int a = 100;
    int b = a;
    //引用类型
    int[] arr1 = new int[]{1,2,3};
    int[] arr2 = arr1;

    //输出类容 a = 100,b = 100
    Console.WriteLine("a = {0},b = {1}",a,b);
    //输出类容 arr1[0] = 1,arr2[0] = 1
    Console.WriteLine("arr1[0] = {0},arr2[0] = {1}",arr1[0],arr2[0]);

---------------现在进行改变---------------
    b = 99;
    arr2[0] = 88;

    //输出类容 a = 100,b = 99
    Console.WriteLine("a = {0},b = {1}",a,b);
    //输出类容 arr1[0] = 88,arr2[0] = 88
    Console.WriteLine("arr1[0] = {0},arr2[0] = {1}",arr1[0],arr2[0]);

    出现这样的原因,可以理解为,创建的时候,int 类型的值存的是拷贝数值,
    而数组 arr2 也是拷贝了 arr1 的值,但是arr1的值是一个地址,指向了创建
    在堆空间的数据也就是{123},因此 arr2 也得到这个{123}的
    地址,arr2[0] 这个是访问了堆空间创建的数组元素的第一个。所以他修
    改后arr1 和 arr2 共同指向的值就变成了{8823} (这是个人理解,若有错误还请指正)


-----------------------------------------------------------------------------------------

特殊引用类型string
    string是一种特殊的引用类型,string赋值的字符串是在堆空间

    string str1 = "123";
    string str2 = str1;    //这个时候str2得到的是str1开辟的空间的地址

    //输出类容 str1 = 123  str2 = 123
    Console.WriteLine("str1 = "+str1);
    Console.WriteLine("str2 = "+str2);
    
    
    str2 = "321" ;     //这个时候,str2重新开辟了一个新的空间,内容是321,指向了新的地址。
                       //因此str1才没有进行改变

    //输出类容 str1 = 123  str2 = 321
    Console.WriteLine("str1 = "+str1);
    Console.WriteLine("str2 = "+str2);

转存失败,建议直接上传图片文件

12、C# 函数

函数(方法),本质是一个具有名称的代码块,函数是封装代码进行重复使用的一种机制
函数的主要作用:
    1.封装代码
    2.提升代码的复用率
    3.抽象行为
函数写在:
    1.class语句块中
    2.struct语句块中
基本语法:
    static 返回类型 函数名(参数类型 参数名1 , 参数类型 参数名2 , .......)
    {
        //函数逻辑

        return 返回值;
    }
    
    static不是必须的,表示静态;
    返回类型是你这个函数结束之后会得到一个什么类型的值,他和返回值是对应的,void表示返回空;
    参数个数是0-n,可以没有参数也可以有n个。

-------------------------------------------------------------------------------------------

refout是函数参数的修饰符
作用是当传入的值类型在函数内部修改时或者引用类型在内部重新声明时,外部的值会发生改变
out的使用和声明和ref一模一样,区别是:
    1.ref传入的变量必须初始化,out不用
    2.out传入的变量必须在内部赋值,ref不用

***** ref *****

    static int ChangeValue(int val)
    {
        val = 10;
    }

    static int ChangeValueRef(ref int val , ref int b)
    {
        val = 10; //只对a复制,b不赋值,不会错
    }

    static void Main()
    {
        int a =0;
        int b =1; //如果不对变量赋值,那么传入时ref就会错
        ChangeValue(a);
        Console.WriteLine(a);    //a 为0;

        ChangeValueRef(ref a,ref b);
        Console.WriteLine(a);    //a 为10;
    }

***** out *****

    static int ChangeValue(int val)
    {
        val = 10;
    }

    static int ChangeValueOut(out int val , out int b)
    {
        val = 10; //如果不赋值,会错
        b = 100;
    }

    static void Main()
    {
        int a =0;
        int b;      //如果不对变量赋值,那么传入时out不会错
        ChangeValue(a);
        Console.WriteLine(a);    //a 为0;

        ChangeValueOut(out a,out b);
        Console.WriteLine("a = {0},b = {1}",a,b);    //a 为10,b为100;
    }

-----------------------------------------------------------------------------------

变长参数:
关键字:params
    1.params关键字后面必须为数组
    2.数组类型可以是任意的
    3.函数参数可以有别的参数和params关键字修饰的参数,但是params关键字只能有一个且在最后

    static int Sum(params int[] arr)
    {
        int sum =0;
        for(int i = 0 ; i<arr.Lenght ; i++)
        {
            sum += arr[i];
        }
        return sum;
    }

    static void Main()
    {
        Sum();//参数可填写0-n个int型,都可以。
        Console.WriteLine("a = {0},b = {1}",a,b);    //a 为10,b为100;
    }

----------------------------------------------------------------------------------

默认参数:
当参数有默认值时一般称为默认参数,这种情况下调用参数可以不传参数。
注意:默认参数可以有多个也可以全是默认参数,但是默认参数必须放在最后。

static void Speak(string name,staring str = "WTF?")
{
    Console.WriteLine(name+":"+str);    //结果是 Tom:WTF?
}

static void Main()
{
    Speak("Tom");    //结果是 Tom:WTF?
    Speak("Joh","?");//结果是 Joh:?
}

--------------------------------------------------------------------------------
函数重载
重载概念:
    在同一语句块(class或者struct)中,
    函数名可以相同,参数不同(数量,类型或者顺序)
作用:
    1.命名一组功能相似的函数,减少函数名的数量,避免命名空间的污染
    2.提升程序可读性

---------------------------------------------------------------------------------
递归函数:
    递归函数就是自己调用自己
一个正确的递归函数必须要有结束调用的条件,同时这个条件必须要改变达到能够停止的目的

转存失败,建议直接上传图片文件

13、C# 结构体

结构体概念:
    结构体是一种自定义变量类型,他是数据和函数的集合
    在结构体中可以声明各种变量和方法
作用:
    用来表示存在关系的数据集合

基本语法:
    1.结构体一般写在namespace语句块中
    2.结构体的关键字是struct

    struct 自定义结构体名
    {
        //第一部分
        //变量

        //第二部分
        //构造函数(可选)

        //第三部分
        //函数

    }

访问修饰符:
    public:公有的
    private:私有的(结构体中不写的话,默认就是私有的)
构造函数:
    没有返回值,函数名和结构体相同,可以重载,主要是帮我们快速初始化结构体对象

    struct Students
    {
        //第一部分:变量
        public int arg;
        public bool sex;
        public string name;

        //第二部分:构造函数(可选)
        public Students(int age , bool sex = true, string name = "Tom")
        {
            this.age =age;
            this.sex = sex;
            this.name = name;
        }

        //第三部分:函数
        public void sleep()
        {
            Console.WriteLine("{0},今年{1}岁,在睡觉",name,age);
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            //
            Students s;
            s.arg = 24;
            s.sex = true;
            s.name = "Tom"
            s.sleep();

            Students s1 = new Students(18);
            s1.sleep();
        }
    }

转存失败,建议直接上传图片文件