惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

大猫的无限游戏
大猫的无限游戏
Webroot Blog
Webroot Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
T
Threat Research - Cisco Blogs
V2EX - 技术
V2EX - 技术
L
LINUX DO - 热门话题
Google DeepMind News
Google DeepMind News
Recorded Future
Recorded Future
S
Schneier on Security
I
InfoQ
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
The GitHub Blog
The GitHub Blog
S
Security @ Cisco Blogs
O
OpenAI News
W
WeLiveSecurity
Vercel News
Vercel News
阮一峰的网络日志
阮一峰的网络日志
Simon Willison's Weblog
Simon Willison's Weblog
人人都是产品经理
人人都是产品经理
Cloudbric
Cloudbric
The Last Watchdog
The Last Watchdog
The Hacker News
The Hacker News
Google Online Security Blog
Google Online Security Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
GbyAI
GbyAI
NISL@THU
NISL@THU
T
Tailwind CSS Blog
V
Visual Studio Blog
PCI Perspectives
PCI Perspectives
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Jina AI
Jina AI
D
DataBreaches.Net
B
Blog RSS Feed
N
News and Events Feed by Topic
N
News and Events Feed by Topic
H
Heimdal Security Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
腾讯CDC
Latest news
Latest news
V
Vulnerabilities – Threatpost
Hacker News: Ask HN
Hacker News: Ask HN
WordPress大学
WordPress大学
V
V2EX
aimingoo的专栏
aimingoo的专栏
博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
D
Darknet – Hacking Tools, Hacker News & Cyber Security
The Register - Security
The Register - Security
Help Net Security
Help Net Security

博客园 - Kiven

50个常用SQL语句 [摘]在ASP.NET MVC中使用DropDownList SQL Server里面可能经常会用到的日期格式转换方法 [摘]Asp.net MVC 3中Session与ViewBag传值到Js中 « 给初学C++者的50条忠告 asp.net页面刷新后样式就发生了改变 System::String^ / std::string / char * 间的转换(部分) [摘]C/C++实现js的split函数功能 char*与System::String^的相互转换 Windows Phone 7 常用控件之Map Windows Phone 7 常用绘图控件 [网摘]深入浅出解读微软云计算:让云触手可及 【网摘日记】云计算五层架构 [MVP在线交流]微软原型设计工具SketchFlow企业级应用(二) Web项目VS2005转VS2008平台注意事宜。 [俱乐部在线交流]微软原型设计工具SketchFlow企业级应用(一) [武汉站]Windows 7社区发布活动圆满成功! [武汉站]Windows 7 社区发布活动 宏博软件“移动公教站”之“微软新技术预览”系列资料
C++/CLI学习入门数组
Kiven · 2012-11-13 · via 博客园 - Kiven

要学习数组,必须先了解跟踪句柄。

一、跟踪句柄

跟踪句柄类似于本地C++指针,但也有很大区别。跟踪句柄确实存储着某个对象的地址,但当CLR压缩堆过程中改变了该对象的地址,则垃圾回收器自动更新句柄所包含的地址。我们不能像本地指针那样用跟踪句柄来执行地址的算术运算,也不允许对跟踪句柄进行强制类型转换。

在CLR堆中创建的对象必须被跟踪句柄引用。所有属于引用类型的对象都存储在堆中,因此为引用这些对象所创建的变量都必须是跟踪句柄。例如,String类型是引用类型,因此引用String对象的变量必须是跟踪句柄。值类型默认分配在堆栈上,但也可以用gcnew操作符将其存储在堆上。此外必须注意,在堆上分配的变量——其中包括所有CLR引用类型——都不能在全局作用域内声明。

通过在类型名称后加”^”符号,用于声明一个该类型的句柄。下面的例子声明了一个String类型的跟踪句柄proverb。

String^ proverb;

在声明时句柄时,系统自动为其分配一个空值,该句柄不引用任何对象。也可显示地将某个句柄置为空值:

proverb = nullptr;

注意不能用0来表示空值。如果用0来初始化某个句柄,则0将自动转换为被引用类型的对象,而句柄则指向该对象。可以在声明句柄时显示的将其初始化:

String^ saying = L"I used to think I was indecisive but now I??¡ê¡èm not so sure."; 

