C++基础篇(三)指针详解与示例

一、指针定义和使用

1.1 单指针

在C++中,指针是一个变量,它存储了另一个变量的内存地址。可以通过指针来访问和修改它所指向的变量的值。
指针所占的内存一般跟处理器的体系架构有关,在X86的处理器下,占4个字节,在X64下占8个字节。
要使用指针,需要先声明一个指针变量。声明指针变量的语法如下:

type *pointer_name;

其中,type是指针所指向的变量的类型,pointer_name是指针变量的名称。

例如,可以声明一个指向整型变量的指针:

int *p;

接下来,需要将指针变量初始化,即将它指向一个已经存在的变量。可以使用取地址运算符&来获取一个变量的内存地址,并将其赋值给指针变量。

int x = 10;
int *p = &x;
cout <<  p << endl;  //输出的是p所指向变量的地址,即x的地址,而不是p的地址

在上面的代码中,声明了一个整型变量x并将其初始化为10。然后,使用取地址运算符&获取x的内存地址,并将其赋值给指针变量p。现在,p指向了变量x。

*是解引用运算符,作用是找到指针指向内存中的数据,可以使用解引用运算符来访问和修改指针所指向的变量的值。


cout << *p << endl; // 输出10
*p = 20;
cout << x << endl; // 输出20

在上面的代码中,使用解引用运算符*访问了指针p所指向的变量的值,并将其输出。然后,使用解引用运算符修改了指针所指向的变量的值。

1.2 多重指针

多重指针是指指向指针的指针。例如,可以声明一个指向整型指针的指针:

int x = 10;
int *p = &x;
int **pp = &p;
out << p << endl; // 输出x的内存地址
cout << pp << endl; // 输出指针p的内存地址

在上面的代码中,声明了一个整型变量x并将其初始化为10。然后声明一个指向整型变量的指针p并将其初始化为x的内存地址。接着声明一个指向整型指针的指针pp并将其初始化为p的内存地址。

使用多重解引用运算符来访问和修改多重指针所指向的值。

cout << **pp << endl; // 输出10
**pp = 20;
cout << x << endl; // 输出20

在上面的代码中,使用多重解引用运算符访问了多重指针pp所指向的值,并将其输出。然后使用多重解引用运算符修改了多重指针所指向的值。

二、指针的其他应用

2.1 const修饰的指针

在C++中,可以使用const关键字来修饰指针,表示指针所指向的值不能被修改或指针本身不能被修改。根据const关键字的位置,可以将const修饰的指针分为三类:常量指针(修饰指针)、指针常量(修饰常量)、既修饰指针又修饰常量。
①常量指针(修饰指针)
常量指针是一个指针,它指向一个常量,也可以理解为常量的指针·。这意味着不能通过这个指针来修改它所指向的值,但是指针的指向(指向的地址)可以修改,想修改这个值就只能直接在这个值上修改

int x = 10;
int y = 20;
const int *p = &x;
*p = 20; // 错误:不能通过常量指针来修改值
p = &y;  //正确:输出*p=20
x = 20; // 正确:直接修改x的值

②指针常量(修饰常量)
指针常量,,但是它不能被重新赋值。将一个指针常量初始化后,它就只能指向同一个地址。也就是说指针指向的值可以修改,但是指针的指向(指向的地址)不能修改

int x = 10;
int *const p = &x;
int y = 20;
*p = 20; // 正确:通过指针常量来修改值
p = &y; // 错误:不能重新赋值指针常量


③既修饰指针又修饰常量
除了常量指针和指针常量之外,还有一种情况是指针的指向和它所指向的值都不能被修改。这种情况可以通过在类型名之前和*之后都加上const关键字来实现。

int x = 10;
const int *const p = &x;
*p = 20; // 错误:不能通过常量指针来修改值
int y = 20;
p = &y; // 错误:不能重新赋值指针常量

2.2 指针与数组

数组名本身就是一个指针常量,它存储了数组第一个元素的内存地址。可以使用数组名来访问数组中的元素。

int arr[] = {1, 2, 3};
cout << *arr << endl; // 输出1
cout << *(arr + 1) << endl; // 输出2
cout << *(arr + +) << endl; // 输出2

