指针
每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。
/**
* 取址符 &
*/
int var1;
char var2[10];
cout << "var1 变量的地址: ";
cout << &var1 << endl;
cout << "var2 变量的地址: ";
cout << &var2 << endl;
//var1 变量的地址: 0x61ff0c
//var2 变量的地址: 0x61ff02
复制代码
指针定义
指针是变量内存位置的直接地址,指针存储内存地址,即声明的指针只能赋值为地址,指针是一种类型,与某种数据类型绑定,单独使用指针则是内存地址,使用*访问则是变量值。
int *ip = var1; //error
cout << ip << endl;
//invalid conversion from 'int' to 'int*' [-fpermissive]
复制代码
通过*访问内存地址的值(访问指针的值)
//指针声明
int *ip = &var1;
// 0x61ff0c
复制代码
如果指针所指向的变量没有初始值则仍是内存地址值
NULL空指针
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。
//空指针
int *ptr = NULL;
cout << ptr << endl;
//0
复制代码
在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。然而,内存地址 0 有特别重要的意义,它表明该指针不指向一个可访问的内存位置。但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。如果访问*ptr空指针则会使程序崩溃。
指针运算
指针是一个用数值表示的地址。因此可以对指针执行算术运算。可以对指针进行四种算术运算:++、--、+、-。无法对空指针进行运算。
指针会根据数据类型移动指针到下一个内存位置
//指针运算
int var[3] = {10, 100, 200};
int *ptr1 = var;
for (int i = 0; i < 3; i++) {
cout << "Address of var[" << i << "] = " << ptr1 << endl;
cout << "Value of var[" << i << "] = " << *ptr1 << endl;
// 移动到下一个位置
ptr1++;
}
/**
Address of var[0] = 0x61fee4
Value of var[0] = 10
Address of var[1] = 0x61fee8
Value of var[1] = 100
Address of var[2] = 0x61feec
Value of var[2] = 200
*/
复制代码
指针与数组
一个数组名对应一个指针常量,因此可以直接用指针指向数组,但通过数组名来移动是非法的。换句话说“数组名是一个指针,指向数组第一个值的地址”
int var[3] = {10, 100, 200};
*var = 1;
cout << var[0] << endl;
//1
复制代码
可以通过数组名修改元素(var本身没改变),就和使用指针常量一样,但移动非法
指针数组
指针数组就是指针的数组,每个元素是一个指针
int *ptr2[3];
for (int i = 0; i < 3; i++) {
ptr2[i] = &var[i]; // 赋值为整数的地址
}
for (int i = 0; i < 3; i++) {
cout << "Value of var[" << i << "] = ";
cout << *ptr2[i] << endl;
}
/*
Value of var[0] = 1
Value of var[1] = 100
Value of var[2] = 200
*/
复制代码
可以用一个指向字符的指针数组来存储一个字符串列表
const char *names[4] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali",
};
for (int i = 0; i < 4; i++) {
cout << "Value of names[" << i << "] = ";
cout << names[i] << endl;
}
复制代码
多级指针
指向指针的指针,单纯的字面意思,和指针的含义一样,地址,存放指针的地址,值
//多级指针
int var3 = 2;
int *ptr3 = &var3;
int **pptr = &ptr3;
cout << *ptr3 << endl << pptr << endl << *pptr << endl << **pptr << endl;
/*
2
0x61feb0 //pptr地址
0x61feb4 //ptr3地址
2 //值
*/
复制代码
指针作为函数参数
指针灵活性方面的代表,可以作为参数传递给函数并且参数值会被改变,因为传进去的就是个内存地址,灵活性非常强。
#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;
}
复制代码
从函数返回指针
还是字面意思,函数可以返回指针,但需要注意,不应该返回局部变量的地址,因为局部变量会在函数返回后被销毁。返回的地址指向一个过期的对象,后面可能发生不可预知的行为。需要将返回的地址定义为static
#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;
}
复制代码
引用
引用就是变量别名,一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。
- 不存在空引用。引用必须连接到一块合法的内存。
- 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
- 引用必须在创建时被初始化。指针可以在任何时间被初始化。
引用定义
变量名称是变量附属在内存位置中的标签,可以把引用当成是变量附属在内存位置中的第二个标签。因此,可以通过原始变量名称或引用来访问变量的内容,引用必须被初始化,引用可以当做和变量一样使用。
// 声明简单的变量
int i;
double d;
// 声明引用变量
int& r = i;
double& s = d;
复制代码
引用作为参数
引用作为函数参数,即引用传递,传递变量地址,相当于传递实际的变量地址,而不是值传递(拷贝值)
#include <iostream>
using namespace std;
// 函数声明
void swap(int& x, int& y);
int main ()
{
// 局部变量声明
int a = 100;
int b = 200;
cout << "交换前,a 的值:" << a << endl;
cout << "交换前,b 的值:" << b << endl;
/* 调用函数来交换值 */
swap(a, b);
cout << "交换后,a 的值:" << a << endl;
cout << "交换后,b 的值:" << b << endl;
return 0;
}
// 函数定义
void swap(int& x, int& y)
{
int temp;
temp = x; /* 保存地址 x 的值 */
x = y; /* 把 y 赋值给 x */
y = temp; /* 把 x 赋值给 y */
return;
}
复制代码
引用作为返回值
与指针一样,被引用的对象不能超出作用域。所以返回一个对局部变量的引用是不合法的,但是,可以返回一个对静态变量的引用。
int& func() {
int q;
//! return q; // 在编译时发生错误
static int x;
return x; // 安全,x 在函数作用域外依然是有效的
}
复制代码
指针与引用
指针和引用都能提供对其他对象的间接访问,然而在具体实现细节上二者有很大不 同,其中最重要的一点就是引用本身并非一个对象。一旦定义了引用,就无法令其再绑定到另外的对象,之后每次使用这个引用都是访问它最初绑定的那个对象。
指针和它存放的地址之间就没有这种限制了。和其他任何变量(只要不是引用)一样, 给指针赋值就是令它存放一个新的地址,从而指向一个新的对象




近期评论