地址的概念
字节是计算机管理内存的最小单位,每一个字节在内存中都有一个编号,这个编号以数字的形式保存,叫做地址。
在程序中定义所有的变量,在内存都需要分配相应的存储单元,不同类型所需要的存储空间大小是不一样的,比如int型的变量,需要占四个连续的存储单元,也就是需要占四个字节。系统给变量内存空间的其实单元地址称为该变量的地址。
指针变量
在程序中,存放地址的变量也叫做指针变量,用于存放其他变量的地址。
指针变量的定义:数据类型*指针变量名;
int*p;//定义了一个int型的变量p1,用来保存int类型变量的地址
可以使用取址运算符(&)来获取变量的地址
int a=1;
cout << &a << " ";
指针的解引用
使用指针运算符“*”来获取地址中的内容
int a=5;
int*p=&a;
cout<<*p<<endl;
输出结果就是5
字符指针
字符指针可以使用指针或者&输出字符串,如果需要获取字符指针的具体地址,需要使用int*强转,如果不使用强转,会出现乱码。
char ch = 'a';
char* p = &ch;
cout << p << endl;
正确写法应该是
char ch = 'a';
char* p = &ch;
cout << (int*)p << endl;
指针的运算
由于指针存放变量的是地址,因此指针运算就是地址的运算,指针运算主要有算数运算和关系运算。
算数运算
指针可以和整数进行加减法运算,也可以进行自增++和自减--运算,进行运算的结果和该指针指向的数据类型有关,例如指针p是int类型的指针变量,则p+1就是向后移动了四个字节。
int* p, a = 5;
p = &a;
cout << p << endl;
cout << p + 1 << endl;
关系运算
指向同一类型的指针可以进行关系运算,如果两个类型的指针是相等的,则这两个指针指向的是同一个地址。
int arr[10] = { 10,20,30,40,50,60,70,80,90,100 };
int* p1, * p2;
// 将第2个元素的地址赋值给p1
p1 = &arr[1];
// 将第4个元素的地址赋值给p2
p2 = &arr[3];
cout << p1 << " " << p2 << endl;
cout << "p1 > p2 ? " << (p1 > p2) << endl; // 0
cout << "p1 < p2 ? " << (p1 < p2) << endl; // 1
cout << "p1 == p2 ? " << (p1 == p2) << endl; // 0
cout << "p1 != p2 ? " << (p1 != p2) << endl; // 1
指针可以用NULL(0)来比较,如果p==0成立,我们把p叫做空指针。
int* p3 = NULL;
if (p3 == NULL)
{
cout << p3 << endl; // 输出的结果是00000000
cout << "p3是空指针" << endl;
}
else
{
cout << *p3 << endl;
}
return 0;
}
指针和数组
数组在内存是连续存放的,所以数组名就是数组的第一个元素的地址,所以数组不需要使用取值符就可以将地址赋值给指针变量来使用。
int arr[5] = { 10,20,30,40,50 };
cout << arr << endl;
cout << *arr;
*p++运算符可以输出数组的第二个元素
int arr[5] = { 10,20,30,40,50 };
int* p = arr;
*p++;
cout << *p << endl;
可以利用指针变量来遍历输出数组中的所有元素
int* p = arr;
for (int i = 0; i < 5; i++)
{
cout << *p << " ";
p++;
//cout << *(p + i) << " ";
// p和arr实际上是一样的,所以arr[i]可以 p[i]也可以
//cout << p[i] << " ";
}
指针数组
数组元素是指针变量的数组叫做指针数组
定义方式:类型名*数组名[数组长度]
int arr1[2]={10,20};
int*p=arr1;
int n=10;
p1[0]=&n;
cout<<*p1[0]<<endl;
也可以使用指针数组处理二维数组
int arr[2][3]={1,2,3,4,5,6};
int*p[2]
p2[0]=arr[0];
p2[1]=arr[1];
例如: 遍历一个二维数组
int arr[2][3] = {
{10,20,30},
{40,50,60}
};
int* p2[2];
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
//p2[i]相当于获取二维数组中的每一行一维数组的首地址 p2[i][j]就是获取每一行的元素
//cout << p[i][j] << " ";
// p2[i]相当于获取的是二维数组的每一行的首地址,p[i]+j就是每一行的首地址来进行指针运算
// *(p2[i] + j) 是对指针运算完的结果进行解引用的操作,才能获取到元素值
//cout << *(p2[i] + j) << endl;
}
}
多级指针
如果一个指针变量保存的是另外一个指针变量的地址,我们就称之为指向指针的指针,也叫做多级指针。
语法:三级指针:数据类型 ***指针变量名;
二级指针:数据类型 **指针变量名;
int a, * p1, ** p2;
a = 10;
p1 = &a;
p2 = &p1;
cout << a << endl << *p1 << endl << **p2 << endl;
得到的结果是三个10。
分别对其取地址:
int a, * p1, **p2;
a = 10;
p1 = &a;
p2 = &p1;
cout << p1 << endl << *p2 << endl << &a << endl;
利用指针变量来处理二维数组的地址问题
例如:利用指针变量来遍历一个二维数组:
使用一层for循环就可以解决
#include<iostream>
using namespace std;
int main()
{
int arr[3][4] =
{
{10,20,30,40},
{20,30,40,50},
{30,40,50,60}
};
for (int i = 0; i < 12; i++)
{
cout << *(*(arr)+i) << endl;//*arr是取数组第一行首地址,*(*arr+i)对每个元素的地址解引用
}
也可以使用双重for循环来处理这个问题
#include<iostream>
using namespace std;
int main()
{
int arr[3][4] =
{
{10,20,30,40},
{20,30,40,50},
{30,40,50,60}
};
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
//cout << *(arr[i] + j);这两种方法都可以实现对二维数组的遍历
cout << *(*(arr + i) + j);
}
}