第一個程序:演示了如何使用new來創建動態數組以及使用數組表示法來訪問元素,還指出了指針和真正的數組名之間的差別
#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;
}
不能修改數組名的值。但指針是變量,因此可以修改它的值。請注意將p3加1的效果,表達式p3[0]現在指的是數組的第2個值。因此,將p3加1導致它指向第2個元素而不是第1個。將它減1后,指針將指向原來的值,這樣程序便可以給delete[]提供正確的地址。
第二個程序:指針算術,C++將數組名解釋為地址
#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;
}
在多數情況下,C++將數組名解釋為數組第1個元素的地址。
記住:將指針變量加1后,其增加的值等于指向的類型占用的字節數。
在很多情況下,可以相同的方式使用指針名和數組名。對于它們,可以使用數組方括號表示法,也可以使用解除引用操作符(*)。在多數表達式中,它們都表示地址。區別之一是,可以修改指針的值,而數組名是常量。
pointername = pointername+1; //valid
arrayname = arrayname + 1; //not allowed
對數組應用sizeof操作符得到的是數組的長度,而對指針應用sizeof得到的是指針的長度,即使指針指向的是一個數組。
第三個程序:如何使用不同形式的字符串
#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;
}
數組和指針的特殊關系可以擴展到C-style string,看下面代碼:
char flower[10] = "rose";
cout<<flower<<"s are red\n";
數組名是第一個元素的地址,因此cout語句中的flower是包含字符r的char元素的地址。cout對象認為char的地址是字符串的地址,因此它打印該地址處的字符,然后繼續打印后面的字符,直到遇到空字符(\0)為止。總之,如果給cout提供一個字符的地址,則它將從該字符開始打印,直到遇到空字符為止。
在C++中,用引號括起的字符串像數組名一樣,也是第一個元素的地址。上述代碼不會將整個字符串發送給cout,而只是發送該字符串的地址。
這意味著對于數組中的字符串、用引號括起的字符串常量以及指針所描述的字符串,處理的方式是一樣的,都將傳遞它們的地址。與逐個傳遞字符串中的所有字符相比,這樣做的工作量確實要少。
記住:在cout和多數C++表達式中,char數組名、指向char的指針以及用引號括起的字符串常量都被解釋為字符串第一個字符的地址。 上述的程序中,函數strlen(),返回字符串的長度。函數strcpy()將字符串從一個位置復制到另一個位置。
const char * bird = "wren";
記住,“wren”實際表示的是字符串的地址,因此這條語句將“wren”的地址賦給了bird指針(一般來說,編譯器在內存留出一些空間,以存儲程序源代碼中所有用引號括起來的字符串,并將每個被存儲的字符串與其地址關聯起來)。這意味著可以像使用字符串“wren”那樣使用指針bird。
字符串字面值是常量,這就是為什么代碼在聲明中使用關鍵字const的原因。以這種方式使用const意味著可以用bird來訪問字符串,但不能修改它。
C++不能保證字符串字面值被唯一地存儲。也就是說,如果在程序中多次使用了字符串字面值“wren”,則編譯器將可能存儲該字符串的多個副本,也可能只存儲一個副本。如果是后面一種情況,則將bird設置為指向一個“wren”,將使它只是指向該字符串的唯一一個副本。將值讀入一個字符串可能會影響被認為是獨立的、位于其他地方的字符串。無論如何,由于bird指針被聲明為const,因此編譯器將禁止改變bird指向的位置中的內容。
試圖將信息讀入ps指向的位置將更糟。由于ps沒有被初始化,因此并不知道信息將被存儲在哪里,這甚至可能改寫內存中的信息。幸運的是,要避免這種問題很容易——只要使用足夠大的char數組來接受輸入即可。請不要使用字符串常量或未被初始化的指針來接受輸入。為避免這些問題,也可以使用std::string對象,而不是數組。
注意,將animal賦給ps并不會復制字符串,而只是復制地址。這樣,這兩個指針將指向相同的內存單元和字符串。
要獲得字符串的副本:首先,需要分配內存來存儲該字符串,可以通過聲明另一個數組或使用new來完成。接下來,需要將animal數組的字符串復制到新分配的空間中。將animal賦給ps是不可行的,因為這樣只能修改存儲在ps中的地址,從而失去程序訪問新分配內存的唯一途徑。需要使用庫函數strcpy():strcp()函數接受2個參數,第一個是目標地址,第二是要復制的字符串的地址。應確定,分配了目標空間,并有足夠的空間來存儲副本。
經常需要將字符串放到數組中。初始化數組時,使用=操作符。否則應使用strcpy()或strncpy()。
如果數組的大小比字符串小,函數將字符串中剩余的部分復制到數組后面的內存字節中,可能會覆蓋程序正在使用的其他內存。要避免這種問題,使用strncpy()。該函數還接受第3個參數——要復制的最大字節數。不過,要注意的是,如果該函數在到達字符串結尾之前,目標內存已經用完,則它將不會添加空字符串。因此,應該這樣使用該函數:
strncp(food,"a picnic basket filled with many goodies",19);
food[19]='\0';
第四個程序:一個使用new和delete的范例
下面介紹一個使用new和delete來存儲通過鍵盤輸入的字符串的。該程序定義了一個函數getname(),該函數返回一個指向輸入字符串的指針。該函數將輸入讀入到一個大型的數組中,然后使用new[]創建一個剛好能夠存儲該輸入字符串的內存塊,并返回一個指向該內存塊的指針。對于讀取大量字符串的程序,這種方法可以節省大量的內存。
另外,可以使用new根據需要的指針數量來分配空間,就目前而言,這有點不切實際。下面程序演示了一些技巧。
#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++不保證新釋放的內存就是下一次使用new時選擇的內存。從程序的運行結果可知,確實不是。
在上面程序中,getname()分配內存,而main()釋放內存。將new和delet放在不同的函數中通常并不是一個好辦法,因為這樣很容易忘記使用delete。