Click here to Skip to main content
Click here to Skip to main content

Getting unsafe with pointers in C#

, 12 May 2002
Rate this:
Please Sign up or sign in to vote.
Introduction to unsafe code

Introduction

I guess one of the reasons a lot of C programmers could not digest Java was because Java didn't let them manipulate pointers. Anyway C# supports pointers. You can use the unsafe keyword to inform the compiler that the following function or block is unsafe. And once you do that you can use pointers in that unsafe area.

Program 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);
    }
}

When you run the program, you'll see 2 printed on screen. This is because you have passed the address of the variable i to the function Increment. Variable i is created on the stack. &i gives its address on the stack. Thus when within the function Increment, p is pointing to i's address. Thus when we add 1 to *p we are actually incrementing i;

Program 2

The following program should make things clearer to you.

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;
    }	
}

When I ran it I got the below output. You would get something similar. The output will clearly give an idea of what's going on.

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

First we assign the address of j to p. Thus when we change *p we automatically change j. Then we change p to point to k's address and thus when we change *p we are actually changing k

Also remember than the pointer variable p itself has an address. This following program will make that clear.

Program 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);
        }		
    }	
}

On running it I got the below output. You'll get similar output too. Notice the alternate use of the unsafe keyword

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

In my case 1244308 is the address of the pointer variable p. The contents of that address is 1244312 which is an address. Thus when we take *p we are referring to the address 1244312. Try printing out *p and it will print out the contents of 1244312 which happens to be 100 in the above case. I hope things are clearer now.

Program 4

Okay. In this final program I'll show you how to use pointers to manipulate a character string. In this program there is a function that takes a string and encodes or decodes it using XOR. If you pass a string to it it will encode it and if you pass the encoded string to it, it will decode it. Of course this is by no way a safe or practical encryption method. I am using it merely to demonstrate the use of pointers.

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;
        }		
    }		
}

This is the output I got. You should get this too.

the original string : Code Project is cool

the encoded string : Fja`%Uwjo`fq%lv%fjji

the decoded string : Code Project is cool

You will notice a new keyword here called fixed. When you precede a statement or a function with fixed you are instructing  the .Net garbage collector not to relocate that variable till the statement or function has finished. The fixed keyword is only allowed in an unsafe context. If we don't use fixed there is little point in using pointers as the results would be unpredictable if the garbage collector keeps relocating the managed variables. Luckily the compiler won't let you point to managed variables unless you specify the fixed keyword.

In the function you can see that I use the expression *(s+y). s is the address pointing to the string. y is incremented starting from 0 and ending upto 19. Thus when I give *(s+y) I get the pointers to characters in those locations. Lets assume s points to 1000. Thus *(s) will give me the contents of location 1000. Now if I give *(s+1) I get the contents of 1002, and for *(s+2) I get 1004 and so on. The compiler knows I am pointing to a character array and thus each increment jumps 2 bytes as char is a 16 bit value. C# actually maps char to the .Net type System.Char.

Program 5

Sometimes, you might need to call the Win32 API. And there are API functions, quite a good number of them to be precise, that take pointers as arguments and often return data via pointers. The following program is an example where such a call is made. Of course, there are other means to obtain the Windows folder from .NET, but the point of the program is to demonstrate the use of unsafe blocks in such a scenario where we need to call an API function that expects pointers.

using System;
using System.Text;
using System.Runtime.InteropServices;

class Class1
{
    [DllImport("kernel32", SetLastError=true)]
    static extern unsafe uint GetWindowsDirectory(byte* lpBuffer,uint uSize);

    static void Main(string[] args)
    {
        byte[] buff = new byte[512]; 
        unsafe 
        {
            fixed(byte *pbuff=buff)GetWindowsDirectory(pbuff,512);
        }
        ASCIIEncoding ae = new ASCIIEncoding();
        System.Console.WriteLine(ae.GetString(buff));
    }
}

Conclusion

Please be careful when writing unsafe code. Any small error, even a silly typing mistake, might crash your program randomly and unpredictably. The error might also be a rarely occurring one and thus harder to debug. But those of you who had used pointers in C/C++ and want to use them in C# may do so at their leisure. Thank You.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Nish Sivakumar

United States United States
Nish is a real nice guy who has been writing code since 1990 when he first got his hands on an 8088 with 640 KB RAM. Originally from sunny Trivandrum in India, he has been living in various places over the past few years and often thinks it’s time he settled down somewhere.
 
Nish has been a Microsoft Visual C++ MVP since October, 2002 - awfully nice of Microsoft, he thinks. He maintains an MVP tips and tricks web site - www.voidnish.com where you can find a consolidated list of his articles, writings and ideas on VC++, MFC, .NET and C++/CLI. Oh, and you might want to check out his blog on C++/CLI, MFC, .NET and a lot of other stuff - blog.voidnish.com.
 
Nish loves reading Science Fiction, P G Wodehouse and Agatha Christie, and also fancies himself to be a decent writer of sorts. He has authored a romantic comedy Summer Love and Some more Cricket as well as a programming book – Extending MFC applications with the .NET Framework.
 
Nish's latest book C++/CLI in Action published by Manning Publications is now available for purchase. You can read more about the book on his blog.
 
Despite his wife's attempts to get him into cooking, his best effort so far has been a badly done omelette. Some day, he hopes to be a good cook, and to cook a tasty dinner for his wife.

Comments and Discussions

 
QuestionHow to get the address of customized data type pointer? Pinmemberxiangzhai11-Apr-10 22:07 
Generalimplement with pointer Pinmembermostafa2afm6-Aug-09 3:15 
JokeNice:) PinmemberFade (Amit BS)3-Jul-09 13:55 
GeneralYou have an error in Program 1 Pinmemberdata_smith4-Apr-08 8:18 
GeneralRe: You have an error in Program 1 PinsitebuilderNishant Sivakumar22-Jul-09 19:22 
GeneralUpdated May 13th 2002 PinmemberNish [BusterBoy]12-May-02 23:41 
GeneralRe: Updated May 13th 2002 PinadminChris Maunder13-May-02 12:58 
GeneralRe: Updated May 13th 2002 PinmemberNish [BusterBoy]13-May-02 14:54 
General.Net Studio PinmemberHumair14-Oct-01 23:04 
GeneralRe: .Net Studio PinmemberNish [BusterBoy]14-Oct-01 23:14 
you can use the /unsafe command-line switch for csc
 
Nish
GeneralRe: .Net Studio PinmemberHumair14-Oct-01 23:22 
GeneralRe: .Net Studio PinmemberNish [BusterBoy]14-Oct-01 23:26 
GeneralRe: .Net Studio PinmemberJuergen15-Oct-01 3:17 
GeneralRe: .Net Studio PinmemberNish [BusterBoy]15-Oct-01 17:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140718.1 | Last Updated 13 May 2002
Article Copyright 2001 by Nish Sivakumar
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid