1. 程式人生 > >學習系列之數據類型

學習系列之數據類型

如果 技術 底層 object類 數字交換 包含 int32 對象賦值 處理

一、數據類型初探

電腦是由什麽來存儲所使用的數據? 這個問題用一句話比較籠統的概括,那就是:電腦使用內存來記憶計算時所使用的數據。在現實生活中的數據各種各樣,整數、小數、字符串、字符等等,它們都類型是不一樣的,所以你要想在計算機中使用這些類型,就必須在內存中為它申請一塊合適的空間。

數據類型總結起來有以下幾點:

  (1)C程序是一組函數和數據類型,C++程序是一組函數和類,而C#程序是一組類型聲明;

  (2)類型是一種模板:模板本身不是數據結構,但它詳細說明了由該模板構造的對象的特征;

  (3)C#提供了16種預定義類型:13種簡單類型(數值類型:int,float,double,decimal等;非數值類型:bool,char),3種非簡單類型(object,string,dynamic);

所有的預定義類型都直接映射到底層的.NET類型。C#的類型名稱其實就是.NET類型的別名,所以使用.NET的類型名稱也符合C#語法,不過並不鼓勵這樣做。在C#程序中,應當盡量使用C#類型名稱而不是.NET類型名稱;

(4)除了上面提到的16種預定義類型外,還可以創建自己的用戶定義類型,一共有6種用戶定義類型可以由用戶自己創建,它們是:類(Class)、結構體(Struct)、數組(Array)、枚舉(Enum)、委托(Delegate)和接口(Interface);

技術分享

二 數據類型詳解

1、整型

技術分享

2、浮點類型 技術分享

float數據類型用於較小的浮點數,因為它要求的精度較低。

double數據類型比float數據類型大,提供的精度也大一倍(15位)。

如果在代碼中沒有對某個非整數值(如12.3)硬編碼,則編譯器一般假定該變量是double。

如果想指定該值為float,可以在其後加上字符F(或f),如:

float f = 12.3F;

3、decimal類型

技術分享

decimal類型專門用於進行財務計算,使用decimal類型提供的28位的方式取決於用戶。

要把數字指定為decimal類型,可以在數字的後面加上字符M或(m),如:

decimal d=12.30M;

4、bool(布爾)類型

技術分享

5、char字符類型

技術分享

char類型的字變量是用單引號括起來的。 如‘A‘

如果把字符把在"A"(雙引號)內,編譯器會把它看作是字符串,從而產生錯誤。

6、引用類型(Object類型和字符串類型)

技術分享

三 數據類型存儲雙雄:棧和堆

3.1 棧

  (1)棧是一個內存數組,是一個LIFO(Last In First Out,後進先出)的數據結構。

技術分享

  (2)棧存儲幾種類型的數據:某些類型變量的值(主要是值類型);程序當前的執行環境;傳遞給方法的參數;

  (3)棧具有幾種顯著的特征:數據只能從棧頂插入和刪除;將數據放到棧頂叫做入棧;將數據從棧頂移除叫做出棧

3.2 堆

  (1)堆是一塊內存區域,在堆裏可以分配大塊的內存用於存儲某類型(主要是引用類型)的數據對象;與棧不同,堆裏的內存能夠以任意的順序插入或移除;

(2)堆中的數據不能顯示地刪除,CLR中的自動GC(Garbage Collector,垃圾收集器)會自動清除無主(判斷程序代碼是否將不再訪問某數據項的時候)的堆內存對象。因此,我們可以驕傲地說:媽媽再也不用擔心我的垃圾了

技術分享

四、值類型和引用類型:屌絲和高富帥

  (1)值類型:只需要一段單獨的內存,用於存儲實際的數據;TIP:對於值類型,數據存放在棧裏;(byte,int,long,float,double,struct,enum等)

技術分享

  (2)引用類型:需要兩段內存,第一段存儲實際的數據,它總是位於堆中;第二段是一個引用,指向數據在堆中的存放位置;TIP:對於引用類型,實際數據存放在堆裏,而引用存放在棧裏。(object,string,dynamic,class,interface,delegate,array)

