第一個(gè)程序:演示了如何使用new來創(chuàng)建動(dòng)態(tài)數(shù)組以及使用數(shù)組表示法來訪問元素,還指出了指針和真正的數(shù)組名之間的差別
#include "stdafx.h"
#include <iostream>
using namespace std;
int main(int argc, char* argv[])


{
double * p3=new double[3];//space for 3 doubles
p3[0]=0.2;
p3[1]=0.5;
p3[2]=0.8;
cout<<"p3[1] is "<<p3[1]<<endl;
p3=p3+1;//increment the pointer
cout<<"Now p3[0] is "<<p3[0]<<" and ";
cout<<"p3[1] is "<<p3[1]<<endl;
p3=p3-1;//point back to beginning
delete[] p3;
return 0;
}
不能修改數(shù)組名的值。但指針是變量,因此可以修改它的值。請(qǐng)注意將p3加1的效果,表達(dá)式p3[0]現(xiàn)在指的是數(shù)組的第2個(gè)值。因此,將p3加1導(dǎo)致它指向第2個(gè)元素而不是第1個(gè)。將它減1后,指針將指向原來的值,這樣程序便可以給delete[]提供正確的地址。
第二個(gè)程序:指針?biāo)阈g(shù),C++將數(shù)組名解釋為地址
#include "stdafx.h"
#include <iostream>
using namespace std;
int main(int argc, char* argv[])


{

double wages[3]=
{10000.0,20000.0,30000.0};

short stacks[3]=
{3,2,1};

//Here are two ways to get the address of an array
double * pw=wages; //name of an array = address
short * ps=&stacks[0]; //or use address operator
//with array element
cout<<"pw = "<<pw<<", *pw = "<<*pw<<endl;
pw=pw+1;
cout<<"pw = "<<pw<<", *pw = "<<*pw<<"\n\n";

cout<<"ps = "<<ps<<", *ps = "<<*ps<<endl;
ps=ps+1;
cout<<"add 1 to the ps pointer:\n";
cout<<"ps = "<<ps<<", *ps = "<<*ps<<"\n\n";

cout<<"access two elements with array notation\n";
cout<<"stacks[0] = "<<stacks[0]<<", stacks[1] = "<<stacks[1]<<endl;
cout<<"access two elements with pointer notation\n";
cout<<"*stacks = "<<*stacks<<", *(stacks+1) = "<<*(stacks+1)<<endl;

cout<<sizeof(wages)<<" = size of wages array\n";
cout<<sizeof(pw)<<" = size of pw pointer\n";
return 0;
}
在多數(shù)情況下,C++將數(shù)組名解釋為數(shù)組第1個(gè)元素的地址。
記住:將指針變量加1后,其增加的值等于指向的類型占用的字節(jié)數(shù)。
在很多情況下,可以相同的方式使用指針名和數(shù)組名。對(duì)于它們,可以使用數(shù)組方括號(hào)表示法,也可以使用解除引用操作符(*)。在多數(shù)表達(dá)式中,它們都表示地址。區(qū)別之一是,可以修改指針的值,而數(shù)組名是常量。
pointername = pointername+1; //valid
arrayname = arrayname + 1; //not allowed
對(duì)數(shù)組應(yīng)用sizeof操作符得到的是數(shù)組的長(zhǎng)度,而對(duì)指針應(yīng)用sizeof得到的是指針的長(zhǎng)度,即使指針指向的是一個(gè)數(shù)組。
第三個(gè)程序:如何使用不同形式的字符串
#include "stdafx.h"
#include <iostream>
#include <cstring> //declare strlen(),strcpy()
using namespace std;
int main(int argc, char* argv[])


