C++指针基础



提示:以下是本篇文章正文内容,下面案例可供参考

一、指针的声明和初始化

1.间接引用

指针变量把内存地址作为它们的值。通常,一个变量直接包含一个特定的值。但是,一个指针包含的是一个变量的内存地址,而该变量包含了一个特定的值。因此从这个意义上来讲,一个变量名直接引用一个值,而一个指针间接引用一个值,如图所示。通过指针引用值称为间接引用。请注意,在图中通常把指针表示为从一个变量指向另一个变量的箭头,前一变量包含一个地址值,后一变量则是在内存中位于该地址的变量。
直接引用和间接引用

2.指针的声明

和任何其他变量一样,指针在使用前必须声明。

int *ptr;

声明了变量ptr是 int *类型的(即一个指向int值的指针),读作“ ptr 是一个指向 int 的指针"。每一个声明为指针的变量在变量名前面必须有一个星号(*)。指针可以被声明为指向任何数据类型的对象。

3.指针的初始化

指针在声明或赋值时,应该被初始化为nullptr,或者一个相应类型的地址。一个值为nullptr的指针“指向空”,被称为空指针。当我们提到空指针时,就是指一个值为nullptr的指针。

二、指针运算符

1.地址运算符 &

地址运算符&是一个一元运算符,它获得操作数的内存地址。

int y = 5;
int *yptr = &a;

请注意,上述赋值语句中“&”的用法和引用变量声明中“&”的用法是不一样的,后者的前面总是有一个数据类型名。在声明一个引用时,&是类型的一部分。在像 &a 的表达式中, & 是地址运算符。

2.间接运算符 *

一元的 * 运算符通常称为间接运算符或间接引用( dereference)运算符,它返回的是一个左值,表示其指针操作数所指向的对象。如下语句:

cout << *yptr;

显示变量 y 的值,即5,和下面语句

cout << y;

是一样的

提示:间接引用一个未被初始化或空的指针会导致不确定的行为,可能造成致命的运行时错误。这也可能引起对重要数据的意外修改,导致程序运行结束后可能得到错误结果。

三、使用指针的按引用传递方式

C++中有三种向函数传递参数的方法——按值传递使用引用参数的按引用传递使用指针参数的按引用传递
引用参数也可以使程序向函数传递大型的数据对象,而避免按值传递对象所需要的开销(也就是需要复制对象的开销)。和引用一样,指针也可用于修改调用者中的一个或多个变量,或者可以将指向大型数据对象的指针传递给函数,从而避免按值传递对象所需要的开销。
在C++中,程序员可以用指针和间接引用运算符(*)来完成按引用传递。当调用具有必须要修改的实参的函数时,就传递该实参的地址。通常这是通过在值需要修改的变量的名字前应用地址运算符(&)来实现的。

四、const指针

1. 指向非const数据的非const 指针

指向非const数据的非const 指针具有最大的访问权限——可以通过间接引用指针修改数据,也可以修改指针使其指向其他数据。声明一个指向非const数据的非const 指针(例如 int * countPr)并不包含const修饰符。

2. 指向const 数据的非const 指针

指向const 数据的非const 指针可以被修改以指向任何适当类型的其他数据项,但是不能通过该指针来修改它所指向的数据。可以用这种指针为函数接收内置数组实参,函数通过它可以读取数组的元素,但不允许修改它们。企图用这个指针去修改函数中数据的任何尝试,都会产生编译错误。声明这样形式的指针是在指针的类型左边加一个const,例如:
const int * countPtr;
使用指向const数据的指针或者const 数据的引用来传递大型对象,可以获得按值传递的安全性。

3. 指向非const 数据的const 指针

指向非const 数据的const 指针始终指向同一个内存位置,通过该指针可以修改这个位置上的数据。声明为const 的指针必须在它们被声明的时候进行初始化,但如果这样的指针是函数的形参,那么就用传递给函数的指针来初始化它。

4. 指向const数据的const 指针

指向const 数据的const 指针具有最小的访问权限。这种指针总是指向内存中相同的位置,并且不能用该指针修改这个内存位置的数据。如果函数接收一个内置数组作实参,只是用数组下标表示法读取内置数组而不修改内置数组,那么应该用这样的指针作形参。

四、指针表达式和指针算术运算

指针算术运算只适用于指向内置数组元素的指针。一个指针可以自增(++)或自减(–),可以加上(+或+= )一个整数,可以减去(-或-= )一个整数,或者一个指针可以减去另一个同类型的指针,后者这一特殊的运算只适用于指向同一内置数组元素的两个指针

假设已声明了内置数组int v[5],并且它的第一个元素在内存位置3000处。又假设指针vPtr已初始化指向v[0](即 vPtr的值是3000)。对一个用4字节存储整数的机器。请注意,可以用下面任何一条语句把vPtr 初始化为指向数组v(因为内置数组的名字的值就是其第0元素的地址):
int *vPtr = v;
int *vPtr = &v[ 0 ];

内置数组v和指向它的指针变量int*vPtr

1.指针加上和减去整数

在常规的算术运算中,加法 3000 +2得到值3002。然而,对于指针算术运算而言一般不是这样的。当一个指针加上或减去一个整数时,它不是简单地加上或减去这个整数,而是加上或减去这个整数与该指针指向对象的字节大小的乘积。字节数取决于对象的数据类型。例如,下面的语句
vPtr += 2;
会得到3008(由计算3000+2×4而来,假设存储一个int数据需要4字节的内存)
此时,在内置数组v中,vPtr指向v[2]
指针算术运算之后的指针vPtr
++vptr;
vptr–;
是将指针加1或减1,使它指向内置数组的下一个或前一个元素。

指针的算术运算是没有边界检查功能的。程序员必须确保每一个指针算术运算,即加上一个整数或减一个整数,产生的结果指针所指向的元素必须在内置数组的边界内。

2.指针相减、指针比较

指向同一个内置数组的指针变量可以相减。例如,如果vPtr包含地址3000,v2Ptr包含地址3008,那么下述语句
×= v2Ptr - vPtr;
将把从vPir到v2Ptr的内置数组元素的个数赋值给x,在这里为2。指针算术运算只有在指向内置数组的指针上进行时才有意义。我们无法假设相同类型的两个变量会连续地存储在内存中,除非它们是一个数组的相邻元素。
指针可以使用相等和关系运算符进行比较。只有在指针指向同一数组的元素时,使用关系运算符对它们进行比较才是有意义的。指针比较是比较存储在指针中的地址。例如,比较指向同一数组的两个指针可以发现,指向内置数组中下标编号大一些的元素的指针比另一个指向下标编号小一些的元素的指针大。一个常用的指针比较是判定一个指针的值是否为nullptr、0或者NULL(即没有任何所指的指针)。

3.指针赋值

如果两个指针是同一类型的,那么可以把一个指针赋值给另一个指针。否则,必须用强制类型转换运算符,将赋值运算符右侧的指针值转换为赋值运算符左侧的指针类型。这个规则有一个例外,就是void指针(即void *),它是一种通用指针,可以表示任何指针类型。任何指向基本类型或类类型的指针都可以被赋值给void *类型的指针,而不需要进行强制的类型转换。但是,void *类型的指针是不可以直接赋值给其他类型的指针的,必须先把void *类型的指针强制转换为适合的指针类型。

五、指针和内置数组之间的关系

在C++中,内置数组和指针是密切相关的,两者几乎可以交换使用。可以用指针进行任何涉及数组下标的操作。
假设有如下的声明:
int b[ 5 ];
int *bPtr;
我们可以用下面的语句把bPtr设置为内置数组b中第一个元素的地址:
bPtr = b;
这完全等同于如下的将内置数组第一个元素的地址赋值给bPtr的方式:
bPtr = &b[ 0 ];

1.指针/偏移量表示法

引用内置数组元素b[3]的另一种方法是采用下面的指针表达式:
(bPtr +3)
该表达式中的3是距离指针bPtr的偏移量( offset)。当该指针指向内置数组的首元素时,偏移量表示应该引用内置数组的哪个元素,并且偏移量的值和该内置数组元素的下标是相同的。这种表示法称为指针/偏移量表示法。因为
的优先级比+的优先级高,所以圆括号是必需的。如果没有圆括号,上面的表达式将加3到* bPtr的值(即3会被加到b[0],假设bPtr指向内置数组的起始元素)。
正像内置数组元素可以用指针表达式引用一样,下面的地址
&b[ 3]
能够写成如下的指针表达式形式:
bPtr + 3

六、基于指针的字符串

1.字符串

一个字符串是一个被视为整体的字符序列。字符串可以包含字母、数字和各种特殊字符,例如+,-、*、/和$等。在C++中,字符串文字( String literal)或字符串常量都写在一对双引号中,如下所示:
“hello,world”

2.基于指针的字符串

基于指针的字符串是一个以空字符(‘0’)结尾的内置字符数组,这个空字符标记了字符串在内存中结束的位置。通过指向字符串第一个字符的指针来访问该字符串。对一个字符串文字进行sizeof运算得到的是包含结束的空字符在内的这个字符串的长度。基于指针的字符串和内置数组一样,内置数组名也是指向该内置数组第一个元素的指针。

3.字符串文字左为初始化值

无论是在内置字符数组的声明中,还是在const char*类型的变量的声明中,都可以将字符串文字作为初始化值。下列声明
char color[] =“blue”;
const char *colorPtr = “b1ue”;
都把变量初始化为字符串“blue”。第一个声明创建了一个具有5个元素的内置数组color,它包含字符‘b’、‘l’、‘u’、‘e’和‘\0’。第二个声明创建了指针变量colorPtr,它指向在内存某处的字符串“ blue”(以‘\0’结尾)中的字母b。字符串文字是static存储类别的(它们在程序执行时间内一直存在),如果程序中有多个地方引用同一个字符串文字,那么它可以被共享,也可以不被共享。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++指针是一种非常重要的概念,它是一种用于存储内存地址的变量类型,可以用于直接访问内存中的数据。指针的基本概念需要理解以下几个方面: 1. 指针的定义和声明:指针的定义需要指定指针的类型,它可以指向任何数据类型,包括整数、字符、浮点数、结构体等。例如,int *p; 声明了一个指向整数类型的指针变量p。 2. 指针的赋值:指针变量可以通过赋值来指向某个变量的地址,例如,int a = 10; int *p = &a; 将指针变量p指向变量a的地址。 3. 指针的解引用:指针变量可以通过解引用(*)操作符来访问它所指向的变量的值,例如,*p = 20; 修改了指针变量p所指向的变量a的值。 4. 指针的算术运算:指针变量可以进行加、减等算术运算,例如,p++; 将指针变量p指向下一个整数类型的地址。 5. 指针和数组:数组名本质上是一个指向数组首元素的指针,可以通过指针和数组名来访问数组中的元素,例如,int a[5] = {1, 2, 3, 4, 5}; int *p = a; cout << *p << endl; 输出数组a的第一个元素1。 6. 指针和函数:指针可以作为函数的参数来传递变量的地址,从而在函数内部对变量进行修改,例如,void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } 可以通过调用swap(&a, &b)来交换a和b的值。 需要注意的是,指针在使用时需要注意指针变量的值是否为空,避免出现野指针的情况,同时需要注意指针变量的生命周期,避免指针变量指向的内存已经被释放的情况。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值