Pointers and Arrays in C#

In this ninth part of a ten-part series that covers C# in depth, you will learn about pointers, arrays, and more. This article is excerpted from chapter four of C# 3.0 in a Nutshell, Third Edition, A Desktop Quick Reference, written by Joseph Albahari and Ben Albahari (O'Reilly; ISBN: 0596527578). Copyright © 2007 O'Reilly Media, Inc. All rights reserved. Used with permission from the publisher. Available from booksellers or direct from O'Reilly Media.

Contributed by
Rating: 3 stars3 stars3 stars3 stars3 stars / 3
November 13, 2008
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

Attribute Targets

Implicitly, the target of an attribute is the code element it immediately precedes, which is typically a type or type member. You can also attach attributes, however, to an assembly. This requires that you explicitly specify the attribute’s target.

Here is an example of using theCLSCompliantattribute to specify CLS compliance for an entire assembly:

  [assembly:CLSCompliant(true)]

Specifying Multiple Attributes

Multiple attributes can be specified for a single code element. Each attribute can be listed either within the same pair of square brackets (separated by a comma) or in separate pairs of square brackets (or a combination of the two). The following three examples are semantically identical:

  [Serializable, Obsolete, CLSCompliant(false)]
  public class Bar {...}

  [Serializable] [Obsolete] [CLSCompliant(false)]
  public class Bar {...}

  [Serializable, Obsolete]
  [CLSCompliant(false)]
  public class Bar {...}

Unsafe Code and Pointers

C# supports direct memory manipulation via pointers within blocks of code marked unsafe and compiled with the /unsafe compiler option. Pointer types are primarily useful for interoperability with C APIs, but may also be used for accessing memory outside the managed heap or for performance-critical hotspots.

Pointer Basics

For every value type or pointer type V, there is a corresponding pointer type V*. A pointer instance holds the address of a value. This is considered to be of type V, but pointer types can be (unsafely) cast to any other pointer type. Table 4-2 shows the main pointer operators.

Table 4-2. Pointer operators

Operator

Meaning

&

The address-of operator returns a pointer to the address of a value.

*

The dereference operator returns the value at the address of a pointer.

->

The pointer-to-member operator is a syntactic shortcut, in whichx->yis equivalent to(*x).y.

Unsafe Code

By marking a type, type member, or statement block with the unsafe keyword, you’re permitted to use pointer types and perform C++ style pointer operations on memory within that scope. Here is an example of using pointers to quickly process a bitmap:

  unsafe void RedFilter(int[,] bitmap)
 
{
   
int length = bitmap.Length;
   
fixed (int* b = bitmap)
   
{
     
int* p = b;
      for(int i = 0; i < length; i++)
        *p++ &= 0xFF;
    }
  }

Unsafe code can run faster than a corresponding safe implementation. In this case, the code would have required a nested loop with array indexing and bounds checking. An unsafe C# method may also be faster than calling an external C function, since there is no overhead associated with leaving the managed execution environment.

The fixed Statement

The fixed statement is required to pin a managed object, such as the bitmap in the previous example. During the execution of a program, many objects are allocated and deallocated from the heap. In order to avoid unnecessary waste or fragmentation of memory, the garbage collector moves objects around. Pointing to an object is futile if its address could change while referencing it, so the fixed statement tells the garbage collector to “pin” the object and not move it around. This may have an impact on the efficiency of the runtime, so fixed blocks should be used only briefly, and heap allocation should be avoided within the fixed block.

Within afixedstatement, you can get a pointer to any value type, an array of value types, or a string. In the case of arrays and strings, the pointer will actually point to the first element, which is a value type.

Value types declared inline within reference types require the reference type to be pinned, as follows:

  class Test
 
{
   
int x;
   
static void Main()
   
{
     
Test test = new Test ();
     
unsafe
     
{
       
fixed(int* p = &test.x) // pins test
        {
         
*p = 9;
       
}
       
System.Console.WriteLine(test.x);
     
}
    }
  }

We describe thefixed statement further in the section “Mapping a Struct to Unmanaged Memory” in Chapter 22.

The Pointer-to-Member Operator

In addition to the & and * operators, C# also provides the C++ style -> operator, which can be used on structs:

  struct Test
  {
    int x;
    unsafe static void Main()
    {
     
Test test = new Test();
      Test* p = &test;
      p->x = 9;
      System.Console.WriteLine(test.x);
    }
  }

Arrays

The stackalloc keyword

