Download as pdf or txt
Download as pdf or txt
You are on page 1of 9

6,648,446 members and growing! (16,829 online) Email Password Sign in Join Remember me? Lost your password?

Home Articles Quick Answers Message Boards Job Board Catalog Help! Lounge
Languages C++ / CLI C++/CLI Beginner License: The Microsoft Public License (Ms-PL) C++/CLI, VC8.0, Windows, .NET,
Visual Studio, Dev
Arrays in C++/CLI Posted: 12 Jul 2004
By Nishant Sivakumar
Updated: 11 Aug 2004
The article exposes the new array syntax available in C++/CLI for the declaration and use of CLI arrays Views: 187,310
Bookmarked: 36 times

Announcements Advanced Search


Search Articles / Quick Answers Go!
Add to IE Search
Windows 7 Comp
Print Share Discuss Report 38 votes for this article.
Win a laptop!
Popularity: 7.00 Rating: 4.43 out of 5 1 2 3 4 5
Monthly Competition

ARTICLES Introduction
Desktop Development
Web Development
Managed arrays are allocated on the CLI heap as opposed to native arrays which are allocated on the unmanaged
C++ heap, which essentially means that they are typical garbage collected .NET objects. And throughout this
Enterprise Systems
article the term array will refer to a managed array, and if at all a native array is mentioned, it will explicitly be
Multimedia
termed as a native array. Some of you might have seen my article on using managed arrays with the old MC++
Database
syntax and I am sure a few of you would have let out pained groans at the really peculiar syntax. Well, those
Platforms, Frameworks & people should be delighted to know that C++/CLI supports managed arrays using a far more intuitive syntax than
Libraries
which existed in the older syntax.
Languages
C / C++ Language Basic features
C++ / CLI
C# Here are some of the basic features of managed arrays in C++/CLI :-
MSIL
VBScript Syntax resembles that of C++ templates
VB.NET System::Array is automatic base type for all managed arrays
VB6 Interop Allocated on the CLR heap (means they get Garbage Collected)
Other .NET Languages Rank of the array need not be 1 (arrays with rank 1 are called single dimensional and those with rank >1
XML are called multi dimensional)
Java Easily supports jagged arrays (unlike in the older syntax, jagged arrays are easier to declare and use)
General Programming Implicit conversion to and explicit conversion from System::Array BCL class
Graphics / Design The rank and dimensions of an array object cannot be changed, once an array has been instantiated
Development Lifecycle
General Reading Pseudo-template of an array type
Third Party Products
Mentor Resources The declaration and usage of array types in C++/CLI seems to use an imaginary template type (there is no such
SERVICES template of course, it s all VC++ compiler magic) :-
Product Catalog
Collapse Copy Code
Code-signing Certificates
Job Board namespace stdcli::language
CodeProject VS2008 Addin
{
template<typename T, int rank = 1>
FEATURE ZONES ref class array : System::Array {};
}
Product Showcase
Code Signing Resources
WhitePapers / Webcasts array is declared inside the stdcli::language namespace so as to avoid conflicts with existing source code
ASP.NET Web Hosting
Single dimensional array usage
Arrays of a reference type

Collapse Copy Code

ref class R
{
public:
void Test1(int x)
{
array<String^>^ strarray = gcnew array<String^>(x);
for(int i=0; i<x; i++)
strarray[i] = String::Concat("Number ",i.ToString());
for(int i=0; i<x; i++)
Console::WriteLine(strarray[i]);
}
};
The syntax does look different from that used for native arrays; C++ coders who have used templates should find
this a lot more intuitive than people who come from a non-C++ background, but eventually they'll get
comfortable with it.

Arrays of a value type

Collapse Copy Code

ref class R
{
public:
void Test2(int x)
{
array<int>^ strarray = gcnew array<int>(x);
for(int i=0; i<x; i++)
strarray[i] = i * 10;
for(int i=0; i<x; i++)
Console::WriteLine(strarray[i]);
}
};

Unlike in the old syntax, array syntax for value types is exactly the same as that for managed types.

Multi dimensional array usage


Multi dimensional arrays are managed arrays that have a rank greater than 1. They are not arrays of arrays
(those are jagged arrays).

Collapse Copy Code

ref class R
{
public:
void Test3()
{
array<String^,2>^ names = gcnew array<String^,2>(4,2);
names[0,0] = "John";
names[1,0] = "Tim";
names[2,0] = "Nancy";
names[3,0] = "Anitha";
for(int i=0; i<4; i++)
if(i%2==0)
names[i,1] = "Brown";
else
names[i,1] = "Wilson";
for(int i=0; i<4; i++)
Console::WriteLine("{0} {1}",names[i,0],names[i,1]);
}
};

Jagged arrays
Jagged arrays are non-rectangular, and are actually arrays of arrays. The new template-style array syntax
simplifies the declaration and use of jagged arrays, which is a major improvement over the old syntax where
jagged arrays had to be artificially simulated by the developer.

Collapse Copy Code

ref class R
{
public:
void Test()
{
array<array<int>^>^ arr = gcnew array<array<int>^> (5);

for(int i=0, j=10; i<5; i++, j+=10)


{
arr[i] = gcnew array<int> (j);
}

Console::WriteLine("Rank = {0}; Length = {1}",


arr->Rank,arr->Length);
/*
Output :-
Rank = 1; Length = 5
*/

for(int i=0; i<5; i++)


Console::WriteLine("Rank = {0}; Length = {1}",
arr[i]->Rank,arr[i]->Length);
/*
Output :-
Rank = 1; Length = 10
Rank = 1; Length = 20
Rank = 1; Length = 30
Rank = 1; Length = 40
Rank = 1; Length = 50
*/
}
};

Using a typedef to simplify jagged array usage

Collapse Copy Code

typedef array<array<int>^> JaggedInt32Array;


typedef array<array<String^>^> JaggedStringArray;

ref class R
{
public:
void Test()
{
JaggedInt32Array^ intarr = gcnew JaggedInt32Array(10);
JaggedStringArray^ strarr = gcnew JaggedStringArray(15);
}
};

Directly initialize an array


The new syntax allows painless direct initialization of arrays.

Collapse Copy Code

ref class R1
{
public:
void Test()
{
//Single dimensional arrays
array<String^>^ arr1 = gcnew array<String^> {"Nish", "Colin"};
array<String^>^ arr2 = {"Nish", "Smitha"};

//Multi dimensional arrays


array<Object^,2> ^ multiobarr = {{"Nish", 100}, {"Jambo", 200}};
}
};

Arrays as function arguments


Collapse Copy Code

ref class R
{
public:
void ShowStringArray(array<String^>^ strarr)
{
for(int i=0; i<strarr->Length; i++)
Console::WriteLine(strarr[i]);
}
void Show2DInt32Array(array<int,2>^ arr)
{
for(int i=0; i<arr->GetLength(0); i++)
{
Console::WriteLine("{0} times 2 is {1}",arr[i,0],arr[i,1]);
}
}
};

void _tmain()
{
R^ r = gcnew R();
r->ShowStringArray(gcnew array<String^> {"hello", "world"});
array<int,2>^ arr = { {1,2}, {2,4}, {3,6}, {4,8} };
r->Show2DInt32Array(arr);
}

//Output :-

/*
hello
world
1 times 2 is 2
2 times 2 is 4
3 times 2 is 6
4 times 2 is 8
*/

Returning arrays from functions


Collapse Copy Code

ref class R
{
public:
array<String^>^ GetNames(int count)
{
array<String^>^ arr = gcnew array<String^>(count);
for(int i=0; i<count; i++)
{
arr[i] = String::Concat("Mr. ",(i+1).ToString());
}
return arr;
}

void ShowNames(array<String^>^ arr)


{
for(int i=0; i<arr->Length; i++)
Console::WriteLine(arr[i]);
}
};

