Click here to Skip to main content
15,868,141 members
Articles / Programming Languages / C#
Article

Getting unsafe with pointers in C#

Rate me:
Please Sign up or sign in to vote.
4.82/5 (45 votes)
12 May 2002CPOL4 min read 193.2K   40   14
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

C#
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.

C#
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

C#
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.

C#
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.

C#
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)


Written By
United States United States
Nish Nishant is a technology enthusiast from Columbus, Ohio. He has over 20 years of software industry experience in various roles including Chief Technology Officer, Senior Solution Architect, Lead Software Architect, Principal Software Engineer, and Engineering/Architecture Team Leader. Nish is a 14-time recipient of the Microsoft Visual C++ MVP Award.

Nish authored C++/CLI in Action for Manning Publications in 2005, and co-authored Extending MFC Applications with the .NET Framework for Addison Wesley in 2003. In addition, he has over 140 published technology articles on CodeProject.com and another 250+ blog articles on his WordPress blog. Nish is experienced in technology leadership, solution architecture, software architecture, cloud development (AWS and Azure), REST services, software engineering best practices, CI/CD, mentoring, and directing all stages of software development.

Nish's Technology Blog : voidnish.wordpress.com

Comments and Discussions

 
QuestionHow to get the address of customized data type pointer? Pin
Leslie Zhai11-Apr-10 22:07
Leslie Zhai11-Apr-10 22:07 
How to get the address of customized data type pointer?
Generalimplement with pointer Pin
mostafa2afm6-Aug-09 3:15
mostafa2afm6-Aug-09 3:15 
JokeNice:) Pin
Fade (Amit BS)3-Jul-09 13:55
Fade (Amit BS)3-Jul-09 13:55 
GeneralYou have an error in Program 1 Pin
data_smith4-Apr-08 8:18
data_smith4-Apr-08 8:18 
GeneralRe: You have an error in Program 1 Pin
Nish Nishant22-Jul-09 19:22
sitebuilderNish Nishant22-Jul-09 19:22 
GeneralUpdated May 13th 2002 Pin
Nish Nishant12-May-02 23:41
sitebuilderNish Nishant12-May-02 23:41 
GeneralRe: Updated May 13th 2002 Pin
Chris Maunder13-May-02 12:58
cofounderChris Maunder13-May-02 12:58 
GeneralRe: Updated May 13th 2002 Pin
Nish Nishant13-May-02 14:54
sitebuilderNish Nishant13-May-02 14:54 
General.Net Studio Pin
Humair14-Oct-01 23:04
Humair14-Oct-01 23:04 
GeneralRe: .Net Studio Pin
Nish Nishant14-Oct-01 23:14
sitebuilderNish Nishant14-Oct-01 23:14 
GeneralRe: .Net Studio Pin
Humair14-Oct-01 23:22
Humair14-Oct-01 23:22 
GeneralRe: .Net Studio Pin
Nish Nishant14-Oct-01 23:26
sitebuilderNish Nishant14-Oct-01 23:26 
GeneralRe: .Net Studio Pin
Juergen15-Oct-01 3:17
Juergen15-Oct-01 3:17 
GeneralRe: .Net Studio Pin
Nish Nishant15-Oct-01 17:08
sitebuilderNish Nishant15-Oct-01 17:08 

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

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