该语句首先在堆上创建一个包含等号右边字符串的String对象,然后将该对象的地址存入saying中。注意字符串字面值的类型为const wchar_t*而非String。类String提供了这样的方法使得const wchar_t*类型的字符串可以用来创建String类型的对象。

下面这条语句创建了值类型的句柄:

int^ value = 99; 

      该语句在堆上创建一个Int32型的值类型变量,然后将该变量的地址存入句柄value中。由于value是一种指针,因此不能直接参与算术运算,可使用*运算符对地址求值(类似于本地C++指针那样):

int result = 2*(*value)+15;

      由于*value表示value所指向地址存储的数值,因此result的值为2*99+15=213。注意,当value作为运算式左值时,不需要*即可对value指向的变量赋值。

int^ result = 0;
result = 2*(*value)+15;

      首先创建了一个指向数值0的句柄result。(该语句会触发一条编译器警告,提示不能利用0来将句柄初始化为空值。)

      第2条语句=号右边为数值,而左边为句柄,编译器将自动将右值赋予句柄所指向的对象,即将其转换为如下语句

*result = 2*(*value)+15;

       注意,要采用上面的语句,result句柄必须实际定义过。如果仅仅声明了result,则会产生运行时错误

int^ result;
*result = 2*(*value)+15;

       这是因为第二句要对地址result求值,即意味着result指向的对象已经存在,但实际并非如此,因为声明该对象时系统默认赋予其空值(nullptr)。在这种情况下,采用下面的方法就可以正常工作了

int^ result;
result = 2*(*value)+15; 

二、数组

(一)数组句柄

       CLR数组是分配在可回收垃圾堆上的。必须用array<typename>指出要创建的数组,同其它CLR堆上的对象一样,需要用句柄来访问它,例子如下:

array<int>^ data;

      数组句柄data可用于存储对元素类型为int的一维数组的引用。下面的例子声明了一个句柄,并新建一个CLR数组来对此句柄初始化。

array<int>^ data = gcnew array<int>(100); 

       和本地C++数组一样,CLR数组中元素的索引值也是从0开始的,可以通过[ ]访问数组元素。数组元素都是CLR对象,在上面的例子中数组元素为Int32型对象,它们在算术表达式中就像普通的整数类型一样。

       Length属性是数组的一个重要属性,记录着数组元素的数量。保存了64位的数组长度。

for(int i=0; i<data->Length; i++)
	data[i] = 2*(i+1);

可以用for each循环遍历数组元素。

array<int>^ value = {3, 5, 6, 8, 6};
for each(int item in value)
{
	item = 2*item + 1;
	Console::WriteLine("{0, 5}", item);
}

该循环输出5字符宽度的字段,以右对齐的方式输出当前元素的计算结果,输出如下:

    7   11   13   17   13 

       数组句柄可以被重新赋值,只要保持数组元素类型和维数(等级)不变即可,在前面例子中的数组句柄data指向一个int类型的一维数组,可以重新给它赋值,使其指向另外的int类型1维数组:

data = gcnew array<int>(45);

       数组可以在创建时通过元素列表初始化,下例在CLR堆上创建了一个double类型的数组,并将引用赋值给了数组句柄:

array<double>^ sample = {3.4, 2.3, 6.8, 1.2, 5.5, 4.9, 7.4, 1.6};

       如果在声明数组句柄时不进行初始化,那么在给句柄赋值时不能采用上面的方法直接用元素列表用作右值,而必须采用显示创建的方式。即不能

array<double>^ sample;
sample = {3.4, 2.3, 6.8, 1.2, 5.5, 4.9, 7.4, 1.6}

       而必须采用如下方式

array<double>^ sample;
sample = gcnew array<double>{3.4, 2.3, 6.8, 1.2, 5.5, 4.9, 7.4, 1.6}

       对于字符串数组,注意每一个元素也是引用类型,这是因为每一个元素String也是在CLR堆上创建的,因此也要用String^来访问它。

array<String^>^ names = {"Jack", "John", "Joe", "Jessica", "Jim", "Joanna"};

       可以用Array类静态函数Clear()对数组中的连续数组元素清零。

Array::Clear(samples, 0, samples->Length);

       Clear()函数的第一个参数是被清零的数组,第二个参数是要清除地第一个元素的索引,第三个参数为要清除地元素数量。因此上述语句将samples数组的所有元素都置为0。如果Clear()清除的是某个跟踪句柄,则句柄所对应的元素都被应用Clear()函数。如果元素为bool型,则被置为false。