技術分享

  (3)引用類型對象的數據始終存放在堆裏,無論它們是值類型還是引用類型。

技術分享

五 、 數據類型轉換

數據類型在一定的條件下是可以相互轉換的,如將int型數據轉換成double型數據。C#允許使用兩種轉換方式:隱式轉換和顯式轉換。

1、隱式轉換

隱式轉換:從類型A到類型B的轉換可以在所有情況下進行,執行轉換的規則非常簡單,可以讓編譯器執行轉換。

隱式轉換不需要做任何工作,也不需要另外編寫代碼。如將int型數據轉換成double型數據:

int a = 10;double b = a;//隱式轉換

隱式轉換規則是:任何類型A,只要其取值範圍完全包含在類型B的取值範圍內,就可以隱式轉換為類型B。基於這個轉換規則,C#的隱式轉換不會導致數據丟失。需要註意的是我們最常用的簡單類型bool和string沒有隱式轉換。

2、顯式轉換

顯式轉換:從類型A到類型B的轉換只能在某些情況下進行,轉換規則比較復雜,應進行某種類型的額外處理。顯式轉換又叫強制類型轉換,顯式轉換需要用戶明確的指定轉換類型。如將double類型數據轉換成int類型數據:

 double c = 10.5;
 int d = (int)c;//顯示轉換

提醒:

(1)、顯式轉換可能會導致錯誤。進行這種轉換時編譯器將對轉換進行溢出檢測。如果有溢出說明轉換失敗,就表明源類型不是一個合法的目標類型。無法進行類型轉換。

(2)、強制類型轉換會造成數據丟失,如上面的例子中,最終得到的d值為10。

3、通過方法進行類型轉換

(1)、使用ToString()方法。所有類型都繼承了Object基類,所以都有ToString()這個方法(轉化成字符串的方法)。

(2)、通過int.Parse()方法轉換,參數類型只支持string類型。註意:使用該方法轉換時string的值不能為為NULL,不然無法通過轉換;另外string類型參數也只能是各種整型,不能是浮點型,不然也無法通過轉換 (例如int.Parse("2.0")就無法通過轉換)。

            int i;
            i = int.Parse("100");

(3)、通過int.TryParse()方法轉換,該轉換方法與int.Parse()轉換方法類似,不同點在於int.Parse()方法無法轉換成功的情況該方法能正常執行並返回0。也就是說int.TryParse()方法比int.Parse()方法多了一個異常處理,如果出現異常則返回false,並且將輸出參數返回0。

 int i;
 string s = null;
 int.TryParse(s,out i);

(4)、通過Convert類進行轉換,Convert類中提供了很多轉換的方法。使用這些方法的前提是能將需要轉換的對象轉換成相應的類型,如果不能轉換則會報格式不對的錯誤。註意:使用Convert.ToInt32(double value)時,如果 value 為兩個整數中間的數字,則返回二者中的偶數;即 4.5 轉換為 4,而 5.5 轉換為 6。

(5)、實現自己的轉換,通過繼承接口IConventible或者TypeConventer類,從而實現自己的轉換。

六 值傳遞

(一)定義:

值類型在復制的時候,傳遞就是這個值得本身,例如:A同學的筆記復印了一份,給B同學,B同學任意修改筆記的內容,A同學都不會受到影響。

技術分享

(二)例子:

            int n1 = 10;
            int n2 = n1;
            n2 = 20;
            Console.WriteLine(n1);
            Console.WriteLine(n2);
            Console.ReadKey(); //  輸出結果:n1=10;  n2=20;      

分析:變量n1在棧區開辟一塊空間,其地址為0x000000e4a99fe094 ,並且為其賦初值10;

變量n2在棧區也開辟了一塊空間,其地址為0x000000e4a99fe090,並n1值賦給了 n2,n2:10

變量n2的值被重新賦值20,n2:20

