指针和数组基本等价的原因在于指针算术和C/C++内部处理数组的方式。
#include <iostream>
using namespace std;
int main()
{
double wages[3] = {100.0, 200.0, 300.0};
short stacks[3] = {3, 2, 1};
double *pw = wages;
short *ps = &stacks[0];
cout << "pw = " << pw << ", *pw = " << *pw <<endl;
pw = pw + 1;
cout << "add 1 to the pw pointer:\n";
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;
}
(1) 上面程序能运行的原因是C/C++将数组名解释为地址。和所有的数组一样,wages存在下面的等式:wages = &wages[0] = 数组中第一个元素的地址;。
(2) 将指针变量加1后,其增加的值等于指向的类型占用的字节数。pw指向double类型,因此对pw加1就会让它的值增加8个字节。
(3) 从程序的输出可知,*(stacks + 1)和stacks[1]是等价的。同样,*(stacks + 2)和stacks[2]是等价的。
在很多情况下,可以以相同的方式使用指针名和数组名。区别之一是,可以修改指针的值,而数组名是常量:
pointername = pointername + 1; //合法
arrayname = arrayname + 1; //不合法
(4)另一个区别是,对数组应用sizeof运算符得到的是数组的长度,而对指针应用sizeof得到的是指针的长度,即使指针指向一个数组。
(5)数组名被解释为其第一个元素的地址,而对数组名应用地址运算符时,得到的是整个数组的地址:
short tell[10];
cout << tell << endl; //是第一个元素的地址
cout << &tell << endl; //是整个数组的地址
从数字上看,两个地址相同,但从概念上说,&tell[0]是一个2字节内存块的地址,而&tell是一个20字节内存块的地址。因此,表达式tell+1将地址值加2,而表达式&tell+2将地址加20。换句话说,tell是一个short指针(*short),而&tell是一个这样的指针,即指向包含20个元素的short数组(short(*)[20])。
(6)使用指针的金科玉律:一定要在对指针应用解除引用运算符(*)之前,将指针初始化为一个确定的、适当的地址。
使用new创建动态结构
使用new创建动态结构的步骤:创建结构和访问成员。创建动态结构时,不能将成员运算符句点用于结构名,因为这种结构没有名称,只是知道它的地址。C/C++专门为这种情况提供了一个运算符:箭头成员运算符(->)。
另一种访问结构成员的方法是,如果ps是指向结构的指针,则*ps就是被指向的值——结构本身。由于*ps是一个结构,因此(*ps).price是该结构体的price成员。C++的运算符优先规则要求使用括号。
#include <iostream>
using namespace std;
struct asd
{
char name[20];
float volume;
double price;
};
int main()
{
asd *ps = new asd;
cout << "Enter asd item: ";
cin.get(ps->name, 20);
cout << "Enter volume:";
cin >> (*ps).volume;
cout << "Enter price:";
cin >> ps->price;
cout <<endl;
cout << "Name: " << (*ps).name <<endl;
cout << "Volume: " << ps->volume << " cubic feet\n";
cout << "Price: " << ps->price <<endl;
delete ps;
return 0;
}
使用new和delete的实例
#include <iostream>
#include <cstring>
using namespace std;
char *getname(void);
int main()
{
char *name;
name = getname();
cout << name << " at " << (int *)name <<endl;
delete []name; //指针所指向的空间被释放,但指针还可以使用
name = getname();
cout << name << " at " << (int *)name <<endl;
delete []name;
return 0;
}
char *getname()
{
char temp[80];
cout << "Enter last name: ";
cin >> temp;
char *pn = new char[strlen(temp) + 1];
strcpy(pn, temp);
return pn;
}
获取空间后,getname()使用标准库函数strcpy()将temp中的字符串复制到新的内存快中,该函数并不检查内存块是否容纳字符串,但getname()通过使用new请求合理的字节数来完成这样的工作。
二级指针实例
若A是指向指针的指针,则称为二级指针。将用于存放二级指针的变量称为二级指针变量。
#include <iostream>
using namespace std;
struct asd
{
int year;
};
int main()
{
asd s1,s2,s3;
s1.year = 2017;
asd *pa = &s2;
pa->year = 2018;
asd trio[3];
trio[0].year = 2019;
cout << trio->year <<endl;
const asd *arp[3] = {&s1, &s2, &s3};
cout << arp[1]->year <<endl;
const asd **ppa = arp;
cout << (*ppa)->year <<endl;
cout << (*(ppa+1))->year <<endl;
return 0;
}
由于ppa指向arp的第一个元素,因此*ppa为第一个元素(ppa是一个指向结构指针的指针,因此*ppa是一个结构指针),即&s1。所以,(*ppa)->year为s1的year成员(*ppa等价于arp[0],所以(*ppa)->year等价于arp[0]->year)。之前提到的,如果ps是指向结构的指针,则*ps就是被指向的值——结构本身。所以还可以这样访问arp[0]所指向的s1:
cout << (**ppa).year <<endl;
使用数组区间
对于处理数组的函数,必须将数组中的数据种类、数组的起始位置和数组中元素数量提交给它;传统的C/C++方法是,将指向数组起始处的指针作为一个参数,将数组长度作为第二个参数。另一种给函数提供信息的方法是指定元素区间,这可以通过传递两个指针来完成,一个指针标识数组开头,另一个指针标识数组的尾部。STL使用"超尾"概念来指定区间。也就是说,对于数组而言,标识数组结尾的参数将是指向最后一个元素后面的指针。
#include <iostream>
using namespace std;
const int Asize = 8;
int sum_arr(const int *begin, const int *end);
int main()
{
int asd[Asize] = {1, 2, 4, 8, 16, 32, 64, 128};
int sum = sum_arr(asd, asd + Asize);
cout << "Total asd: " << sum <<endl;
sum = sum_arr(asd, asd + 3);
cout << "First three elements: " << sum <<endl;
sum = sum_arr(asd + 4, asd + 8);
cout << "Last four elements: " << sum <<endl;
return 0;
}
int sum_arr(const int *begin, const int *end)
{
const int *pt;
int total = 0;
for(pt = begin; pt != end; pt++)
{
total = total + *pt;
}
return total;
}