(二)数组排序

Array类还定义了一个Sort()静态函数,可用于对数组进行排序。如果以数组句柄作为参数,则对整个数组排序。如果要对数组部分排序,则还需要增加元素起始索引及数量,如下例

array<int>^ samples = {27, 3, 54, 11, 18, 2, 16};
Array::Sort(samples, 2, 3);

排序后数组元素变为{27, 3, 11, 18, 54, 2, 16}

Sort函数还有很多其它版本,下面的例子展示了如何排序两个相关的数组,即第一个数组中的元素是第二个数组对应元素的键。对第一个数组排序后,可对第二个数组进行相应的调整,使得键与值相互对应。

Sort()函数对2个数组排序时,用第一个数组参数来确定两个数组的顺序,以此保持2个数组元素对应关系不变。

- - - - - - - - - - - - - - - - <<== 华丽的分割线 ::开始==>> [Ex4_13.cpp] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// Ex4_13.cpp : main project file.
#include "stdafx.h"
using namespace System;

int main(array<System::String ^> ^args)
{
	array<String^>^ names = { "Jill", "Ted", "Mary", "Eve", "Bill", "Al" };
	array<int>^ weights = {103, 168, 128, 115, 180, 176};

	Array::Sort(names, weights);
	for each( String^ name in names )
		Console::Write(L"{0, 10}", name);
	Console::WriteLine();
	
	for each(int weight in weights)
		Console::Write(L"{0, 10}", weight);
	Console::WriteLine();
	
	return 0;
}

- - - - - - - - - - - - - - - - <<== 华丽的分割线 ::结束==>> [Ex4_13.cpp] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

输出为: 
Al Bill Eve Jill Mary Ted 
176 180 115 103 128 168 

(三)数组搜索

Array类还提供了函数BinarySearch()以使用对分法搜索算法,对一维数组或给定范围内搜索特定元素的索引位置。使用该函数要求数组必须是顺序排列的,因此在搜索之前必须对数组进行排序。

array<int>^ value = { 23, 45, 68, 94, 123, 150, 203, 299 };
int toBeFound = 127;
int position = Array::BinarySearch(value, toBeFound);
if(position<0)
        Console::WriteLine(L"{0} was not found.", toBeFound);
else
        Console::WriteLine(L"{0} was found at index position {1}", toBeFound, position);

Array::BinarySearch()的第一个参数是被搜索数组的句柄,第二个参数是要查找的内容,返回值为int类型的数值。如果返回值小于0则说明未找到。如果要指定搜索范围,则需要传递4个参数,其中第2参数为搜索起始索引,第3参数为搜索的元素数量,第4个是要搜索的内容。下面的代码从第4个元素开始,一直搜索到结束位置。

array<int>^ value = { 23, 45, 68, 94, 123, 150, 203, 299 };
int toBeFound = 127;
int position = Array::BinarySearch(value, 3, 6, toBeFound);    

- - - - - - - - - - - - - - - - <<== 华丽的分割线 ::开始==>> [Ex4_14.cpp] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// Ex4_14.cpp : main project file.
#include "stdafx.h"
using namespace System;

int main(array<System::String ^> ^args)
{
	array<String^>^ names = { "Jill", "Ted", "Mary", "Eve", "Bill", "Al", "Ned", "Zoe", "Dan", "Jean" };
	array<int>^ weights = {103, 168, 128, 115, 180, 176, 209, 98, 190, 130};
	array<String^>^ toBeFound = {"Bill", "Eve", "Al", "Fred"};
	
	int result = 0;
	Array::Sort(names, weights);

	for each( String^ name in toBeFound )
	{
		result = Array::BinarySearch(names, name);
		if(result<0)
			Console::WriteLine(L"{0} was not found.", name);
		else
			Console::WriteLine(L"{0} weights {1} lbs.", name, weights[result]);
	}

	return 0;
}

- - - - - - - - - - - - - - - - <<== 华丽的分割线 ::开始==>> [Ex4_14.cpp] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        当搜索不到目标时,Array::BinarySearch()函数输出的并非任意负数,而是第一个大于该目标的元素索引值的按位补码。利用该方法,可以不打乱顺序在数组中插入新值。如,我们希望插入”Fred”到names数组中