(三)內存代碼:

            &n1    0x000000e4a99fe094    n1: 0
            &n1    0x000000e4a99fe094    n1: 10
            &n2    0x000000e4a99fe090    n2: 0
            &n2    0x000000e4a99fe090    n2: 10
            &n2    0x000000e4a99fe090     n2: 20

由此可以看出:n1和n2在棧上的內存地址並不一樣,所以在改變任意其中的而一個值,另一個並不受其影響

(四) 內存示意圖:

技術分享

七 、引用傳遞

(一)定義:

引用類型在復制的時候,傳遞的是對這個對象的引用

(二)例子:

  Person p1 = new Person();
  p1.Name = "張三";
  Person p2 = p1;
  p2.Name="李四";
  Console.WriteLine(p1.Name);
  Console.WriteLine(p2.Name);//   輸出結果:李四 李四

分析:

變量p1在棧中開辟一塊空間,地址為:0x00000095e5efdfd ,並且在堆中也有一塊空間,存放的是new Person();這個對象,其內存空間地址為:0x0000000000000000,並且為p1.name賦值張三

變量p2在棧中也開辟一塊空間,地址為:0x00000095e5efdfc8 ,此時,把p1對象賦值給p2對象,即p2也指向new Person()開辟的這塊空間,其內存空間地址為:0x0000000000000000,隨後,我們把p2.name賦值為 李四,那麽由於p1.name也指向這塊空間,所以,p1.name=”李四”

(四)內存代碼:

 &p1  0x00000095e5efdfd   p1: 0x0000000000000000
 &p2  0x00000095e5efdfc8   p2: 0x0000000000000000

(五)內存示意圖:

技術分享

八 特殊的引用類型

例子:

            string s1 = "張三";
            string s2 = s1;
            s2 = "李四";
            Console.WriteLine(s1)
            Console.WriteLine(s2);

結果:s1=張三 s2=李四 string雖然為引用類型,但是string具有不可變性

九 、方法的參數類型

(一) 兩類參數的定義:

實參:具有實際意義的參數,一般在調用方法時,在方法的括號裏面傳遞的參數為實參

形參:在方法聲明時,方法名後面括號裏面的參數為形參,一般(值傳遞)形參是接收實參傳過來的值

(二) out參數:

1、定義:

在一個方法需要返回多個參數的時候,一般在參數列表裏面聲明out類型的參數,以便輸出多個返回值。其中,out參數只負責把結果輸出,不負責輸入參數。一般out聲明的變量需要在方法體內部賦值

2、例子:

class Program
    {
        static void Main(string[] args)
        {
            int[] ShuZi = { 1,2,3,4,5,6};
            int max1;
            int min1;
            int sum1;
            JiSuan(ShuZi,out max1,out min1,out sum1);
            Console.WriteLine("數組的最大值為:{0},數組的最小值為:{1},數組的和為:{2}",max1,min1,sum1);
            Console.ReadKey();
        }
        public static void JiSuan(int []number,out int max,out int  min,out int sum)
        {
            max = number[0];
            min = number[0];
            sum = 0;
            for (int i = 0; i < 6; i++)
            {
                sum += number[i];
                if (number[i] > max)
                {
                    max = number[i];
                }
                else
                {
                min=number[i];
                }
            }
        }
    }

輸出結果為:最大值:6,最小值:1,和為21

(二)ref參數

1、定義:

即可以傳入值,又可以傳出值,雙向性

(二)例子;

class Program
    {
        static void Main(string[] args)
        {
            int n1=10;
            int n2=20;
            Console.WriteLine("兩個數字交換之前的值為n1={0},n2={1}",n1,n2);
            JiaoHuan(ref n1, ref n2);
            Console.WriteLine("兩個數字交換之後的值為n1={0},n2={1}", n1, n2);
            Console.ReadKey();
        }
        public static void JiaoHuan( ref int n1,ref int n2)
        {
            int temp = n1;
            n1 = n2;
            n2 = temp;
        }
}

結果為:

兩個數字交換之前的值為n1=10,n2=20

兩個數字交換之後的值為n1=20,n2=10

參考資料:《c#圖解教程》

學習系列之數據類型