C#中使用指针

作者: 飞刀 www.ASPCool.com 时间:2001-11-12 12:08:20 阅读次数:1328

我想许多C程序员不愿意学习Java的原因就是Java不支持指针,但是现在类似于Java的C#却已经支持了指针,你可以使用unsafe关键字来告诉编译器下面的函数或者代码是不安全的。一旦你使用了unsafe,那么你就可以在unsafe区域中使用指针。

程序1

using System;
class nish
{
    unsafe static void Increment(int* p)
    {
        //increment the int pointed to by p 
        *p = *p + 1;
    }
    public static void Main()
    {
        int i = 1;
        //we pass the address of the int to the function as it expects a pointer 
        unsafe Increment(&i);
        //now we print out the value of i 
        Console.WriteLine(i);
    }
}  

当你运行这个程序,你将会看到输出结果2。这是因为你已经将变量i的地址送给了函数Increment来处理。变量i建立于栈,&i则表示它在栈中的地址。这样在函数Increment中,p就指向i的地址,当我们对*p1时,实际上是对变量i进行增加。

程序2

下面的程序将会让你更清楚的了解:

using System;
class nish
{
    unsafe public static int Main()
    {
        int j = 100;
        int k = 100;
        Console.WriteLine("address of j={0} and address of k={1}", (int)&j, (int)&k);
        Console.WriteLine("j={0} k={1}", j, k);
        int* p;
        p = &j;
        Console.WriteLine("p now points to {0}", (int)p);
        *p = 200;
        Console.WriteLine("j={0} k={1}", j, k);
        p = &k;
        Console.WriteLine("p now points to {0}", (int)p);
        *p = 300;
        Console.WriteLine("j={0} k={1}", j, k);
        return 0;
    }
}

当运行上面的程序,我们将得到下面的结果。你会看到一些你熟悉的东东,下面的输出结果将会清楚的看到程序执行的过:

address of j=1244312 and address of k=1244308 
j=100 k=100 
p now points to 1244312 
j=200 k=100 
p now points to 1244308 
j=200 k=300 

首先将变量的j的地址赋给p,这样当我们改变*p时,j的值也将自动改变。接着我们将p指向变量k的地址,这时改变*p则是在改变k

同样需要清楚的就是变量p也有自己的地址,下面的程序将会清楚的告诉您一切。

程序 3

using System;
class nish
{
    public static void Main()
    {
        unsafe
        {
            int a = 100;
            int* p;
            p = &a;
            Console.WriteLine("address of a is {0}", (int)&a);
            Console.WriteLine("p now points to {0}", (int)p);
            Console.WriteLine("address of the pointer variable p is {0}", (int)&p);
        }
    }
}

一运行上面的代码,我们将获得下面显示的输出。你将同样获得一些类似的输出,注意这里unsafe关键字的使用。

address of a is 1244312 
p now points to 1244312 
address of the pointer variable p is 1244308 

1244308是指针变量p的地址,而1244312则是指针p所指向的地址,我们使用*p来获得。

程序 4

Okey。在最后的一个程序中,我将向大家介绍如何使用指针来操作字符串。在这个程序中存在一个程序来将一段字符串通过异或运算进行编码解码的操作。如果您将一段字符串送入这个函数这个字符串将会被编码,如果您将一段已经编码的字符送入这个函数,这段字符串将会被解码。当这并不是一个安全的加密方法,我仅仅是想通过这个例子来演示一下指针的作用。

using System;
class nish
{
    public static void Main()
    {
        string s = "Code Project is cool";
        Console.Write("the original string : ");
        Console.WriteLine("{0}\r\n", s);

        char[] b = new char[100];
        s.CopyTo(0, b, 0, 20);

        Console.Write("the encoded string : ");
        unsafe fixed (char* p = b) NEncodeDecode(p);
        for (int t = 0; t < 20; t++)
            Console.Write(b[t]);
        Console.WriteLine("\r\n");

        Console.Write("the decoded string : ");
        unsafe fixed (char* p = b) NEncodeDecode(p);
        for (int t = 0; t < 20; t++)
            Console.Write(b[t]);
        Console.WriteLine();

    }
    unsafe public static void NEncodeDecode(char* s)
    {
        int w;
        for (int y = 0; y < 20; y++)
        {
            w = (int)*(s + y);
            w = w ^ 5;
            *(s + y) = (char)w;
        }
    }
}

下面是我得到的输出,你也同样可以得到:

  the original string : Code Project is cool 
   
  the encoded string : Fja`%Uwjo`fq%lv%fjji 
   
  the decoded string : Code Project is cool 

本例中,你会发现一个新的关键字--fixed。当你在语句或函数之前使用fixed时,你是在告诉.Net平台的垃圾回收器,在这个语句或函数执行完毕前,不得回收其所占的内存空间。fixed关键字只能在不安全的代码中使用。本例中如果不使用fixed关键字,那么这段程序的执行的结果是不可预知的,因为垃圾回收器会不断的回收这些可控制代码的所占用的内存空间。幸运的是,编译器不会允许您指向可控制变量,除非您使用了fixed关键字。

在这个函数中,你看到我使用了*(s+y)表达式。s是指向字符串的地址(注意是首地址)。y则通过循环从0增加到19。这样*(s)给我们的地址是1000,*(s+1)则是1002,*(s+2)则是1004,以此类推。编译器知道我指向的是一个字符数据,因此第次就向前移动两个字节,因为char是16位的(这与c是不同的,c中char只占8位)。

结论

使用不安全代码时,必须十分小心,任何细小的错误,甚至是类型错误,都会导致输出结果的不可遇知,而且这种错误是很难调试发现。当然如果您是C/C++程序员,您已经对指针了解得十分透彻,那么当我的话没有说。呵呵,祝好运。 (编译:http://www.aspcn.com 飞刀)

Contributors: FHL