3.14C#类型之指针(Pointer)

1.指针类型声明

类型为referent类型*的指针变量存储的是类型为referent类型的固定变量或可移动变量的地址。只有非托管类型可为referent类型

任何指针类型可以分配 null

//声明未初始化
//比如:byte*、int*、double*、char*.
referent类型* 指针变量;

//p 是指向整数的指针。
int* p;

//p 是指向整数的指针的指针。
int** p;

//p 是指向整数的指针的一维数组。
int*[] p;

//p 是指向字符的指针。
char* p;

//p 是指向未知类型的指针。
//允许但不推荐
void* p;

2.继承

指针类型没有从 System.Object 继承。

3.类型转换

指针类型与 System.Object 之间不存在转换。

任何指针类型都可以隐式转换为 void* 类型。任何指针类型可以使用强制转换表达式显式转换为任何其它指针类型。

任何整数类型可以显式转换为指针类型,或将任何指针类型显式转换为整数类型。

4.装箱(Boxing)和取消装箱(Unboxing)

指针类型不支持装箱与取消装箱。

5.函数指针(Function pointer)

可以使用 delegate* 语法定义函数指针。需在 unsafe 上下文中使用。

可以调用采用 delegate*(或返回 delegate*)的方法。

//第一种方法使用 System.Func<T1,T2,TResult> 委托类型。
public static T Combine<T>(Func<T, T, T> combinator, T left, T right) => 
    combinator(left, right);


// 第二种方法使用具有相同参数和返回类型的 delegate* 声明。
public static T UnsafeCombine<T>(delegate*<T, T, T> combinator, T left, T right) => 
    combinator(left, right);

只可在 static 函数上使用 & 运算符获取函数的地址。(此规则适用于成员函数和本地函数)。

static int localMultiply(int x, int y) => x * y;
int product = UnsafeCombine(&localMultiply, 3, 4);

6.unsafe关键字

unsafe 关键字表示不安全上下文,任何带指针的运算都需要使用 unsafe 上下文。

若要编译不安全代码,必须指定 AllowUnsafeBlocks 编译器选项。不能通过公共语言运行时验证不安全代码。

如果在类型或成员的声明中使用 unsafe 修饰符,则类型或成员的整个正文范围均被视为不安全上下文。不安全上下文的范围从参数列表到方法的结尾。

//参数包含指针
unsafe static void FastCopy ( byte* ps, byte* pd, int count ) {...}
unsafe static void FastCopy(byte[] src, byte[] dst, int count)
{
    //方法体包含指针
}

还可以使用不安全块从而能够使用该块内的不安全代码。

unsafe
{
    //代码块包含指针
}

7.&(获取固定变量的地址)

& (address-of运算符)用于获取固定变量(驻留在不受垃圾回收器操作影响的存储位置的变量)的地址。

类型A 变量a = 值;
类型A* 指针变量b = &变量a;

8.fixed语句(获取可移动变量的地址)

fixed 语句用于固定可移动变量(驻留在受垃圾回收器影响的存储位置的变量)并获取可移动变量的地址,获取的地址仅在 fixed 语句块中有效。

fixed 语句将为托管(managed)变量设置一个指针(指针为未托管类型),并在该语句的执行过程中“单边锁定”该变量。

fixed语句可以固定 数组、字符串、固定大小的缓冲区(fixed-size buffer)或变量的地址(对象字段、数组元素)或非托管(unmanaged)变量,还可以固定任何实现了GetPinnableReference方法的类型。GetPinnableReference 方法必须返回一个未托管(unmanaged)类型的 ref 变量。比如:System.Span<T> 结构和 System.ReadOnlySpan<T>结构。

fixed 语句仅允许存在于不安全上下文中。 

在 fixed 语句中初始化的指针为只读变量。 如果想要修改指针值,必须声明第二个指针变量,并修改它。

fixed (byte* ps = srcarray, pd = dstarray)
{
    byte* pSourceCopy = ps;

    // point to the next element.
    pSourceCopy++; 
    // invalid: cannot modify ps, as it is declared in the fixed statement.
    ps++; 
}

8.1用于数组

//数组
fixed (double* p = arr) { /*...*/ }
//等同于以下代码
//变量地址(数组元素)
double[] arr = { 0, 1.5, 2.3, 3.4, 4.0, 5.9 };
fixed (double* p = &arr[0]) { /*...*/ }

8.2用于字符串

//字符串
string str = "Hello World";
fixed (char* p = str) { /*...*/ }
//以下语句无效,因为str[0]是char,它是值,不是变量。
fixed (char* p = &str[0]) { /*...*/ }

8.3用于固定大小的缓冲区(Fixed-size buffer)

使用 fixed 语句来创建在数据结构中具有固定大小的数组的缓冲区。当编写与其它语言或平台的数据源进行互操作的方法时,固定大小的缓冲区很有用。 固定的数组可以采用允许用于常规结构成员的任何特性或修饰符。 唯一的限制是数组类型必须为 boolbytecharshortintlongsbyteushortuintulongfloat 或 double

private fixed char name[30];

8.4用于变量地址

//变量地址(对象字段)
class Point
{
    public int x;
    public int y;
}

unsafe private static void ModifyFixedStorage()
{
    Point pt = new Point();

    fixed (int* p = &pt.x)
    {
        *p = 1;
    }
}

9.*(获取指针指向的变量)

*(指针间接运算符,又称”取消引用运算符“)用于获取指针指向的变量,操作数必须是指针类型。

类型A 变量a = 值;
类型A* 指针变量b = &变量a;
*指针变量b = 新值;

原创文章,作者:huoxiaoqiang,如若转载,请注明出处:https://www.huoxiaoqiang.com/csharp/csharplang/14048.html

(0)
上一篇 2021年3月13日 15:58
下一篇 2021年3月15日 01:53

相关推荐

  • 3.11C#类型之元组(ValueTuple)值类型和元组(Tuple)引用类型

    1.元组声明和初始化 元组提供了简洁的语法来将多个数据元素组合在一个轻型数据结构里。 通过声明 ( 和 ) 之间的成员的类型和名称来实例化元组。 2.访问成员 3.析构(Deconstruct)元组 析构的过程恰恰与元组的声明和初始化相反,析构是将已存在的元组析构成多个单独的变量…

    C#语言教程 2021年3月11日
    04600
  • 3.7C#引用类型之数组(Array)

    数组(Array)是一种数据结构,可以用一个统一的数组名和不同的下标(或称索引,index)来确定数组中唯一的元素。根据数组的维度,可以将其分为一维数组、多维数组和交错数组。 数组中的元素是有序的,包含 Length 个元素的数组从 0 索引到 Length-1。 数组中的元素必须属于同一个类型,而且可以随时替换元素。…

    C#语言教程 2021年3月7日
    04380
  • 2.10C#函数成员之终结器(Finalizer)

    终结器声明 终结器(Finalizer),以前称为 析构函数(Destructor),用于在类实例被垃圾回收器回收时执行任何必要的最终清理操作。因此,无法在结构中定义终结器,它们仅用于类。 终结器的声明方式与方法相似,名称为所属类的名称前加~波浪号,不过既不能包含参数和可访问性修饰符,也不能进行显式调用。 重载 终结器…

    C#语言教程 2021年2月10日
    05390

发表回复

登录后才能评论