(1)define pointer types
有的时候, 使用typedef用于定义一个type name or definition的alias 很有用。
首先是的程序易读性很好。
举个例子:
typedef double Kilometers;
Kilometers distance;
(1) avoid the mistake of omiting an asterisk。 例如, 当我们想要声明两个指针的时候, 很容易犯如下错误。
int* p1, p2;
正确的做法是:
int *p1, *p2;
typedef int* IntPtr;
IntPtr p1, p2;
void sampleFunction(IntPtr& pointerVariable);
易错点: pointer as call by value parameters.
EX:
#include
using namespace std;
typedef int* IntPointer;
void sneaky(IntPointer temp); // pointer as call by value parameters
int main() {
IntPointer p;
p = new int;
*p = 77;
cout << "Before call to function *p == "
<< *p << endl;
sneaky(p);
cout << "After call to function *p == "
<< *p << endl;
delete p;
return 0;
}
void sneaky(IntPointer temp) {
*temp = 99;
cout << "Inside function call *temp == "
<< *temp << endl;
}
对于上例子中, 参数temp 是一个call by value 的参数, 所以他是一个Local variable。 当sneak 函数被调用的时候, temp 变量的值被设定为指针变量p的值。 由于temp 是一个Local variable, 所以生存期不会出了函数, 调用结束后, tamp变量会消失掉, 如果我们在函数内部修改可temp的内容, 也不会改变p 的值。 因为是call by value 的嘛。
但是, p 指向的地址的内容却可能随着temp的改变而改变, 如上例的有77变成了99..虽然变量p 本身的内容没有改变, 还是只想那个地址。
这里有一个易错点, 就是当我们的class 或者struct 里面有一个member variable 为一个pointer type的时候, 如果我们在一个函数中使用call by value arguments of this class type, 函数中对复制进来的对象做出改动的时候, 会implicitly 改变到指针指向的值, 也就是修改到了外部的物件的指针指向的内容, 这是我们不希望发生的。 所以只要class 里面有指针变量, 当我们要将这个类作为函数的参数的时候, 我们需要定义一个copy constructor。
动态数组学习。
下面对于使用的数组时正确的:
#include
using namespace std;
typedef int* IntPtr;
int main() {
int a[10];
IntPtr p;
p = a;//okay
cout << sizeof(a) << endl;
cout << sizeof(p) << endl;
return 0;
}
当我们执行p = a; 语句的时候,于是p 和 a 指向内存中同一块区域。 所以 p[0], p[1], p[3], ... p[9]分别可以代表 a[0], ..., a[10].。 也就是说, 只要指针p 指向的是一个数组的内存区域, 我们就可以使用the square bracket notation(当然也可以使用*(p+i)代表 array[i]).
另外, 虽然上例子中a 表示数组名, 不难看出其还有内存大小的(是内存大小, 而非数组长度的信息)的信息, 因为sizeof(a) 的大小是40啊。
a 存储的是a[0]的地址, 即数组的起始地址。我们有的时候可以将数组名看成一个指针变量, 但是必须吃保留态度, 因为你无法修改一个数组变量的地址。 例如下例就是非法的:
a = p2;// you cannot assign a different address to a
上述语句非法的原因就是Array variable is not of type int*, 我们可以进一步修饰, 将其看成一个呗const 修饰的指针变量, (当然数组之间的直接赋值也是错误的)。 但是任然有保留, 因为数组变量a 还附带有数组size 的 information。
创建动态数组。
使用指针和new创建一个动态数组。
typedef double* DoublePtr;
DoublePtr p;
p = new double[10];
注意delete和new 配套使用, delete [] 和 new [] 配套使用。 关于动态分配, 更多参见absolute C++。
下面说说一个函数如何返回一个数组(A function returns an array)
在C++中, an array type is not allowed as the return type of a function. 例如下面的语句非法:
int [] someFunction();//illegal
int* someFunction;//legal
如下例:
#include
using namespace std;
int* doubler(int a[], int length);
//Postcondition: length is the size of the array a
//all indexed variables of a have values
//returns: a pointer to an array of the same size as a in which
// each indexed variable is double the corresponding element
int* doubler2(int a[], int length);//原位修改, 不许动态分配了
int main() {
int a[] = {1, 2, 3, 4, 5};
int* b;
int length = sizeof(a) / sizeof(int); // 5
b = doubler(a, length);
int i;
cout << "Array a: \n";
for(i = 0; i < length; i++) {
cout << a[i] << " ";
}
cout << endl;
cout << "Array b: \n";
for(i = 0; i < length; i++) {
cout << b[i] << " ";
}
cout << endl;
delete[] b;
return 0;
}
int* doubler(int a[], int length) {
int* temp = new int[length]; // 当然此时必须动态分配的才能保存到函数体外
for(int i = 0; i < length; i++) {
temp[i] = 2 * a[i];
}
return temp;
}
int* doubler2(int a[], int length) {
// 当然此时必须动态分配的才能保存到函数体外
for(int i = 0; i < length; i++) {
a[i] = 2 * a[i];
}
return a;
}
运行结果:
关于多维数组的分配和释放, 参见absoluteC++。
返回一个数组的另一个办法。