array<String^>^ names = { "Jill", "Ted", "Mary", "Eve", "Bill", "Al", "Ned", "Zoe", "Dan", "Jean" }
Array::Sort(names);
String^ name = L"Fred";
int position = Array::BinarySearch(names, name);
if(position<0)
position = ~position;

此时,position保存的是大于Fred的第一个元素的位置,该数值可用于插入新值。

array<String^>^ newNames = gcnew array<String^>(names->Length+1);
for(int i=0;i<position;i++)
	newNames[i] = names[i];
newNames[position] = name;

if(position<name->Length)
	for(int i=position; i<names->Length; i++)
		newNames[i+1] = names[i];
names = nullptr;

注意:最后一句用于删除names数组。

(四)多维数组

C++/CLI中可以创建多维数组,最大维数32维。与ISO/ANSI C++不同的是,C++/CLI中的多维数组并非数组的数组,而是真正的多维数组,创建整数多维数组方法如下:

array<int 2>^ value = gcnew array<int, 2>(4, 5);

上面的代码创建了一个二维数组,四行五列,共20个元素。访问的方法是利用多个用逗号分隔的索引值来访问每一个元素,而不能用一个索引值访问一行

int nrows = 4;
int ncols = 5;
array<int, 2>^ value = gcnew array<int, 2>(nrows, ncols);
for(int i=0; i<nrows; i++)
    for(int j=0; j<ncols; j++)
        value[i, j] = (i+1)*(j+1);

上面的代码利用循环给二维数组value赋值。这里访问二维数组元素的符号与本地C++不同:后者实际上是数组的数组,而C++/CLI是真正的二维数组,不能用一个索引值来访问二维数组,那样是没有意义的。数组的维数被称为等级,上面value数组的等级为2。而本地C++数组的等级始终为1。当然,在C++/CLI中也可以定义数组的数组,方法见下例

- - - - - - - - - - - - - - - - <<== 华丽的分割线 ::开始==>> [Ex4_15.cpp] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// Ex4_15.cpp : main project file.
#include "stdafx.h"
using namespace System;

int main(array<System::String ^> ^args)
{
	const int SIZE = 12;
	array<int, 2>^ products = gcnew array<int, 2>(SIZE, SIZE);
	
	for(int i=0; i<SIZE; i++)
		for(int j=0; j<SIZE; j++)
			products[i, j] = (i+1)*(j+1);
	Console::WriteLine(L"Here is the {0} times table:", SIZE);

	// Write horizontal divider line
	for(int i=0; i<=SIZE; i++)
		Console::Write(L"_____");
	Console::WriteLine();

	// Write top line of table
	Console::Write(L"    |");
	for(int i=1; i<=SIZE; i++)
		Console::Write("{0, 3} |", i);
	Console::WriteLine();

	// Write horizontal divider line with verticals
	for(int i=0; i<=SIZE; i++)
		Console::Write("____|", i);
	Console::WriteLine();

	// Write remaining lines
	for(int i=0; i<SIZE; i++)
	{
		Console::Write(L"{0, 3} |", i+1);
		for(int j=0; j<SIZE; j++)
			Console::Write("{0, 3} |", products[i, j]);
		Console::WriteLine();
	}

	// Write horizontal divider line
	for(int i=0; i<=SIZE; i++)
		Console::Write("_____", i);
	Console::WriteLine();
	return 0;
}

- - - - - - - - - - - - - - - - <<== 华丽的分割线 ::结束==>> [Ex4_15.cpp] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

上面的例子创建了一个12x12的乘法表,输出如下:

Here is the 12 times table:
_________________________________________________________________
    |  1 |  2 |  3 |  4 |  5 |  6 |  7 |  8 |  9 | 10 | 11 | 12 |
____|____|____|____|____|____|____|____|____|____|____|____|____|
  1 |  1 |  2 |  3 |  4 |  5 |  6 |  7 |  8 |  9 | 10 | 11 | 12 |
  2 |  2 |  4 |  6 |  8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 |
  3 |  3 |  6 |  9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 |
  4 |  4 |  8 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | 40 | 44 | 48 |
  5 |  5 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 |
  6 |  6 | 12 | 18 | 24 | 30 | 36 | 42 | 48 | 54 | 60 | 66 | 72 |
  7 |  7 | 14 | 21 | 28 | 35 | 42 | 49 | 56 | 63 | 70 | 77 | 84 |
  8 |  8 | 16 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 88 | 96 |
  9 |  9 | 18 | 27 | 36 | 45 | 54 | 63 | 72 | 81 | 90 | 99 |108 |
 10 | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 | 90 |100 |110 |120 |
 11 | 11 | 22 | 33 | 44 | 55 | 66 | 77 | 88 | 99 |110 |121 |132 |
 12 | 12 | 24 | 36 | 48 | 60 | 72 | 84 | 96 |108 |120 |132 |144 |