{
char animal[20] = "bear"; //animal holds bear;
const char * bird = "wren"; //bird holds address of string
char * ps; //uninitialized

cout<<animal<<" and "; //display bear
cout<<bird<<"\n"; //display wren

cout<<"Enter a kind of animail: ";
cin>>animal;

ps=animal;
cout<<ps<<"s!\n";
cout<<"Before using strcpy();\n";
cout<<animal<<" at "<<(int *)animal<<endl;
cout<<ps<<" at "<<(int *)ps<<endl;

ps = new char[strlen(animal)+1];//get new storage
strcpy(ps,animal);//copy string to new storage
cout<<"After using strcpy():\n";
cout<<animal<<" at "<<(int *)animal<<endl;
cout<<ps<<" at "<<(int *)ps<<endl;
delete [] ps;
return 0;
}
數(shù)組和指針的特殊關(guān)系可以擴(kuò)展到C-style string,看下面代碼:
char flower[10] = "rose";
cout<<flower<<"s are red\n";
數(shù)組名是第一個(gè)元素的地址,因此cout語(yǔ)句中的flower是包含字符r的char元素的地址。cout對(duì)象認(rèn)為char的地址是字符串的地址,因此它打印該地址處的字符,然后繼續(xù)打印后面的字符,直到遇到空字符(\0)為止。總之,如果給cout提供一個(gè)字符的地址,則它將從該字符開始打印,直到遇到空字符為止。
在C++中,用引號(hào)括起的字符串像數(shù)組名一樣,也是第一個(gè)元素的地址。上述代碼不會(huì)將整個(gè)字符串發(fā)送給cout,而只是發(fā)送該字符串的地址。
這意味著對(duì)于數(shù)組中的字符串、用引號(hào)括起的字符串常量以及指針?biāo)枋龅淖址幚淼姆绞绞且粯拥模紝鬟f它們的地址。與逐個(gè)傳遞字符串中的所有字符相比,這樣做的工作量確實(shí)要少。
記住:在cout和多數(shù)C++表達(dá)式中,char數(shù)組名、指向char的指針以及用引號(hào)括起的字符串常量都被解釋為字符串第一個(gè)字符的地址。 上述的程序中,函數(shù)strlen(),返回字符串的長(zhǎng)度。函數(shù)strcpy()將字符串從一個(gè)位置復(fù)制到另一個(gè)位置。
const char * bird = "wren";
記住,“wren”實(shí)際表示的是字符串的地址,因此這條語(yǔ)句將“wren”的地址賦給了bird指針(一般來說,編譯器在內(nèi)存留出一些空間,以存儲(chǔ)程序源代碼中所有用引號(hào)括起來的字符串,并將每個(gè)被存儲(chǔ)的字符串與其地址關(guān)聯(lián)起來)。這意味著可以像使用字符串“wren”那樣使用指針bird。
字符串字面值是常量,這就是為什么代碼在聲明中使用關(guān)鍵字const的原因。以這種方式使用const意味著可以用bird來訪問字符串,但不能修改它。
C++不能保證字符串字面值被唯一地存儲(chǔ)。也就是說,如果在程序中多次使用了字符串字面值“wren”,則編譯器將可能存儲(chǔ)該字符串的多個(gè)副本,也可能只存儲(chǔ)一個(gè)副本。如果是后面一種情況,則將bird設(shè)置為指向一個(gè)“wren”,將使它只是指向該字符串的唯一一個(gè)副本。將值讀入一個(gè)字符串可能會(huì)影響被認(rèn)為是獨(dú)立的、位于其他地方的字符串。無(wú)論如何,由于bird指針被聲明為const,因此編譯器將禁止改變bird指向的位置中的內(nèi)容。
試圖將信息讀入ps指向的位置將更糟。由于ps沒有被初始化,因此并不知道信息將被存儲(chǔ)在哪里,這甚至可能改寫內(nèi)存中的信息。幸運(yùn)的是,要避免這種問題很容易——只要使用足夠大的char數(shù)組來接受輸入即可。請(qǐng)不要使用字符串常量或未被初始化的指針來接受輸入。為避免這些問題,也可以使用std::string對(duì)象,而不是數(shù)組。
注意,將animal賦給ps并不會(huì)復(fù)制字符串,而只是復(fù)制地址。這樣,這兩個(gè)指針將指向相同的內(nèi)存單元和字符串。
要獲得字符串的副本:首先,需要分配內(nèi)存來存儲(chǔ)該字符串,可以通過聲明另一個(gè)數(shù)組或使用new來完成。接下來,需要將animal數(shù)組的字符串復(fù)制到新分配的空間中。將animal賦給ps是不可行的,因?yàn)檫@樣只能修改存儲(chǔ)在ps中的地址,從而失去程序訪問新分配內(nèi)存的唯一途徑。需要使用庫(kù)函數(shù)strcpy():strcp()函數(shù)接受2個(gè)參數(shù),第一個(gè)是目標(biāo)地址,第二是要復(fù)制的字符串的地址。應(yīng)確定,分配了目標(biāo)空間,并有足夠的空間來存儲(chǔ)副本。
經(jīng)常需要將字符串放到數(shù)組中。初始化數(shù)組時(shí),使用=操作符。否則應(yīng)使用strcpy()或strncpy()。
如果數(shù)組的大小比字符串小,函數(shù)將字符串中剩余的部分復(fù)制到數(shù)組后面的內(nèi)存字節(jié)中,可能會(huì)覆蓋程序正在使用的其他內(nèi)存。要避免這種問題,使用strncpy()。該函數(shù)還接受第3個(gè)參數(shù)——要復(fù)制的最大字節(jié)數(shù)。不過,要注意的是,如果該函數(shù)在到達(dá)字符串結(jié)尾之前,目標(biāo)內(nèi)存已經(jīng)用完,則它將不會(huì)添加空字符串。因此,應(yīng)該這樣使用該函數(shù):
strncp(food,"a picnic basket filled with many goodies",19);
food[19]='\0';
第四個(gè)程序:一個(gè)使用new和delete的范例
下面介紹一個(gè)使用new和delete來存儲(chǔ)通過鍵盤輸入的字符串的。該程序定義了一個(gè)函數(shù)getname(),該函數(shù)返回一個(gè)指向輸入字符串的指針。該函數(shù)將輸入讀入到一個(gè)大型的數(shù)組中,然后使用new[]創(chuàng)建一個(gè)剛好能夠存儲(chǔ)該輸入字符串的內(nèi)存塊,并返回一個(gè)指向該內(nèi)存塊的指針。對(duì)于讀取大量字符串的程序,這種方法可以節(jié)省大量的內(nèi)存。
另外,可以使用new根據(jù)需要的指針數(shù)量來分配空間,就目前而言,這有點(diǎn)不切實(shí)際。下面程序演示了一些技巧。
#include "stdafx.h"
#include <iostream>
#include <cstring> //or string.h
using namespace std;
char * getname(void); //function prototype
int main(int argc, char* argv[])


{
char * name;//create pointer but no storage

name=getname();//assign address of string to name
cout<<name<<" at "<<(int*)name<<"\n";
delete[] name;//memory freed

name=getname();//reuse freed memory
cout<<name<<" at "<<(int*)name<<"\n";
delete[] name;//memory freed again
return 0;
}
char * getname() //return pointer to new string


{
char temp[80];//temporary storage
cout<<"Enter last name: ";
cin>>temp;
char * pn=new char[strlen(temp)+1];
strcpy(pn,temp);//copy string into smaller space
return pn;//temp lost when function ends
}
C++不保證新釋放的內(nèi)存就是下一次使用new時(shí)選擇的內(nèi)存。從程序的運(yùn)行結(jié)果可知,確實(shí)不是。
在上面程序中,getname()分配內(nèi)存,而main()釋放內(nèi)存。將new和delet放在不同的函數(shù)中通常并不是一個(gè)好辦法,因?yàn)檫@樣很容易忘記使用delete。