void _tmain()
{
R^ r = gcnew R();
array<String^>^ arr = r->GetNames(7);
r->ShowNames(arr);
}

Array covariance
You can assign an array of type R to an array of type B, where B is a direct or indirect parent of R, and R is a ref
class.

Collapse Copy Code

ref class R1
{
//...
};

ref class R2 : R1
{
//...
};

void _tmain()
{
array<R1^>^ arr1 = gcnew array<R1^>(4);
array<R2^>^ arr2 = gcnew array<R2^>(4);

array<R1^>^ arr3 = arr2;


array<R1^>^ arr4 = gcnew array<R2^>(4);
}

Parameter arrays
C++/CLI has support for parameter arrays. There can only be one such parameter array per function and it also
needs to be the last parameter.

Collapse Copy Code

ref class R
{
public:
void Test(String^ s, [ParamArray] array<int>^ arr )
{
Console::Write(s);
for(int i=0; i<arr->Length; i++)
Console::Write(" {0}",arr[i]);
Console::WriteLine();
}
};

void _tmain()
{
R^ r = gcnew R();
r->Test("Nish");
r->Test("Nish",1);
r->Test("Nish",1,15);
r->Test("Nish",1,25,100);
}

Right now the only supported syntax uses the ParamArray attribute, but the eventual syntax will also support
the simpler style shown below :-

void Test(String^ s, ... array<int>^ arr )

Calling System::Array methods


Since every C++/CLI array is implicitly a System::Array object, we can use System::Array methods on CLI
arrays.

Collapse Copy Code


ref class R
{
public:
bool CheckName(array<String^>^ strarr, String^ str)
{
Array::Sort(strarr);
return Array::BinarySearch(strarr,str) < 0 ? false : true;
}
};

void _tmain()
{
R^ r = gcnew R();
array<String^>^ strarr = {"Nish","Smitha",
"Colin","Jambo","Kannan","David","Roger"};
Console::WriteLine("Nish is {0}",r->CheckName(strarr,"Nish") ?
gcnew String("Present") : gcnew String("Absent"));
Console::WriteLine("John is {0}",r->CheckName(strarr,"John") ?
gcnew String("Present") : gcnew String("Absent"));
}

I've used System::Sort and System::BinarySearch in the above example.

Here's another snippet that clearly demonstrates the implicit conversion to System::Array.

Collapse Copy Code

ref class R
{
public:
void ShowRank(Array^ a)
{
Console::WriteLine("Rank is {0}",a->Rank);
}
};

void _tmain()
{
R^ r = gcnew R();
r->ShowRank( gcnew array<int>(10) );
r->ShowRank( gcnew array<String^,2>(10,2) );
r->ShowRank( gcnew array<double,3>(10,3,2) );
r->ShowRank( gcnew array<int> {1,2,3} );
r->ShowRank( gcnew array<int,2> {{1,2}, {2,3}, {3,4}} );
}

Arrays of non-CLI objects


You can declare C++/CLI arrays where the array type is of a non-CLI object. The only inhibition is that the type
needs to be a pointer type. Consider the following native C++ class :-

Collapse Copy Code

#define Show(x) Console::WriteLine(x)

class N
{
public:
N()
{
Show("N::ctor");
}
~N()
{
Show("N::dtor");
}
};

Now here's how you can declare an array of this type :-

Collapse Copy Code

ref class R
{
public:
void Test()
{
array<N*>^ arr = gcnew array<N*>(3);
for(int i=0; i<arr->Length; i++)
arr[i] = new N();
}
};

Put this class to use with the following test code :-

Collapse Copy Code

void _tmain()
{
R^ r = gcnew R();
r->Test();
Show("Press any key...");
Console::ReadKey();
}

/* Output:

N::ctor
N::ctor
N::ctor
Press any key...

*/