数组名不能被重新赋值也就是不能改变它所指向的内存地址,但是可以通过它来修改它所指向的值。

int arr[] = {1, 2, 3};
arr = nullptr; // 错误:不能重新赋值数组名
arr[0] = 10; // 正确:可以通过数组名来修改值

在本人博客c++基础篇(二)基本数组及示例中详细的说明了高维数组和指针的配合使用。

2.3 指针与函数

在C++中,可以使用指针作为函数参数来传递变量的地址。这样,在函数中对指针所指向的变量进行修改时,原变量也会被修改。这种方式被称为地址传递。
与地址传递相对应的是值传递。将一个变量的值作为实参传递给一个函数时,函数中对应的形参将接收到这个值的拷贝。在函数中,可以修改这个拷贝,但是原变量不会被修改。
①值传递

void increment(int x) {
    x++;
}

int main() {
    int a = 10;
    increment(a);
    cout << a << endl; // 输出10
    return 0;
}

在上面的代码中,定义了一个increment函数,它接受一个整型变量作为形参,并进行自增操作。然后,在main函数中,声明一个整型变量a并将其初始化为10。调用increment函数并将a的值作为实参传递给它。在increment函数中,对a的拷贝进行了自增操作。但是,由于这只是对拷贝的修改,所以原变量a并没有被修改。最后输出a的值,仍然是10。
②地址传递
与值传递不同,使用地址传递时,在函数中对指针所指向的变量进行修改时,原变量也会被修改。

void increment(int *x) {
    (*x)++;//解引用,将指针x指向地址的值进行一次自增操作
}

int main() {
    int a = 10;
    increment(&a);//传递地址
    cout << a << endl; // 输出11
    return 0;
}

将a的地址作为实参传递给increment函数,使用指针来访问和修改a的值。由于这次修改是直接对原变量进行的,所以原变量a也被修改了。最后输出a的值为11。

三、指针易错点

3.1 未初始化的指针

如果声明了一个指针变量但没有将其初始化,那么它将存储一个随机值。当试图访问或修改这个随机地址上的值,程序可能会崩溃。

int *p; // 未初始化
cout << *p << endl; // 错误:试图访问随机地址上的值

3.2 空指针

空指针是一个特殊的指针,它不指向任何有效地址。试图访问或修改空指针所指向的值,程序会崩溃。

int *p = nullptr; // 空指针
cout << *p << endl; // 错误:试图访问空地址上的值

3.3 悬空指针

悬空指针是一个曾经有效但现在已经无效的指针。例如,如果一个局部变量离开了它所在的作用域,那么它所占用的内存空间将被释放。如果此时还有一个指针仍然指向这个局部变量,那么这个指针就成为了悬空指针。访问或修改悬空指针所指向的值,程序会崩溃。

int *p;
{
    int x = 10;
    p = &x;
}
cout << *p << endl; // 错误:悬空指针

3.4 野指针

野指针是一个未被正确初始化或已经释放但未被置为nullptr的指针。野指针可能会导致程序崩溃或数据丢失。

为了避免野指针,应该在声明指针变量时就将其初始化,并在释放内存后将其置为nullptr

int *p = new int(10); // 初始化
delete p; // 释放内存
p = nullptr; // 置为nullptr

四、浅谈指针意义

跟其他语言相比,指针是c/c++里的一大特色也是一大难点。指针赋予了c++能直接访问和修改内存地址的强大能力,例如:
①能够在运行时动态分配内存,让程序员根据程序的需要来创建新的变量,而不需要在编译时就确定它们的数量和大小,在不需要时使用delete释放内存即可;
②能够通过函数的地址传递直接修改传入参数的值;
③虽然指针本身会占用一定的内存空间,但是使用指针可以更加高效地管理内存,避免不必要的数据拷贝,提高程序的运行效率。
④使用指针可以更加高效的实现数据结构,如链表、树、图等。
尽管指针提供了强大的作用,但是直接操作内存带来的风险也是不容忽视的,稍加不慎就会造成程序崩溃。指针是一个比较抽象的概念,需要程序员对计算机内存模型有一定的了解,在本文第三部分中已对常见易错点进行了整理。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值