C#基础知识--Day06

Day06

交错数组

  1. 元素为数组的数组,每个元素都是一个新的一位数组。
  2. 语法:
-- 定义
数据类型[[]数组名= new 数据类型[元素总数][];
stringlil] array = new string[3][1];
--赋值
数组名[索引]= new 数据类型[子元素数];
array[0]=  new  string[2];
--读写元素
数组名[元素索引][子元素索引]

输出一个交错数组

static void Main(string[] args)
{
    //[行,列]
    int[,] arr = null; // null;
    arr = new int[5, 3];
    arr[0, 2] = 100;
    //交错数组  参数数组
    int[][] array02;//null
                    //创建具有4个元素的交错数组
    array02 = new int[4][];
    //创建一维数组 赋值给 交错数组的第一个元素

    array02[0] = new int[3];
    array02[1] = new int[5];
    array02[2] = new int[4];
    array02[3] = new int[1];

    // 将数据1赋值给交错数组的第一个元素 的 第一个元素
    array02[0][0] = 1;
    array02[1][2] = 2;
    array02[1][4] = 3;
    array02[2][2] = 4;
    array02[2][3] = 5;

//遍历数组里面所有数
    /*foreach (int[] array in array02)
    {
        foreach (int element in array)
        {
            Console.WriteLine(element);
        }
    }*/

    //数据类型 变量名
    //int a;
    //int[] arr;
    //array02.Length 交错数组元素数(理解为 :行数)
    for (int r = 0; r < array02.Length; r++)
    {
        for (int c = 0; c < array02[r].Length; c++)
        {
            Console.Write(array02[r][c] + "\t");
        }
        Console.WriteLine();
    }

}

在这里插入图片描述

参数数组——params

  1. 在方法形参中通过关键字params 定义。
  2. 方法调用者可以传递数组,也可以传递一组数据类型相同的变量,甚至可以不传递参数。
  3. 注意:
    参数数组必须在形参列表中的最后一位。只能在一维数组上使用params 关键字。
  4. WriteLine中使用占位符,就是通过参数数组实现的。

使用参数数组定义整数相加的方法

  1. 类型确定个数不确定的情形使用参数数组。
  2. params 参数数组
  3. 对于方法内部而言:就是个普通数组
    对于方法外部(调用者)而言:可以传递数组,传递一组数据类型相同的变量集合,可以不传递参数。
  4. 作用 :简化调用者调用方法的代码、
static void Main2()
{
    int result01 = Add(new int[] { 1, 34, 43, 54, 78 });
    int result02 = Add(1, 34, 43, 54 ,78);
    //Console.WriteLine("{0}{1}{2}"), new object[] { 1, 2, 3, 4, 5 }
    Console.WriteLine("{0}{1}{2}", 1, 2, 3, 4, 5);
}

private static int Add(params int[] arr)
{
    int sum = 0;
    foreach (var item in arr)
    {
        sum += item;
    }
    return sum;
}

数据类型

  1. 值类型:存数据本身。int bool char(比较小的)
  2. 引用类型:存引用(内存地址)。string Array(int[])(比较大的)——如果是引用类型不需要返回值,传递的是地址
  3. 方法内部声明的变量都在栈上(不管是值类型还是引用类型)

引用传进来,修改堆中数组对象。

private static void OrderBy(int[] array)//不需要返回值的
private static int OrderBy(int[] array)//不需要返回值的
//array = newArray; 替换引用 方法外不会受到影响
//array[o]= newArray[o]; 通过引用修改堆中数组对象(如果有修改堆中的数据的代码改void就不用添加代码了)
  1. 方法执行在栈中 ,所以在方法中声明的变量都在栈中
  2. 因为值类型直接存储数据,所以数据存储在栈中

arr改的是栈里面的数据
arr[]改的是堆里面的数据

局部变量

  1. 定义在方法内部的变量。
  2. 特 点 :
    -没有默认值,必须自行设定初始值,否则不能使用。
    -方法被调用时,存在栈中,方法调用结束时从栈中清除。

值类型和引用类型(局部变量)

  1. 值类型:
    声明在中,数据存储在中。
  2. 引用类型:
    声明在中,数据存储在中,栈中存储该数据的引用。

分配图

在这里插入图片描述

垃圾回收器

  1. GC(Garbage Collection)是CLR 中一种针对托管堆自动回收释放内存的服务。
  2. GC线程从栈中的引用开始跟踪,从而判定哪些内存是正在 使用的,若GC 无法跟踪到某一块堆内存,那么就认为这块内存不再使用了,即为可回收的。

成员变量

  1. 定义在类中方法外的变量
  2. 特 点 :
    – 具有默认值。
    – 所在类被实例化后,存在堆中,对象被回收时,成员变量从堆中清除。
    – 可以与局部变量重名。

值类型与引用类型(成员变量)

  1. 值类型:
    声明在中,数据存储在中。
  2. 引用类型:
    声明在中,数据存储在堆的另一块空间

分配图

在这里插入图片描述

应用

(1)

static void Main()
{
    //a在栈中  1在栈中
    int a = 1;
    int b = a;
    a = 2;
    Console.WriteLine(b);//?

    //arr在栈中存储数组对象的引用(内存地址) 1在堆中
    int[] arr = new int[] { 1 };
    int[] arr2 = arr; 
    arr[0] = 2;//修改的是堆中的数据
    Console.WriteLine(arr2[0]);//?
}

在这里插入图片描述
(2)

int[] arr = new int[] { 1 };
int[] arr2 = arr; 
arr[0] = 2;//修改的是堆中的数据
arr = new int[] { 2 };//修改的是栈中存储的应用
Console.WriteLine(arr2[0]);//?

