C#中指针使用总结
C#為了類型安全,默認并不支持指針。但是也并不是說C#不支持指針,我們可以使用unsafe關(guān)鍵詞,開啟不安全代碼(unsafe code)開發(fā)模式。在不安全模式下,我們可以直接操作內(nèi)存,這樣就可以使用指針了。在不安全模式下,CLR并不檢測unsafe代碼的安全,而是直接執(zhí)行代碼。unsafe代碼的安全需要開發(fā)人員自行檢測。
一、Vs2010中開啟unsafe code 的方式
在方法、類、代碼塊中使用unsafe關(guān)鍵詞,如:
unsafe static void Main(string[] args){ //代碼}
unsafe
{
//代碼塊
}
然后再項目上點擊鼠標右鍵,選擇“屬性”,在“生成”選項卡中選中“允許不安全代碼”
二、C#可以定義為指針的類型有
sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool,
struct(結(jié)構(gòu)體),結(jié)構(gòu)體中只能包括非托管類型。
三、C#指針操作符
| 操作符 | 說明 |
| * | 取值運算符 |
| & | 取址運算符 |
| -> | 通過指針處理結(jié)構(gòu)體中的數(shù)據(jù)(獲取或賦值) |
| ++與– | 指針增、減操作 |
| fixed | 用戶暫時固定托管代碼中引用類型的位置。 |
| Stackallc | 分配內(nèi)存 |
例如分配內(nèi)存
char* cptr = stackalloc char[26];
for (int i = 0; i < 26;i++ )
{
cptr[i] = (char) (i+65);
}
for (int i = 0; i < 26;i++ )
{
Console.WriteLine(string.Format("{0}:{1}",(int)&cptr[i],cptr[i]));
}
至于釋放內(nèi)存,我在msdn上搜索了一下,c#并沒有提供釋放內(nèi)存的函數(shù)。而msdn給的解釋是:分配的內(nèi)存會在方法結(jié)束后自動釋放。
fixed的應(yīng)用會在下面的類與指針中做說明。
四、C#指針的定義
| 定義指針 | 說明 |
| int* p | 整形指針 |
| int** p | 指向整形指針的指針 |
| char* c | 指向字符的指針 |
| int*[] arr | 整形一維數(shù)組指針 |
五、指針的使用
1.整形指針的使用
int i=10; int* iptr = &i; //將i的地址賦值給iptr Console.WriteLine((int)&iptr); //取iptr得地址 Console.WriteLine(*iptr); //取iptr指向的值
2.結(jié)構(gòu)體指針
struct Location
{
public int X;
public int Y;
}
unsafe static void Main(string[] args)
{
Location location;
location.X = 10;
location.Y = 5;
Location* lptr = &location;
Console.WriteLine(string.Format("location 地址{0},lptr地址{1},lptr值{2}",(int)&location,(int)lptr,*lptr));
Console.WriteLine(string.Format("location.x的地址{0},location.x的值{1}",(int)&(lptr->X),lptr->X));
Console.WriteLine(string.Format("location.y的地址{0},location.y的值{1}", (int)&(lptr->Y), lptr->Y));
}
以上代碼輸出結(jié)構(gòu)體的地址和值。我們在操作地址時,可以直接看到結(jié)構(gòu)體的內(nèi)存分配。
3.指針與參數(shù)
public static unsafe int* Add(int* x,int* y)
{
int sum = *x + *y;
return ∑
}
int i = 2, j = 3;
Console.WriteLine(*Add(&i,&j));
4.類與指針,因為類是托管類型,我們知道類受到“垃圾收集”的影響,它的內(nèi)存地址是不固定的。而且類是引用類型,是不能聲明為指針類型的。而指針分配內(nèi)存后,不受“垃圾收集”影響,地址是固定的。所以為了使用類中的數(shù)據(jù),我們需要臨時固定類的地址。這就用到fixed關(guān)鍵詞,用fixed后,就可以操作類中的值類型了。
class People
{
public int Age; //值類型,不可以是屬性
public void ShowAge()
{
Console.WriteLine(Age);
}
}
People people = new People();
people.Age = 10;
fixed(int* agePtr=&people.Age)
{
*agePtr += 1;
}
people.ShowAge(); //11
通過以上的方法,我們可以操作值類型,也可以獲得值類型的地址。但如何獲取類的內(nèi)存地址?我們可以使用GCHandle,來自System.Runtime.InteropServices命名空間。GCHandle提供從非托管內(nèi)存訪問托管對象的方法。如下:
object p = new People(); GCHandle h = GCHandle.Alloc(p, GCHandleType.Pinned); IntPtr addr = h.AddrOfPinnedObject(); Console.WriteLine(addr.ToString()); h.Free();
六、C#中使用指針的總結(jié)
1.引用類型不能定義為指針
2.msdn上說enum可以定義為指針,可是我真不知道它的用處是什么。所以在指針的類型中并沒有出現(xiàn)enum類型。
3.c#中的指針操作遠遠不如c/c++,如果想學習指針的話,還是用c/c++
4.微軟并不推薦使用unsafe code模式,也不推薦使用指針。在msdn官方文檔中,唯一一句贊美C#指針的話就是“合理的使用指針,可以提高程序的執(zhí)行速度”。但是什么是“合理的使用”?我下載了msdn上的幾個關(guān)于C#指針的實例代碼,發(fā)現(xiàn)用的最多的是調(diào)用api函數(shù),在api函數(shù)中,有大量的指針參數(shù)。
5.fixed的使用可能產(chǎn)生存儲碎片,因為它們不能移動。如果確實需要固定對象,固定對象的時間應(yīng)該越短越好。
6.可以使我們了解非托管類型的內(nèi)存分配。
總結(jié)
- 上一篇: 星型模式、雪花模式和事实星座模式
- 下一篇: 概念:弱监督学习