Visual C++ 2008入门经典 第四章数组 字符串(二)
////////////////////////////////////////////////////////////////////////////////////// //4.4 使用引用 //引用在许多方面都类似于指针,所以后们放在这里进行讨论,但实现上二者根本不是一回事 //4.4.1 引用的概念 //引用是另一个变量的别名,这样的别名可以代替原来的变量名,因为是别名而非指针,所以声明引用时必须指出所对应的变量,与指针不同的是 //我们不能修改引用,使其表示另一个变量 //4.4.2 声明并初始化引用 //long number = 0; //long& rnumber = number; //rnumber +=10; //long* pnumber = &number; //*pnumber +=10; //使用指针与使用引用之间的重大区别, //指针需要被解除引用才能参与到表达式中.. //解除引用是指long* pnumber = &number;吗? //用来访问变量的是指针包含的地址,而在使用引用的情况下,不必解除引用,在某些方面,引用就像是已经被解除引用的指针,但不能改变引用另一个变量,引用完全等价于被引用的变量 //看起来引用可能只是给变量找的替代符号,引处引用表现出的行为的确如此,但是,当我们讨论C++函数时,将看到真相不完全是这样,引用可以提供某此非常强大的额外功能 ////////////////////////////////////////////////////////////////////////////////////// //4.5 字符串的本地C++库函数 //本地C++的<string>标准头文件定义了代表字符串的string和wstring类, //string类代表char类型的字符串, wstring类代表示wchar_t类型的字符串 //4.5.1 查找以空字符结尾的字符串的长度 //strlne与wcslen返回字符长度值不包括结尾的空字符,一定要记住这一点,尤其是当我们用字符串的长度来创建另一个相同长度的字符串时更要注意 //strnlen和wcsnlen()函数,这两个函数都要求使用第二个参数来指定第一个参数指定的字符串要存储的缓冲区的长度 //4.5.2 连接以空字符结尾的字符串 //strcat()函数用来拼接两个以空字符结尾的字符串,第二个参数指定的字符串被添加到第一个参数指定的字符串后面, //char str1[30] = "Many hands"; //char* str2("make light work."); //strcat(str1,str2); //cout<<str1<<endl; //wcscat()函数拼接宽字符,不过其他方面的与strcat()函数的运行方式完全相同 //strncat()函数可以将一个以空字符结尾的字符串的一部分附加到另一个字符串的后面,前两个参数是目标字符串和源字符串,第三个参数是要从源字符串附加的字符个数 /*char str1[30] = "Many hands "; char* str2("make light work."); cout<<strncat(str1,str2,4)<<endl;*/ //wcsncat()提供的功能与strncat()相同,只是它用于宽字符串 //录处理不受信任的数据时它们也是不安全的, //<cstring>中的strcat_s() wcscat_s() strncat_s() 和wcsncat_s()函数提供了安全的替换方式 /*const size_t count = 30; char str1[count] = "Many hands "; char* str2("make light work."); errno_t error = strcat_s(str1,count,str2); if(error == 0){ cout<<"Strings joined successfully."<<endl; }else if(error == EINVAL){ cout<<"Error source or destination string is null"; }else if(error == ERANGE){ cout<<"error! destination string too small."; }*/ //4.5.3 复制以空字符结尾的字符串 //标准库函数strcpy()将字符串从源位置复制到目标位置,第一个参数是指向目标位置的指针,第二个参数是指向源字符串的指针,两个参数类型均为char* /*const size_t LENGTH = 33; const char source[LENGTH] = "The more the merrier!"; char destination[LENGTH]; cout<<" the destionation string is:"<<strcpy(destination,source)<<endl; cout<<" destination:"<<destination<<endl;*/ //strcpy_s()函数是strcpy()的一个更安全的版本,它要求在目标参数与源参数之间用一个额外的参数指定目标字符串缓冲区的大小 /*const size_t LENGTH = 33; const char source[LENGTH] = "The more the merrier!"; char destination[LENGTH]; errno_t error = strcpy_s(destination, LENGTH, source); if(error == EINVAL) cout<<"is null"<<endl; else if(error == ERANGE) cout<<"error is too small"<<endl; else cout<<"strcpy_s string is:"<<destination<<endl;*/ //这些复制函数也有类似的宽字符版本,分别是wcscpy() 和wcscpy_s(); //4.5.4 比较以空字符结尾的字符串 //strcmp()函数可以比较我们通过参数(char*类型的指针)指定的两个以空字符结尾的字符串 //该函数返回一个int类型的值,根据第一个参数指向的字符串大小,等于还是大于第二个参数指向的字符串,返回值将会-1 0, 1来决定 /*char* str1("Aill"); char* str2("Jacko"); char* comp[] ={"小于","等于","大于"}; cout<<str1<<"is "<<comp[strcmp(str1,str2)+1]<<str2<<".";*/ //wstrcmp()函数对应于strcmp()的宽字符串版本 //4.5.5 搜索以空字符结尾的字符串 //strspn()函数可能搜索字符串不包含在给定集合中的第一个字符,并返回该字符的索引,第一个参数是指要搜索的字符串的指针, //第二个参数是指向包含该字符集合的字符中的指针 /*char* str="Iagree with everything."; char* vowels="aeiouAEIOU"; size_t index = strspn(str,vowels); cout<<"index:"<<index<<endl; cout<<"在str中与vowels最先相同的首字符为:'"<<str[index]<<"' 索引值为:"<<index<<endl;*/ //在str中搜索第一个字符不在vowels中的字符串 //wcspn()函数是strspn()的宽字符串版本 //strstr()函数返回一个指针,指向第一个参数中第二个参数指定的子串的位置 /*char* str = "I agree with everything."; char* substring = "ever"; char* psubstr = strstr(str,substring); if(!psubstr){ cout<<"没有找到"<<substring<<"出现的位置"<<endl; }else{ cout<<substring<<"出现的首字符索引为:"<<psubstr-str<<endl; }*/ /*char* str = "Smith, where Jones had had \"had had\" had had \"had\"." "\n\"had had\" had had the examiners' approval."; char* word = "had"; cout<<"str:"<<str<<endl; int count = 0; char* pstr = str; char* found = 0; while(true) { found = strstr(pstr,word); if(!found) //将已经没有的时候退出循环 break; ++count; //查到一次加一 //重新定义pstr //查到的位置 + 3 pstr = found+strlen(word); //pstr = found; 为什么要加strlne(word)呢,弄不懂呢 //明白,因为找到的位置是包括word的字符在内的,所以要减去word的长度,在word的后面进行查找才对, 哈哈哈 //真笨这都不明白 //cout<<"found:"<<found<<endl; cout<<"pstr:"<<pstr<<endl<<endl; } cout<<word<<" was found "<<count<<" times in the string."<<endl; */ //system("pause"); //return 0; //} #include "stdafx.h" #include <iostream> #include <iomanip> using namespace std; using namespace System; int main(array<System::String ^> ^args) { //Console::WriteLine(L"Hello World"); //4.6 C++/CLI编程 //4.6.1 跟踪句柄 //声明跟踪句柄 //我们通过将符号^(通常被称为什么”帽子“)放在类型名称的后面来指定该类型的句柄, //String^ proverb; //proverb = nullptr; //注意,我们这里不能像使用本地指针时那样,使用0来表示空值,如果用0来初始化句柄,则数值0将被转换为该句柄引用的对像的类型,而这个新对像的地址将被存入该句柄中 //string^ saying=L"I used to think I was indecisive but now I'm not so sure"; //int^ value = 99; //记住我们创建的是一种指针,因此在没有解除引用的情况下value不能参与算术运算,为了解除对跟踪句柄的引用,我们以与使用本地指针时相同的方式使用*运算符, //int result = 2*(*value)+15; //cout<<"result:"<<result<<endl; //4.6.2 CLR数组 /*array<int>^ values = {3,5,6,8,6}; for each(int item in values) { item = 2*item+1; Console::Write("{0,5}",item); }*/ //data = gcnew array<int>(45); //array<double>^ samples ={ 3.4, 2.3, 6.8, 1.2, 5.5, 4.9, 7.4, 1.6}; //array<String^>^ names={"Jack","Jane","Joe","Jessica","Jim","Joanna"}; //array<String^>^ names; //names = gcnew array<String^>{"Jack","Jane","Joe","Jessica","Jim","Joanna"}; //Array类中定义的静态Clear()函数,将数组中任意的连接数组元素清零 // Array::Clear(samples, 0, samples->Length); /* array<double>^ samples = gcnew array<double>(50); Random^ generator = gcnew Random; //在CLR堆上创建一个Random类型的对像,Random对像具有一些可生成伪随机数的函数,我们在下面的循环中使用NextDouble函数 //它返回0.0~1.0之间的double类型的随机数,通过使其与100.0相* //注意:Raddom对像的Next()函数可返回int类型的随机非负为九,如果调用Next()函数时提供一个整数作为参数,该函数将返回小于给定参数的随机非负数,我们也可以提供两个整数参数据--它们表示将返回随机整数的最小值和最大值 for(int i=0; i<samples->Length; i++){ samples[i] = 100.0 * generator->NextDouble(); //generator->NextDouble(); 这是什么东东,表示什么??? } Console::WriteLine(L"The array contains the following values:"); for(int i=0; i<samples->Length; i++) { //循环显示所有samples中的元素 //当5个字符一行显示 Console::Write(L"{0,10:F2}",samples[i]); if((i+1)%5 == 0) Console::WriteLine(); } //找出最大值 double max = 0; for each(double sample in samples){ if(max < sample) max = sample; } Console::WriteLine(L"The maxinum value in the array is {0:F2}",max);*/ //1: 一维数组的排序 //System命名空间中Array类定义了一个可将一维数组的元素以升序排列的事Srot()函数 /*array<int>^ samples ={27,3,54,11,18,2,16}; //Array::Sort(samples); //我们还可以将数组的总分元素排序 Array::Sort(samples,2,3); for each(int val in samples){ Console::Write(L"{0,8}",val); } Console::WriteLine();*/ /*array<String^>^ names = {"Jill","Ted","Mary","Eve","Bill","Al"}; array<int>^ weights = {103,168,128,115,180,176}; for(int i=0; i<names->Length; i++){ Console::WriteLine("姓名:{0},体重{1}",names[i],weights[i]); } Array::Sort(names,weights); Console::WriteLine(L"排序操作以后"); for(int i=0; i<names->Length; i++){ Console::WriteLine("姓名:{0},体重{1}",names[i],weights[i]); }*/ //2: 搜索一维数组 //Array类还提供了搜索一维数组元素的函数,BinarySearch()函数使用对分搜索算法,在整个数组中或者从给定范围的元素中,寻找特定元素的索引位置 //对分搜索算法要求数组元素是顺序排列的,因此我们在看好索之前将数组元素排序 /*array<int>^ values={23,45,68,94,123,127,150,203,299}; int toBeFound = 127; //int position = Array::BinarySearch(values, toBeFound); //为了搜索数组中给定范围的元素,我们要使用接受四个参数的BinarySearch()函数 //第一个是搜索数组的句柄 //第二个参数是搜索开始位置对应的元素索引值 //第三个是参数是搜索的元素数量 //第四个要查找的内容 int position = Array::BinarySearch(values, 1, 3, toBeFound); if(position<0) { Console::WriteLine(L"没有找到{0}",toBeFound); }else{ Console::WriteLine(L"{0}找到了,位置在{1}",toBeFound,position); }*/ /*array<String^>^ names = {"Jill","Ted","Mary","Eve","Bill","Al"}; array<int>^ weights = {103,168,128,115,180,176}; array<String^>^ toBeFound ={"Bill","Eve","Al","Fred"}; Array::Sort(names, weights); int result = 0; 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} weighs {1} lbs",name, weights[result]); } }*/ /*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; } //如果搜索结果为负数,则将所有位反转就是应该插入新姓名的索引位置,如果结果为正数,则说明新姓名与该位置的姓名相同,因此我们可以直接将结果作新位置 array<String^>^ newNames = gcnew array<String^>(names->Length+1); //copy 这里先copy了position前面的字符 for(int i=0; i<position; i++){ newNames[i] = names[i]; } newNames[position] = name; //这里开始copy position后面的数值 if(position < names->Length){ for(int i=position; i<names->Length; i++){ newNames[i+1] = names[i]; } } names = nullptr; for each(String^ str in newNames) { Console::WriteLine(L"str:{0}",str); }*/ // 3 多维数组 //我们可以创建二级或多维数组,数组的最大维数是32 //array<int,2>^ values = gcnew array<int, 2>(4,5); //array<int,2>^ values = gcnew array<int, 2>(4,5); /*int nrows = 4; int ncols = 5; array<int,2>^ values = gcnew array<int,2>(nrows, ncols); for(int i=0; i<nrows; i++){ for(int j=0; j<ncols; j++){ values[i,j] = (i+1) * (j+1); } } for(int i=0; i<nrows; i++){ for(int j=0; j<ncols; j++){ Console::WriteLine("{0}",values[i,j]); } Console::WriteLine(); }*/ /*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); for(int i=0; i<SIZE; i++){ Console::Write(L"_____"); } Console::WriteLine(); Console::Write(L" | "); for(int i=0; i<SIZE; i++) { Console::Write(L"{0,5}",i); } Console::WriteLine(); for(int i=0; i<=SIZE; i++){ Console::Write(L"____|"); } Console::WriteLine(); for(int i=0; i<SIZE; i++) { Console::Write(L"{0,3} |",i+1); for(int j=0; j<SIZE; j++){ Console::Write(L"{0,3} |",products[i,j]); } Console::WriteLine(); } for(int i=0; i<SIZE; i++){ Console::Write(L"_____"); } Console::WriteLine();*/ //4 数组的数组 //数组元素可以是任意类型,因此当然也可以是引用数组的跟踪句柄 /*array< array<String^>^ >^ grades = gcnew array< array<String^>^ >(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"}; //我们看到,字符串数组的长度是变化的,因此显然可以用这种方法管理一组任意长度的数组 //另一种声明方式 array< array<String^>^ >^ gradesBak = gcnew array< array<String^>^ > { gcnew array<String^>{"Louise","Jack"}, gcnew array<String^>{"Bill","Mary","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^>^ gread in gradesBak) { Console::WriteLine(L"Students with Grade {0}:", gradeLetter++); for each(String^ student in gread) { Console::Write(L"{0,12}",student); //字符宽度为12 } Console::WriteLine(); }*/ //4.6.3 字符串 /*System::String^ saying = L"Many hands make light work."; Console::WriteLine("第二个字符是{0}",saying[2]); //注意,我们只能使用索引值来检索字符串中的字符,而不能以这种方式更新字符串,String对像是固定不变的,因此不能被修改 Console::WriteLine("字符串长度为{0}",saying->Length); //1 链接字符串 String^ name1 = L"Beth"; String^ name2 = L"Betty"; String^ name3 = name1 + L" and " + name2; Console::WriteLine("name3:{0}",name3); //我们还可以连接String对像和数值或bool值,这些值将在连接操作之前自动转换为字符串, String^ str = L"Value:"; String^ str1 = str + 2.5; Console::WriteLine("str1:{0}",str1); String^ str2 = str + 25; Console::WriteLine("str1:{0}",str2); String^ str3 = str + true; Console::WriteLine("str1:{0}",str3); //我们也可以链接String对像和字符串,但结果取决于字符的类型 char ch = 'Z'; wchar_t wch = L'Z'; String^ str4 = str + ch; Console::WriteLine("str1:{0}",str4); String^ str5 = str + wch; Console::WriteLine("str1:{0}",str5); //char类型的字符被作为数值对待,因此与字符串连接是字符Z的代码值,wchar_t字符与String对像中的字符具有相同的类型(Char类型) //所以字符Z附加到字符串后面 //不要忘记,String对像固定不变的,它们一旦创建之后就不能再被修改,这意味着所有表面上在修改String对像的操作实际上都是在创建一个新的String对像 //Join()函数,链接成一个字符串 array<String^>^ names = {L"Jill",L"Ted",L"Mary",L"Eve",L"Bill"}; //String^ separtor = L","; String^ separtor = L" and "; String^ joined = String::Join(separtor,names); Console::WriteLine("joined:{0}",joined);*/ /*array<int>^ values = {2,456,23,-46,34211,456,5609,112098,234,-76504,341,6788,-909121,99,10}; String^ formatStr1 = L"{0,"; String^ formatStr2 = L"}"; String^ number; int maxLength = 0; for each(int v in values) { number = L"" + v; //这里将v值转换为String if(maxLength < number->Length) maxLength = number->Length; } String^ format = formatStr1 + (maxLength+1) + formatStr2; int numberPerLine = 3; for(int i=0; i<values->Length; i++) { Console::Write(format,values[i]); if( (i+1) % numberPerLine == 0){ Console::WriteLine(); } } Console::WriteLine();*/ //2 修改字符串 //去空格操作 /*String^ str = {L" Handsome is as handsome does..."}; String^ newStr = str->Trim(); Console::WriteLine("{0}",str); Console::WriteLine("{0}",newStr); String^ toBeTrimmed = L"wool sheep sheep wool wool wool"; array<wchar_t>^ notWanted = {L'w',L'o',L'l',L' '}; Console::WriteLine(toBeTrimmed->Trim(notWanted)); //如果我们只想修改字符串的一端,则可以使用TrimEnd()或TrimStart()函数 //填写充空格或其它字符串 //PadLeft或PadRight()函数 String^ value = L"3.142"; String^ leftPadStr = value->PadLeft(10); Console::WriteLine("{0}",leftPadStr); String^ rightPadStr = value->PadRight(10); Console::WriteLine("{0}",rightPadStr);*/ /*String^ value = L"3.142"; String^ leftPadStr = value->PadLeft(10,L'*'); Console::WriteLine("{0}",leftPadStr); String^ rightPadStr = value->PadRight(10,L'#'); Console::WriteLine("{0}",rightPadStr); //转换为大写或小字母的ToUpper()和ToLower()函数 String^ proverb = L"Many hands make light work."; String^ upper = proverb->ToUpper(); Console::WriteLine("{0}",upper); String^ lower = proverb->ToLower(); Console::WriteLine("{0}",lower);*/ //Insert()函数,可以在现有字符串的给定位置插入一个字符串, /*String^ proverb = L"Many hands make light work."; String^ newProverb = proverb->Insert(5," deck "); Console::WriteLine("{0}",newProverb);*/ //Replace()函数的第一个参数指定要被第二个参数值替换 /*String^ proverb = L"Many hands make light work."; String^ newProverb = proverb->Replace(L' ', L'*'); Console::WriteLine("{0}",newProverb); String^ newProverb_ = proverb->Replace(L"hands",L"HANDS"); Console::WriteLine("{0}",newProverb_);*/ //3 比较字符串 Compare() /*String^ him(L"Jacko"); String^ her(L"Jillo"); int result = String::Compare(him,her); if(result < 0 ){ Console::WriteLine(L"{0} 小于 {1}",him,her); }else if(result > 0){ Console::WriteLine(L"{0} 大于 {1}",him,her); }else{ Console::WriteLine(L"{0} 等于 {1}",him,her); }*/ //Compare()的另一个版本需要第三个参数,类型为bool型,如果第三个参数为true,比罗时忽略大小写,如果为false比较是区分大小写 //4 搜索 StartsWith() EndsWith(); /*String^ sentence = L"Hide, the cow's outside."; if(sentence->StartsWith(L"Hide")){ Console::WriteLine("Hide 存在于 {0}",sentence); }else{ Console::WriteLine("Hide 不存在 {0}",sentence); } Console::WriteLine(L" Hide {0} {1}",sentence->EndsWith(L"Hide") ? L"存在于" : L"不存在", sentence);*/ //IndexOf()函数搜索给定字符或子串在字符串中第一次出现的字符位置 /*String^ sentence = L"Hide, the Cow's outside."; int ePosition = sentence->IndexOf(L'e'); Console::WriteLine("e出现在{0} 的位置为{1}",sentence,ePosition); int thePosition = sentence->IndexOf(L"the"); Console::WriteLine("the出现在{0} 的位置为{1}",sentence,thePosition);*/ //更典型的情况是需要找出给定字符或子串在字会串中出现的所有字符位置 /*String^ sentence = L"Hide, woll the Cow's outside. woll wolll"; int index=0; int count=0; String^ strKey=L"woll"; while((index =sentence->IndexOf(strKey,index)) >= 0) { Console::WriteLine("index:{0}",index); index += strKey->Length; //这里加的是strKey的长度,而不是sentence的长度 ++count; } Console::WriteLine("一共找到了{0}次",count);*/ //ListIndexOf()函数从尾部或指定的索引位置往回搜索 /*String^ sentence = L"Hide, woll the Cow's outside. woll wolll"; int index=sentence->Length - 1; int count=0; String^ strKey=L"woll"; while((index = sentence->LastIndexOf(strKey,index)) >= 0) { Console::WriteLine("index:{0}",index); //index -= strKey->Length; --index; //现在如果发现woll出现时,我们必须将index减一,以便下次往回搜索时从当前woll之前的那个字符开始 count++; } Console::WriteLine("一共找到了{0}次",count);*/ //搜索任意一组字符 /*array<wchar_t>^ punctuation = {L'"',L'\'',L'.',L',',L':',L';',L'!',L'?'}; String^ sentence = L"It's chilly in here\", the boy's monther said coldly."; array<wchar_t>^ indicators = gcnew array<wchar_t>(sentence->Length){L' '}; int index =0; int count = 0; while((index = sentence->IndexOfAny(punctuation,index)) >= 0) { indicators[index] = L'^'; ++index; ++count; } Console::WriteLine(L"there are {0} 一共有 string",count); Console::WriteLine(L"\n{0} \n{1}",sentence, gcnew String(indicators));*/ //4.6.4 跟踪引用 //我们使用%运算符定义跟踪引用, /*int value = 10; int% trackValue = value; trackValue *= 5; Console::WriteLine("value:{0}",value);*/ //4.6.5 内部指针 //虽然我们不能对跟踪句柄中的地址执行算术运算,但是C++/CLI提供的另外一种指针形式却允许算述运算,那就是用关键字interior_ptr定义的内部指针 //内部指针中存储的地址必要时可以由CLR垃圾回收机制自动更新,内部指针总是函数局部自动变量 //下面是定义内部指针的方法, /*array<double>^ data = {1.5,3.5,6.7,4.2,2.1}; interior_ptr<double> pstart = &data[0]; interior_ptr<double> pend = &data[data->Length - 1]; double sum = 0.0; while(pstart <= pend){ sum += *pstart++; } Console::WriteLine(L"Total of data array elememts = {0}",sum); array<String^>^ strings = {L"Land ahoy!", L"Splice the mainbrace!", L"Shiver me timbers!", L"Never throw into the wind!"}; for(interior_ptr<String^> pstrings = &strings[0]; pstrings-&strings[0] < strings->Length; ++pstrings) { Console::WriteLine(*pstrings); }*/