![在这里插入图片描述](https://img-blog.csdnimg.cn/c668c6a114464ab3b5ffd516aa63ccda.png![在这里插入

(3)

string s1 = "男";
string s2 = s1;
s1 = "女";//修改的是栈中存储的引用
//s1[0] =女
//堆中的文字 不能修改
Console.WriteLine(s2);

在这里插入图片描述
(4)

 static void Main()
 {
     int a = 1;
     int[] arr = new int[] { 1 };
     Fun1(a, arr);//实参将 数据1. 数据引用  赋值给形参
     Console.WriteLine(a);//?
     Console.WriteLine(arr[O]);//?
 }
 private static void Fun1(int a, int[] arr)
 {
     a = 2; 
     arr[0] = 2;
 }

在这里插入图片描述
(5)

int num01 = 1, num02 = 1;
bool r1 = num01 == num02;//?true 因为值类型存储的是数据,所以比较的是数据
int[] arr01 = new int[] { 1 }, arr02 = new int[] { 1 };
bool r2 = arr01 == arr02;//?false  因为引用类型存储的是数据的引用,所以比较的是存储的引用
bool r3 = arr01[0] == arr02[0];//这种比较的才是数据

值参数

  1. 值参数: 按值传递 - 传递实参变量存储的内容**
  2. 作用:传递数据(信息)
private static void Fun2(int a,int[] arr)
{
    a = 2;
    //arr[0] = 2;
    //arr = new int[] { 2 };
}

引用参数

  1. 使用ref关键字修饰。
  2. 引用参数 : 按引用传递 – 传递实参变量自身的内存地址(调用方法时复制实参变量在栈中的引用。)
  3. 作用:改变数据
  4. 语法:
    …… (ref数据类型参数名[,ref 数据类型 参数名])
private static void Fun3(ref int a)
{//方法内部修改引用参数 实质上就是在修改实参变量
    a = 2;
}

输出参数

  1. 使用out关键字修饰
  2. 输出参数: 按引用传递 传递实参变量自身的内存地址
  3. 语 法 :
    … …(out 数据类型参数名[,out 数据类型 参数名])
private static void Fun4(out int a)
{
    a = 2;
}

引用参数(ref)和输出参数(out)的区别

  1. 区别1: 方法内部必须为输出参数赋值
  2. 区别2 : 输出参数传递之前可以不赋值
    (ref要求实参必须在传递前进行赋值,
    out 要求形参离开方法前必须赋值。)
  3. 实际上就是直接在实参的内存上修改,不像值传递将实参的值拷贝到另外的内存地址中才修改。

TryParse

  1. TryParse方法,返回2个结果
  2. 通 过bool表达式配合TryParse使用,防止类型转换失败。
    在这里插入图片描述
static void Main()
{
    int num01 = 100, num02 = 200;
    Swop(ref num01, ref num02);

    int area; 
    int perimeter;
    CalculateRect(15, 20, out area, out perimeter);

    //int number = int.Parse("250+");
    int result;
    //TryParse方法,返回2个结果

    //out : 转换后的结果
    //返回值 : 是否可以转换
    //将string类型转化成int类型,若转化成功,将值赋给num1,并返回true;若转化失败,返回false。
    bool re = int.TryParse("250+", out result);
}

练习1:定义 两个整数交换的方法

private static void Swop(ref int one, ref int two)
    {
        int temp = one;
        one = two;
        two = temp;
    }

练习2 : 根据矩形长、宽计算面积(长* 宽)与周长( (长+宽)*2

private static void CalculateRect(int lenght, int width, out int area, out int perimeter)
{
    area = lenght * width;
    perimeter = (lenght + width) * 2;
}

拆装箱

装箱操作(box):“比较”消耗性能(最)

  1. 值类型隐式转换为 object 类型或由此值类型实现的任何接口类型的过程。
  2. 内部机制:
    1.在堆中开辟内存空间
    2.将值类型的数据复制到堆中
    3.返回堆中新分配对象的地址
int a = 1;
object o = a;

//比这种
/*int a = 1;
int b = a;*/

拆箱操作(unbox):“比较”消耗性能

  1. 从object 类型到值类型或从接口类型到实现该接口的值类
    型的显式转换。
  2. 内部机制:
    1.判断给定类型是否是装箱时的类型
    2.返回已装箱实例中属于原值类型字段的地址
int b = (int)o;

字符串和int直接相加就是一次装箱操作

//1
int num = 100;
string str = num.ToString();//未装箱
//2
string str02 = "" + num;
//上面那句话内部执行代码;string str02 = string.Concat(.,num) //int==>object

形参object类型,实参传递值类型,则装箱
可以通过 重载、泛型 避免。

注意

  1. 拆箱后的类型必须与装箱时的类型相同。
  2. 伴随拆箱的字段复制步骤不属于拆箱过程。
  3. 装箱和拆箱不是互逆的过程,装箱的性能开销远大于拆箱。

string

  1. 字符串池
    字符串常量在创建前,首先在字符串池中查找是否存在相同文本。如果存在,则直接返回该对象引用;如果不存在,则开辟空间存储。
    目的:提高内存利用率。
string s1 = "八戒";
string s2 = "八戒";//同一个数据地址,同一个字符串

string s3 = new string(new char[] { '八', '戒' });
string s4 = new string(new char[] { '八', '戒' });
bool r1 = object.ReferenceEquals(s3, s4);//不同数据地址,不同字符串
  1. 字符串的不可变性
    字符串常量一旦进入内存,就不得再次改变。因为如果在 原位置改变会使其他对象内存被破坏,导致内存泄漏。当遇到 字符串变量引用新值时,会在内存中新建一个字符串,将该字符串地址交由该变量引用。
重新开辟空间 存储 新字符串,再替换栈中引用

s1 = "悟空";
Console.WriteLine(s1);
//将文本“八戒”改为“悟空"//?NO
//而是重新开辟空间 存储 新字符串,再替换栈中引用

每次修改,都是重新开辟新的空间存储数据,替换栈中引用

  1. 例子:尽量避免这种情况
string strNumber = "";
for (int i = 0; i < 10; i++)
{
    //第一次循环:""+"0"(空加0)
    //"0"+"1"每次拼接产生新的对象 替换引用(原有数据成为一个垃圾)
    strNumber = strNumber + i.ToString();
}
Console.WriteLine(strNumber);//?  0123456789

可变字符串:StringBuilder

(结果跟上面的一样)

  1. 一次开辟可以容纳10个字符大小的空间
  2. 优点:可以在原有空间修改字符串,避免产生垃圾(但是不是在原有的上面扩,而是新开辟了一个空间将所有东西拷贝进去再)
  3. 适用性:频繁对字符串操作(增加 替换 移除)
StringBuilder builder = new StringBuilder();
    for (int i = 0; i < 10; i++)
    {
        builder.Append(i);
    }
    string result = builder.ToString();

每日一练:

  1. 单词反转 How are you ==》 you are How
  2. 字符反转 How are you ==》 uoy era woH
  3. 查找指定字符串中不重复出现的文字(重复的文字保留1个)
  • 23
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值