_________________________________________________________________

其中创建二维数组的代码如下:

const int SIZE = 12;
array<int, 2>^ products = gcnew array<int, 2>(SIZE, SIZE);

第一行定义了一个整型常量SIZE,用于指定每一维数组的元素数量,第二行代码定义了一个等级2的数组,为12x12大小,该数组用于存储12x12的乘法表乘积。然后在嵌套循环中给数组赋值,大部分代码用于格式化输出以使其更加美观,这里就不再说明。

(五)数组的数组

如果数组的元素是引用数组的跟踪句柄,那么就可以创建数组的数组。同时,每一维数组的长度可以不同,即所谓的“锯齿形数组”。例如,用ABCDE来表示学生的成绩等级,根据等级分组存储班内学生的姓名,则可以创建一个包含5个元素的数组,每个元素为一个姓名数组(即字符串数组)

array<array<String ^>^>^ grades = gcnew array<array<String^>^>(5)

利用上面创建的数组,然后可以创建5个姓名数组了

grades[0] = gcnew array<String^>{"Louise", "Jack"};
grades[1] = gcnew array<String^>{"Bill", "Mary", "Ben", "Joan"};
grades[2] = gcnew array<String^>{"Jill", "Will", "Phil"};
grades[3] = gcnew array<String^>{"Ned", "Fred", "Ted", "Jed", "Ed"};
grades[4] = gcnew array<String^>{"Dan", "Ann"};

grades[n]访问grades数组的第n个元素,而各元素为指向String^类型数组的句柄,因此上面的语句用于创建了String对象句柄的数组,并将创建数组的地址赋值给了grades数组元素。同时,这些字符串数组的长度是不同的。

上面的语句也可以用一个初始化语句来实现

array<array<String^>^>^ grades = gcnew array<array<String^>^>
{
    gcnew array<String^>{"Louise", "Jack"},
    gcnew array<String^>{"Bill", "Maray", "Ben", "Joan"},
    gcnew array<String^>{"Jill", "Will", "Phil"},
    gcnew array<String^>{"Ned", "Fred", "Ted", "Jed", "Ed"},
    gcnew array<String^>{"Dan", "Ann"},
};

注意:元素的初值必须写在花括号里。

- - - - - - - - - - - - - - - - <<== 华丽的分割线 ::开始==>> [Ex4_16.cpp] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// Ex4_16.cpp : main project file.
#include "stdafx.h"
using namespace System;

int main(array<System::String ^> ^args)
{
	array<array<String^>^>^ grades = gcnew array<array<String^>^>
		{
			gcnew array<String^>{"Louise", "Jack"},
			gcnew array<String^>{"Bill", "Maray", "Ben", "Joan"},
			gcnew array<String^>{"Jill", "Will", "Phil"},
			gcnew array<String^>{"Ned", "Fred", "Ted", "Jed", "Ed"},
			gcnew array<String^>{"Dan", "Ann"}
		};
	
	wchar_t gradeLetter = 'A';
	for each(array<String^>^ grade in grades)
	{
		Console::WriteLine(L"Students with Grade {0}:", gradeLetter++);
		for each(String^ student in grade)
			Console::Write("{0, 12}", student);
		Console::WriteLine();
	}
	return 0;
}

- - - - - - - - - - - - - - - - <<== 华丽的分割线 ::结束==>> [Ex4_16.cpp] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

输出为

Students with Grade A:
      Louise        Jack
Students with Grade B:
        Bill       Maray         Ben        Joan
Students with Grade C:
        Jill        Will        Phil
Students with Grade D:
         Ned        Fred         Ted         Jed          Ed
Students with Grade E:
         Dan         Ann
 
摘:http://www.cppblog.com/golq/archive/2009/06/29/88733.html
更多:http://www.cppblog.com/golq/category/11113.html