There, that worked. Of course the destructors for the array elements did not get called, and in fact they won't get
called even if a Garbage Collection takes place and the array object is cleaned up. Since they are native objects
on the standard C++ heap, they need to have delete called on them individually.

Collapse Copy Code

ref class R
{
public:
void Test()
{
array<N*>^ arr = gcnew array<N*>(3);
for(int i=0; i<arr->Length; i++)
arr[i] = new N();
for(int i=0; i<arr->Length; i++)
delete arr[i];
}
//...

/* Output

N::ctor
N::ctor
N::ctor
N::dtor
N::dtor
N::dtor
Press any key...

*/

Ok, that's much better now. Or if you want to avoid calling delete on each object, you can alternatively do
something like this :-

Collapse Copy Code

ref class R
{
public:
void Test()
{
N narr[3];
array<N*>^ arr = gcnew array<N*>(3);
for(int i=0; i<arr->Length; i++)
arr[i] = &narr[i];
}
};

This yields similar results to the above snippet. Alternatively you could init the array members in its containing
class's constructor and delete them in the destructor, and then use the containing class as an automatic variable
(C++/CLI supports deterministic destruction).

Direct manipulation of CLI arrays using native pointers


Here's some code that shows how you can directly manipulate the contents of an array using native pointers. The
first sample is for a single dimensional array and the second is for a jagged array.

Natively accessing a single-dimensional array

Collapse Copy Code

void Test1()
{
array<int>^ arr = gcnew array<int>(3);
arr[0] = 100;
arr[1] = 200;
arr[2] = 300;

Console::WriteLine(arr[0]);
Console::WriteLine(arr[1]);
Console::WriteLine(arr[2]);

/*
Output :-
100
200
300
*/

// Modifying the array using a native int*


// that points to a pinned pointer in GC'd heap
pin_ptr<int> p1 = &arr[0];
int* p2 = p1;
while(*p2)
{
(*p2)++;
p2++;
}

Console::WriteLine(arr[0]);
Console::WriteLine(arr[1]);
Console::WriteLine(arr[2]);

/*
Output :-
101
201
301
*/
}

Natively accessing a jagged array

Collapse Copy Code

void Test2()
{
array<array<int>^>^ arr = gcnew array<array<int>^>(2);
arr[0] = gcnew array<int>(2);
arr[1] = gcnew array<int>(2);
arr[0][0] = 10;
arr[0][1] = 100;
arr[1][0] = 20;
arr[1][1] = 200;

Console::WriteLine(arr[0][0]);
Console::WriteLine(arr[0][1]);
Console::WriteLine(arr[1][0]);
Console::WriteLine(arr[1][1]);

/*
Output:
10
100
20
200
*/

// Copying the managed jagged array to


// a native array of pointers and accessing
// the members using the native array
pin_ptr<int> p1 = &arr[0][0];
pin_ptr<int> p2 = &arr[1][0];
int* p3[2];
p3[0] = p1;
p3[1] = p2;

Console::WriteLine(p3[0][0]);
Console::WriteLine(p3[0][1]);
Console::WriteLine(p3[1][0]);
Console::WriteLine(p3[1][1]);

/*
Output:
10
100
20
200
*/

// Assigning the native array of pointers


// to a native int** and modifying the array
int** p4 = p3;
for(int i=0; i<2; i++)
for(int j=0; j<2; j++)
p4[i][j] += 3;

Console::WriteLine(arr[0][0]);
Console::WriteLine(arr[0][1]);
Console::WriteLine(arr[1][0]);
Console::WriteLine(arr[1][1]);

/*
Output:
13
103
23
203
*/
}

Essentially we use a pinning pointer to the GC'd heap and then treat the casted native pointer as if it were
pointing to a native array. Gives us a really fast method to manipulate array content!

Conclusion
Array syntax in C++/CLI is definitely an aesthetic improvement over the older MC++ syntax, and it also brings in
a consistency of syntax that was severely lacking earlier. The template-style syntax should give a natural feel for
C++ coders though it might take a little while before you fully get used to it. As usual, I request you to freely
post any comments, suggestions, criticism, praise etc. that you might have for me.

History
Jul 13, 2004 - First published
Aug 12, 2004 - Updated article by adding sections on using non-CLI objects as array members, and directly
accessing an array using pointers

License
This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-
PL)

