如何在C#中使用指针

2020-06-01 18:01:13王冬梅

3. ++、–运算符

这种算术操作常常用在数组或者字符串等值类型集合,比如下面代码:

 fixed (int* ptr = new int[3] { 1, 2, 3 }) { }
 fixed (char* ptr2 = "abcd") { }

首先ptr默认指向数组在堆上分配的首地址,也就是1的内存地址,当ptr++后会进入到下一个整形元素2的内存地址,再++后又进入下一个int的内存地址,也就是3,很简单吧,我举一个例子:

  unsafe
  {
   fixed (int* ptr = new int[3] { 1, 2, 3 })
   {
    int* cptr = ptr;
			 Console.WriteLine(((long)cptr++).ToString("x16"));
				Console.WriteLine(((long)cptr++).ToString("x16"));
				Console.WriteLine(((long)cptr++).ToString("x16"));
   }
  }

0:000> !clrstack -l
 LOCALS:
  0x00000070c15fea50 = 0x000001bcaac82da0
  0x00000070c15fea48 = 0x0000000000000000
  0x00000070c15fea40 = 0x000001bcaac82dac
  0x00000070c15fea38 = 0x000001bcaac82da8

一图胜千言哈,Console中的三个内存地址分别存的值是1,2,3哈, 不过这里要注意的是,C#是托管语言,引用类型是分配在托管堆中,所以堆上地址会存在变动的可能性,这是因为GC会定期回收内存,所以vs编译器需要你用fixed把堆上内存地址固定住来逃过GC的打压,在本例中就是 0x000001bcaac82da0 - (0x000001bcaac82da8 +4)

三:用两个案例帮你理解

古语说的好,一言不中,千言无用,你得拿一些例子活讲活用,好吧,准备两个例子。

1. 使用指针对string中的字符进行替换

我们都知道string中有一个replace方法,用于将指定的字符替换成你想要的字符,可是C#中的string是不可变的,你就是对它吐口痰它都会生成一个新字符串,🐮👃的是用指针就不一样了,你可以先找到替换字符的内存地址,然后将新字符直接赋到这个内存地址上,对不对,我来写一段代码,把abcgef 替换成 abcdef, 也就是将 g 替换为 d

   unsafe
   {
    //把 'g' 替换成 'd'
    string s = "abcgef";
    char oldchar = 'g';
    char newchar = 'd';
    Console.WriteLine($"替换前:{s}");
    var len = s.Length;
    fixed (char* ptr = s)
    {
     //当前指针地址
     char* cptr = ptr;
     for (int i = 0; i < len; i++)
     {
      if (*cptr == oldchar)
      {
       *cptr = newchar;
       break;
      }
      cptr++;
     }
    }

    Console.WriteLine($"替换后:{s}");
   }

看输出结果没毛病,接下来用windbg去线程栈上找找当前有几个string对象的引用地址,可以在break处抓一个dump文件。