Memory can be allocated in a block on the stack explicitly using the stackalloc keyword. Since it is allocated on the stack, its lifetime is limited to the execution of the method, just as with any other local variable. The block may use the [] operator to index into memory.

  int* a = stackalloc int [10];
  for (int i = 0; i < 10; ++i)
     onsole.WriteLine(a[i]); // print raw memory

Fixed-size buffers

Memory can be allocated in a block within a struct using the fixed keyword:

fixed keyword:Memory can be allocated in a block within a struct using the fixed keyword:

  unsafe struct UnsafeUnicodeString
 
{
    public short Length;
    public fixed byte Buffer[30];
  }

  unsafe class UnsafeClass
 
{
    private UnsafeUnicodeString uus;
    public UnsafeClass (string s)
    {
     
uus.Length = (short)s.Length;
      fixed (byte* p = uus.Buffer)
        for (int i = 0; i < s.Length; i++)
          p[i] = (byte)s[i];
    }
  }
  class Test
  {
   
static void Main() {new UnsafeClass("Christian Troy");}
  }

Thefixedkeyword is also used in this example to pin the object on the heap that contains the buffer (which will be the instance ofUnsafeClass).

void*

Rather than pointing to a specific value type, a pointer may make no assumptions about the type of the underlying data. This approach is useful for functions that deal with raw memory. An implicit conversion exists from any pointer type to void*. A void* cannot be dereferenced, and arithmetic operations cannot be performed on void pointers. For example:

  class Test
 
{
   
unsafe static void Main ()
   
{
     
short[ ] a = {1,1,2,3,5,8,13,21,34,55};
       
fixed (short* p = a)
       
{
         
//sizeof returns size of value-type in bytes
          Zap (p, a.Length * sizeof (short));
        }
      foreach (short x in a)
        System.Console.WriteLine (x); // prints all zeros
    }

    unsafe static void Zap (void* memory, int byteCount)
    {
      byte* b = (byte*)memory;
        for (int i = 0; i < byteCount; i++)
          *b++ = 0;
    }
  }

Pointers to Unmanaged Code

Pointers are also useful for accessing data outside the managed heap (such as when interacting with C DLLs or COM), or when dealing with data not in the main memory (such as graphics memory or a storage medium on an embedded device).

Preprocessor Directives

Preprocessor directives supply the compiler with additional information about regions of code. The most common preprocessor directives are the conditional directives, which provide a way to include or exclude regions of code from compilation. For example:

  #define DEBUG
 
class MyClass
  {
    int x;
    void Foo()
    {
     
# if DEBUG
     
Console.WriteLine("Testing: x = {0}", x);
     
# endif
    }
    ...
  } 

In this class, the statement inFoois compiled as conditionally dependent upon the presence of theDEBUGsymbol. If we remove theDEBUGsymbol, the statement is not compiled. Preprocessor symbols can be defined within a source file (as we have done), and they can be passed to the compiler with the/define:symbol command-line option.

The#errorand#warningsymbols prevent accidental misuse of conditional directives by making the compiler generate a warning or error given an undesirable set of compilation symbols. See Table 4-3 for a list of preprocessor directives and their actions.

Table 4-3. Preprocessor directives and their actions

Preprocessor directive

Action

#define symbol

Defines symbol.

#undef symbol

Undefines symbol.

#if symbol [operator symbol2] ...

symbolto test.

 

operators are ==, !=, &&, and ||followed by #else, #elif, and #endif.

#else

Executes code to subsequent #endif.

#elif symbol [operator symbol2]

Combines #elsebranch and #iftest.

#endif

Ends conditional directives.

#warning text

text of the warning to appear in compiler output.

#error text

text of the error to appear in compiler output.

#line [ number ["file"] | hidden]

numberspecifies the line in source code; fileis the file-name to appear in computer output; hiddenspecifies that the compiler should generate debugger information (this feature was added in Visual C# 2003).

#region name

Marks the beginning of an outline.

#end region 

Ends an outline region.

Please check back next week for the conclusion to this article.

blog comments powered by Disqus
C# ARTICLES

- Beginning C#
- ASP.NET RedirectPermanent Method using C# an...
- C Programming Language and UNIX Pioneer Pass...
- Using Facebook JavaScript SDK in ASP.NET wit...
- ASP.NET Export to Excel and Word using VB.NE...
- WAV and MP3 Streaming with ASP.Net and C#
- Game Programming using SDL: the File I/O API
- C# and Java Developer Jobs on the Rise
- The Future Evolution of C# and VB.NET
- C# If and Else-if Statements
- How To Use the C# String Replace Method
- 5 Ways to Parse XML in C#
- C# Meets Design Patterns
- Coding a CRC-Generating Algorithm in C
- Cyclic Redundancy Check

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 2 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials