一、指针基本定义
cout << &var1 << endl;
输出var对应的内存地址。
指针变量声明的一般形式为:
type *var-name;
如:
int *ip; /* 一个整型的指针 */
double *dp; /* 一个 double 型的指针 */
float *fp; /* 一个浮点型的指针 */
char *ch; /* 一个字符型的指针 */
此时ip对应地址,*ip对应地址的值。
二、指针算术运算
指针算术运算的详细解析:
-
加法运算:可以对指针进行加法运算。当一个指针p加上一个整数n时,结果是指针p向前移动n个元素的大小。例如,如果p是一个int类型的指针,每个int占4个字节,那么p + 1将指向p所指向的下一个int元素。
-
减法运算:可以对指针进行减法运算。当一个指针p减去一个整数n时,结果是指针p向后移动n个元素的大小。例如,如果p是一个int类型的指针,每个int占4个字节,那么p - 1将指向p所指向的前一个int元素。
-
指针与指针之间的减法运算:可以计算两个指针之间的距离。当从一个指针p减去另一个指针q时,结果是两个指针之间的元素个数。例如,如果p和q是两个int类型的指针,每个int占4个字节,那么p - q将得到两个指针之间的元素个数。
-
指针与整数之间的比较运算:可以将指针与整数进行比较运算。可以使用关系运算符(如<、>、<=、>=)对指针和整数进行比较。这种比较通常用于判断指针是否指向某个有效的内存位置。
特殊的,如p++,则代表指针p向前移动指向下一个对应元素。
指针的比较 如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较。
三、指针和数组
指针和数组是密切相关的。事实上,指针和数组在很多情况下是可以互换的。例如,一个指向数组开头的指针,可以通过使用指针的算术运算或数组索引来访问数组。如:
#include <iostream>
using namespace std;
const int MAX = 3;
int main ()
{
int var[MAX] = {10, 100, 200};
int *ptr;
// 指针中的数组地址
ptr = var;
for (int i = 0; i < MAX; i++)
{
cout << "var[" << i << "]的内存地址为 ";
cout << ptr << endl;
cout << "var[" << i << "] 的值为 ";
cout << *ptr << endl;
// 移动到下一个位置
ptr++;
}
return 0;
}
然而,指针和数组并不是完全互换的。例如,请看下面的程序:
#include <iostream>
using namespace std;
const int MAX = 3;
int main ()
{
int var[MAX] = {10, 100, 200};
for (int i = 0; i < MAX; i++)
{
*var = i; // 这是正确的语法
var++; // 这是不正确的
}
return 0;
}
把指针运算符 * 应用到 var 上是完全可以的,但修改 var 的值是非法的。这是因为 var 是一个指向数组开头的常量,不能作为左值。
由于一个数组名对应一个指针常量,只要不改变数组的值,仍然可以用指针形式的表达式。例如,下面是一个有效的语句,把 var[2] 赋值为 500:
*(var + 2) = 500;
四、指针数组
可能有一种情况,我们想要让数组存储指向 int 或 char 或其他数据类型的指针。下面是一个指向整数的指针数组的声明:
int *ptr[MAX];
在这里,把 ptr 声明为一个数组,由 MAX 个整数指针组成。因此,ptr 中的每个元素,都是一个指向 int 值的指针。下面的实例用到了三个整数,它们将存储在一个指针数组中,如下所示:
#include <iostream>
using namespace std;
const int MAX = 3;
int main ()
{
int var[MAX] = {10, 100, 200};
int *ptr[MAX];
for (int i = 0; i < MAX; i++)
{
ptr[i] = &var[i]; // 赋值为整数的地址
}
for (int i = 0; i < MAX; i++)
{
cout << "Value of var[" << i << "] = ";
cout << *ptr[i] << endl;
}
return 0;
}
也可以用一个指向字符的指针数组来存储一个字符串列表。
#include <iostream>
using namespace std;
const int MAX = 4;
int main ()
{
const char *names[MAX] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali",
};
for (int i = 0; i < MAX; i++)
{
cout << "Value of names[" << i << "] = ";
cout << names[i] << endl;
}
return 0;
}
char *names[MAX] 是指针数组, 它的本质是存储指针的数组, 既存储 char 类型的指针的数组, 数组内的每个元素都是一个指针指向一个存储 char 类型的地址。
五、传递指针给函数
C++ 允许您传递指针给函数,只需要简单地声明函数参数为指针类型即可。
下面的实例中,我们传递一个无符号的 long 型指针给函数,并在函数内改变这个值:
#include <iostream>
#include <ctime>
using namespace std;
// 在写函数时应习惯性的先声明函数,然后在定义函数
void getSeconds(unsigned long *par);
int main ()
{
unsigned long sec;
getSeconds( &sec );
// 输出实际值
cout << "Number of seconds :" << sec << endl;
return 0;
}
void getSeconds(unsigned long *par)
{
// 获取当前的秒数
*par = time( NULL );
return;
}
能接受指针作为参数的函数,也能接受数组作为参数,如下所示:
#include <iostream>
using namespace std;
// 函数声明
double getAverage(int *arr, int size);
int main ()
{
// 带有 5 个元素的整型数组
int balance[5] = {1000, 2, 3, 17, 50};
double avg;
// 传递一个指向数组的指针作为参数
avg = getAverage( balance, 5 ) ;
// 输出返回值
cout << "Average value is: " << avg << endl;
return 0;
}
double getAverage(int *arr, int size)
{
int i, sum = 0;
double avg;
for (i = 0; i < size; ++i)
{
sum += arr[i];
}
avg = double(sum) / size;
return avg;
}
六、从函数返回指针
C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 static变量。
现在,让我们来看下面的函数,它会生成 10 个随机数,并使用表示指针的数组名(即第一个数组元素的地址)来返回它们,具体如下:
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
// 要生成和返回随机数的函数
int * getRandom( )
{
static int r[10];
// 设置种子
srand( (unsigned)time( NULL ) );
for (int i = 0; i < 10; ++i)
{
r[i] = rand();
cout << r[i] << endl;
}
return r;
}
// 要调用上面定义函数的主函数
int main ()
{
// 一个指向整数的指针
int *p;
p = getRandom();
for ( int i = 0; i < 10; i++ )
{
cout << "*(p + " << i << ") : ";
cout << *(p + i) << endl;
}
return 0;
}