C++笔记(?):指针

一、指针是什么

在定义一个普通变量时,程序为其分配内存,内存位置有一个地址,可通过&运算符访问值的地址.
指针也是一种变量,其储存的是一个值的地址,而不是值本身.

#include<iostream>

using namespace std;

int main()
{
    int a = 10;
    cout << "a的地址:" << &a << endl;
    return 0;
 }
a的地址:0x6ffe1c

显示地址时,常用十六进制表示法来描述.

  • 声明和初始化指针
int *p = &a;

int* 的类型是指向int的指针,则p是一个指针,储存地址;
*p则是一个int.
初始化时,被初始化的是指针p,而不是指针指向的值,因此初始化时赋值为一个地址&a.

a 和 *p 相同,均是一个值;
&a 和 p 相同,均是一个地址;

一个例子:

#include<iostream>

using namespace std;

int main()
{
    int a = 10;
    int *p = &a;
    cout << "Value of a : " << a << endl;
    cout << "Address of a : " << &a << endl;
    cout << "Value of *p : " << *p << endl;
    cout << "Value of p : " << p << endl;
    return 0;
 }
Value of a : 10
Address of a : 0x6ffe04
Value of *p : 10
Value of p : 0x6ffe04

指针可以指向其他数据类型

double *p1;
char *p2;
float *p3;

p1, p2, p3均是指针,只是指向不同的类型,但其储存的都是一个十六进制地址.

二、指针与数组

用指针指向数组时,不使用&运算符,数组名称a即表示数组的地址;

int a[3] = {1, 2, 3};
int *p;
p = a;
  • 运用指针访问数组的值
    初始化指针p后,p指向数组的第一个元素,则*p是第一个元素的值.
    访问数组中的其他元素,可以把指针当作数组名使用,即使用p[1]访问第二个元素.
#include<iostream>

using namespace std;

int main()
{
    int a[3] = {1, 2, 3};
    int *p;
    p = a;
    cout << "*p = " << *p << endl;
    cout << "p[1] = " << p[1] << endl;
    return 0;
 }
*p = 1
p[1] = 2

另一种访问不同元素的方式:

#include<iostream>

using namespace std;

int main()
{
    int a[3] = {1, 2, 3};
    int *p;
    p = a;
    cout << "p[0] = " << p[0] << endl;
    cout << "p[1] = " << p[1] << endl;
    p++;
    cout << "new p[1] = " << p[1] << endl;
    return 0;
 }
p[0] = 1
p[1] = 2
new p[1] = 3

p是地址,p++不会修改指针指向的数组的值,但指针是变量,此次修改试指针指向下一个元素.

数组名既然也表示数组的地址,则可以像使用指针一样使用数组名.
同理,array初始时也指向数组array的第一个元素,(array + 1)则指向下一个元素.
但数组名与指针也有不同,array = array + 1是不合法的.

int array[3] = {1, 2, 3};
cout << "*array = " << *array << endl;
cout << "*(array + 1) = " << *(array + 1) << endl;
return 0;
*array = 1
*(array + 1) = 2

三、通过指针修改变量

对指针p进行加减,改变的是地址,对*p进行四则运算,则变量a中的值也被改变.

#include<iostream>

using namespace std;

int main()
{
    int a = 1;
    int *p = &a;
    cout << "*p = " << *p << endl;
    *p = *p + 1;
    cout << "new *p = " << *p << endl;
    cout << "new a = " << a << endl;
    return 0;
 }
*p = 1
new *p = 2
new a = 2

四、new运算符

new运算符可以在程序运行阶段分配未命名的内存,这样的内存只能通过指针来访问.

  • 在运行时”新建”一个int
    new会为指定的数据类型找到一个长度正确的内存块,并返回该内存块的地址,赋值给一个指针.
int *pn = new int;

new在得知需要一个int后,找到int需要的字节数的内存,把地址返回赋给指针pn,*pn则是一个新的int.

double *pd = new double;
*pd = 1.41;
cout << *pd << endl;

new分配的内存块与变量声明分配的内存块不同,变量的值被储存在称为的内存区域中,而new从被称为自由存储区的内存区域中分配内存.

  • delete运算符
    new可以请求内存,当内存不再需要使用时,可以用delete运算符把内存释放,释放的内存可供程序其他部分使用.
    使用delete时,后面为指向内存块的指针(只能是用new分配的).
int *pn = new int;
…
delete pn;

一些不建议的行为:

int a = 5;
int *p1 = &a;
delete p1; //不要用delete释放不是new分配的内存;
int *p2 = new int;
delete p2; //OK
delete p2; //不那么OK
//不要重复用detele释放同一内存

指针的内存被释放后,指针可继续使用,让其指向变量或用new请求新的内存块.

int *pn = new int;
*pn = 1;
cout << "NO.1 *pn = " << *pn << endl;
delete pn;
int a = 5;
pn = &a;
cout << "NO.2 *pn = " << *pn << endl;
  • 动态数组
    对于小型变量,用new来节省内存没有太大意义,但对于大型数组,正是new大显身手之处.

通过声明来创建数组,则程序在编译时就给其分配内存空间,在运行时,这部分空间无论是否有被使用,都被占据着;
静态联编:在编译时给数组分配内存.
使用new来创建数组,在运行阶段,需要时创建,不需要就不创建,同时可以在运行时选择数组的长度;
动态联编:在运行时给数组分配内存.

使用静态联编时,编写程序时必须确定数组长度;使用动态联编时,可以运行时再确定数组长度,节省内存,这种数组叫动态数组.

创建动态数组:

int *p = new int[10];

new运算符找到了可储存包含10个int的数组的内存块,并把第一个元素的地址返回给指针p.
释放整个数组:

delete []p;

动态数组方括号[]中的长度可以不是常量,即变量也OK.

#include<iostream>

using namespace std;

int main()
{
    int a;
    scanf("%d", &a);
    int *p = new int[a];
    for(int i=1; i<=a; i++)
    {
        *p = i;
	printf("p[%d] = %d \n", i-1, *p);
	p++;
    }
    delete []p;
    return 0;
 } 

五、const关键字与指针

const关键字的使用将无法通过指针修改被指向的对象.

  • 常量指针1
int a = 10;
const int *p = &a;

*p的数据类型为const int,即p指向一个常量,不能使用*p来修改值.
但是a仍然是一个变量,可以直接通过a来修改a的值.

a = a + 1; //OK
*p = 11; //不怎么OK
  • 常量指针2
const int a = 10;
const int *p = &a;

把const变量的地址赋给const指针,则既不可以通过a来修改值,也不可以通过指针p来修改a的值.
把const变量的地址赋给普通指针是不可行的.

const int a = 10;
int *p = &a; //不怎么OK
  • 还有一件事
int a = 10;
const int *p = &a;
int b = 12;
p = &b; //OK

const指针可以防止指针修改指向的值,但是不可以阻止指针自身的值(指向的地址)被改变.
另一种const可以解决这个问题:

int a = 10;
int *const pp = &a;
*pp = 12; //OK
pp = &b; //不怎么OK

把const换一个位置,此时指针pp指向的地址不可被改变,但是可以通过指针pp修改变量a的值.
把两种const同时使用:

const int *const po = &a;
po = &b; //不怎么OK
*po = 12; //不怎么OK

此时指针po指向的地址不可改变,也不可通过po改变变量a的值.

posted @ 2022-08-16 17:14  Wang_ZR  阅读(11)  评论(0)    收藏  举报