[C#] C#中的指针

RuntimeMapMaker3D-Pro在这里插入图片描述


  C#在有限的范围内支持指针。C#的指针只不过是一个持有另一类型内存地址的变量。但是在C#中,指针只能被声明为持有值类型和数组的内存地址。与引用类型不同,指针类型不被默认的垃圾收集机制所跟踪。出于同样的原因,指针不允许指向引用类型,甚至不允许指向包含引用类型的结构类型。我们可以说,指针只能指向非托管类型,包括所有基本数据类型、枚举类型、其他指针类型和只包含非托管类型的结构。

声明指针类型

声明指针类型的一般形式如下所示,

type *variable_name;

其中 * 称为取消引用运算符。例如下面的语句

int *x ;

  声明一个指针变量x,它可以保存一个int类型的地址。引用操作符(&)可以用来获取一个变量的内存地址。

int x = 100;  

&x 给出了变量 x 的内存地址,我们可以将它分配给一个指针变量

int* ptr = &x;.  
Console.WriteLine((int)ptr) // Displays the memory address  
Console.WriteLine(*ptr) // Displays the value at the memory address.  

不安全代码

  C#语句可以在安全或不安全的情况下执行。通过使用关键字unsafe标记为不安全的语句在垃圾收集器的控制之外运行。记住,在C#中,任何涉及指针的代码都需要一个不安全的上下文。

  我们可以通过两种不同的方式使用 unsafe 关键字。它可以用作方法、属性和构造函数等的修饰符。例如

// Author: [email protected]  
using System;  
class MyClass  
{  
    public unsafe void Method()  
    {  
        int x = 10;  
        int y = 20;  
        int* ptr1 = &x;  
        int* ptr2 = &y;  
        Console.WriteLine((int)ptr1);  
        Console.WriteLine((int)ptr2);  
        Console.WriteLine(*ptr1);  
        Console.WriteLine(*ptr2);  
    }  
}  
class MyClient  
{  
    public static void Main()  
    {  
        MyClass mc = new MyClass();  
        mc.Method();  
    }  
}  

  关键字unsafe也可以用来标记一组语句为不安全,如下图所示。

// Author: [email protected]  
//unsafe blocks  
using System;  
class MyClass  
{  
    public void Method()  
    {  
        unsafe  
        {  
            int x = 10;  
            int y = 20;  
            int* ptr1 = &x;  
            int* ptr2 = &y;  
            Console.WriteLine((int)ptr1);  
            Console.WriteLine((int)ptr2);  
            Console.WriteLine(*ptr1);  
            Console.WriteLine(*ptr2);  
        }  
    }  
}  
class MyClient  
{  
    public static void Main()  
    {  
        MyClass mc = new MyClass();  
        mc.Method();  
    }  
}  

固定住对象

  在垃圾收集过程中,C#垃圾收集器可以随意移动内存中的对象。C#提供了一个特殊的关键字fixed来告诉垃圾收集器不要移动一个对象。这意味着这在内存中固定了值类型所指向的位置。这就是C#中所谓的固定住。

  固定语句通常通过生成向垃圾收集器描述的表来实现,哪些对象将在可执行代码的哪些区域中保持固定。因此,只要在执行固定语句期间实际上没有发生垃圾收集器进程,与此相关的成本就非常低。但是,当垃圾收集器进程确实发生时,固定对象可能会导致堆碎片化。因此,只有在绝对必要时才应该Fixed对象,并且只能在最短的时间内Fixed。

指针和方法

  这些点可以作为参数传递给一个方法,如下所示。这些方法也可以返回一个指针。

// Author: [email protected]  
using System;  
class MyClass  
{  
    public unsafe void Method()  
    {  
        int x = 10;  
        int y = 20;  
        int* sum = swap(&x, &y);  
        Console.WriteLine(*sum);  
    }  
    public unsafe int* swap(int* x, int* y)  
    {  
        int sum;  
        sum = *x + *y;  
        return}  
}  
class MyClient  
{  
    public static void Main()  
    {  
        MyClass mc = new MyClass();  
        mc.Method();  
    }  
}  

指针和转换

  在C#中,指针类型不继承于对象,指针类型和对象之间不存在转换。这意味着指针不支持装箱和拆箱。但是C#支持不同的指针类型和指针类型与整型之间的转换。

C# 支持不安全上下文中的隐式和显式指针转换。隐式转换是

  1. 从任何类型的指针类型到 void * 类型。
  2. 从空类型到任何指针类型。

任何显式类型转换都需要强制转换运算符 (())。显式类型转换是

  1. 从任何指针类型到任何其他指针类型。
  2. 从 sbyte、byte、short、ushort、int、uint、long、ulong 到任何指针类型。
  3. 从任何指针类型到 sbyte、byte、short、ushort、int、uint、long、ulong 类型。

例如

char c = 'R';  
char* pc = &c;  
void* pv = pc; // Implicit conversion  
int* pi = (int*) pv; // Explicit conversion using casting operator  

指针运算

  在非安全的上下文中,++ 和 - 运算符可以应用于除 void * 类型之外的所有类型的指针变量。因此,对于每个指针类型 T*,以下运算符都被隐式重载。

T* operator ++ (T *x);  
T* operator -- (T *x);  

  对于 T* 类型的指针变量,++ 运算符将 sizeof(T) 添加到变量中包含的地址,- 运算符从变量中包含的地址中减去 sizeof(–)。

  在非安全的上下文中,可以从指针变量中添加或减去常量。类似地,可以从另一个指针变量中减去一个指针变量。但是在 C# 中不能添加两个指针变量。

  在非安全的上下文中 ==, ! =、<、>、< =、> = 运算符可以应用于所有指针类型的值类型。指针变量与常量或另一个指针变量的乘法和除法在 C# 中是不可能的。

栈分配

  在非安全的上下文中,局部声明可能包括栈分配初始化程序,它从调用栈分配内存。

  stackalloc T[E] 要求 T 是非托管类型,E 是 int 类型的表达式。上面的构造从调用栈中分配 E * sizeof(T) 个字节,并生成一个指向新分配块的 T* 类型的指针。 E 为负,抛出 System.OverFlowException。如果没有足够的内存可供分配,则会引发 System.StackOverflowException。

  新分配内存的内容未定义。无法隐式释放使用 stackalloc 分配的内存。相反,一旦函数返回,所有栈分配的内存块都会自动丢弃。

class Test  
{  
   char *buffer =  
}  

指针和数组

  在 C# 中,可以使用指针符号访问数组元素。

// Author: [email protected]  
using System;  
class MyClass  
{  
    public unsafe void Method()  
    {  
        int[] iArray = new int[10];  
        for (int count = 0; count < 10; count++)  
        {  
            iArray[count] = count * count;  
        }  
        fixed (int* ptr = iArray)  
            Display(ptr);  
        //Console.WriteLine(*(ptr+2));  
        //Console.WriteLine((int)ptr);   
    }  
    public unsafe void Display(int* pt)  
    {  
        for (int i = 0; i < 14; i++)  
        {  
            Console.WriteLine(*(pt + i));  
        }  
    }  
}  
class MyClient  
{  
    public static void Main()  
    {  
        MyClass mc = new MyClass();  
        mc.Method();  
    }  
} 

指针和结构

  C# 中的结构是值类型。如果结构仅包含值类型作为其成员,则指针可以与结构一起使用。例如

// Author: [email protected]  
using System;  
struct MyStruct  
{  
    public int x;  
    public int y;  
    public void SetXY(int i, int j)  
    {  
        x = i;  
        y = j;  
    }  
    public void ShowXY()  
    {  
        Console.WriteLine(x);  
        Console.WriteLine(y);  
    }  
}  
class MyClient  
{  
    public unsafe static void Main()  
    {  
        MyStruct ms = new MyStruct();  
        MyStruct* ms1 = &ms;  
        ms1->SetXY(10, 20);  
        ms1->ShowXY();  
    }  
} 

你可能感兴趣的:(c#,c#)