About the Author

Nishant Sivakumar Nish is a real nice guy living in Atlanta, who has been coding since 1990, when he was
13 years old. Originally from sunny Trivandrum in India, he recently moved to Atlanta
from Toronto and is a little sad that he won't be able to play in snow anymore.

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
Member 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.
Location: United States

Other popular C++ / CLI articles:


.NET Dynamic Software Load Balancing
A Draft Implementation of an Idea for .NET Dynamic Software Load Balancing
Quake II .NET
A port of the famous C-language based game engine to Visual C++ with a .NET
managed heads-up display.
A first look at C++/CLI
A brief look at the new C++/CLI syntax and how it improves over the old
MC++ syntax
OLE DB - Bound controls
Shows how you can use data bound controls with OLE DB
How to get the clients IP address using TcpClient in Managed
C++
How to get the clients IP address using TcpClient in Managed C++

Article Top Sign Up to vote for this article

You must Sign In to use this message board.


FAQ Search

Noise Tolerance Medium Layout Normal Per page 25 Update


Msgs 1 to 25 of 42 (Total in Forum: 42) (Refresh) First Prev Next

try sahrulijam 8:44 17 Aug '09

What do you mean when you say implicit conversion? knockNrod 4:23 11 Sep '08

Funny syntax for multi dimensions mef526 8:34 19 Jun '06

Re: Funny syntax for multi dimensions Jun Du 9:16 19 Jun '06

Re: Funny syntax for multi dimensions mef526 11:48 19 Jun '06

Re: Funny syntax for multi dimensions Nishant Sivakumar 2:49 20 Jun '06

Re: Funny syntax for multi dimensions mef526 4:43 20 Jun '06

Re: Funny syntax for multi dimensions Jun Du 4:55 20 Jun '06

How to Create Label Array on the Run-Time dataminers 4:58 14 Jun '06

Help me! sangtao 0:57 21 Jan '06

dynamically allocated arrays PRMARJORAM 5:19 1 Dec '05

Arrays/Pinned Pointers jcarlaft 5:39 17 Jan '05

Re: Arrays/Pinned Pointers bschwagg 11:40 5 Jun '06

Is MFC and ATL going out...... Aji Varghese 3:28 14 Oct '04

Re: Is MFC and ATL going out...... Nishant S 18:18 14 Oct '04

COMPLICATED.... Aji Varghese 3:24 14 Oct '04

Re: COMPLICATED.... Nishant S 18:16 14 Oct '04

'array': undeclared identifier Jefus 21:01 14 Sep '04

Re: 'array': undeclared identifier Nishant S 21:10 14 Sep '04

Re: 'array': undeclared identifier marco_it 0:00 1 Oct '04

Re: 'array': undeclared identifier parsley_w 0:03 9 Jun '06

What's the best way to .NET Majid Shahabfar 9:52 6 Aug '04

Re: What's the best way to .NET Nishant S 10:06 6 Aug '04

Which version do you use for your articles? Nemanja Trifunovic 14:36 18 Jul '04

Re: Which version do you use for your articles? Nishant S 16:58 19 Jul '04

Last Visit: 11:24 29 Nov '09 Last Update: 11:24 29 Nov '09 1 2 Next

General News Question Answer Joke Rant Admin

PermaLink | Privacy | Terms of Use Copyright 2004 by Nishant Sivakumar


Last Updated: 11 Aug 2004 Everything else Copyright CodeProject, 1999-2009
Editor: Nishant Sivakumar Web18 | Advertise on the Code Project

You might also like