可爱的指针(一)

可爱的指针(一)

基本介绍

在互联网时代,几乎人人都会使用互联网来浏览信息。自互联网2.0以后,网页也变得越来越丰富。一个网页可以包含各种形式的信息,比如文字、图片、视频等。网页及其中的图片、视频都可以通过网址来获得。比如链接https://www.nasa.gov/sites/default/files/styles/full_width_feature/public/thumbnails/image/potw2045a.jpg对应一张NASA的星云图。
[图片上传失败...(image-f2f3ba-1605971654846)]
给定一个链接(或者称之为地址),浏览器会根据地址向对应的服务器获取图片(内容)。指针也是类似的概念。我们可以把网络地址看成指向网络资源的指针。

在计算机内存中,每一个资源都对应了一个地址。每当我们用程序语言定义一个变量,计算机都会在内存中开辟一个特定大小的存储空间,用来存储对应变量的值。
[图片上传失败...(image-57e600-1605971654846)]
每一个变量都有三个要素:(1)变量名,(2)变量的地址,(3)变量的值。在上面的图中,变量c的地址为0x0012FF74,变量c的值为76。不难发现,变量和上面例子当中的NASA星云图是很像的。和指向星云图的指针(网址)类似,我们可以把某个变量的地址称为指向该变量的指针。

有趣的是,计算机是可以通过变量的地址(指针)访问或改变变量的内容。抛开指针,我们可以通过cout<<c<<endl;来打印变量c的值。在使用指针来打印变量之前,我们首先需要获得变量的指针(地址)。C++语言中,可以通过&c获得变量c的地址(指针)。如果我们想把&c存放在一个变量里,我们就需要定义一个指针变量 int* pointerpointer作为指针变量,它是用来存储指针的,pointer本身作为一个变量,也有一个对应的地址,这个地址和它本身存储的地址是不同的)。pointer = &c称作指向变量c的指针。

int c = 76; //定义int类型变量c,并赋值76
int *pointer; //定义名字为pointer的指针变量,*表示pointer类型为指针类型
pointer = &c; //将变量c的地址赋值给指针变量pointer

这里,int *中的int称为指针类型的基类型,基类型可以帮助程序确定指针指向的变量在内存中所占空间的大小。

有了指针变量之后,如何通过指针变量访问指针变量指向的变量内容呢?(如何利用pointer访问变量c的值76呢?)可以使用指针运算符*实现。使用*pointer,我们可以获得pointer所指向的存储单元的内容。这里,pointer所指向的存储单元的内容是变量c(注意,内容是变量c而不是76,因为我们可以实现操作*pointer = 72其含义等于c = 72)。

Example 1:

void main(){
  int c;
  int *pointer;
  c = 76;
  pointer = &c;
  cout<<*pointer<<endl;
}

这里,cout<<*pointer<<endl;相当于cout<<c<<endl;所以结果打印出76。注意,在使用指针变量时,一定要先对其进行赋值,然后才能使用指针变量访问或者改变指向变量的值。

Example 2:

void main(){
  int akey = 0,b = 0;
  int *p = NULL, *q = NULL;
  akey = 66;
  p = &akey;
  q = &b;
  *q = *p;
  cout<<"b = "<<b<<endl;
  cout<<"*q = "<<*q<<endl;
}

这个结果会打印出

b = 66
*q = 66

程序的逻辑很简单,最关键的一行就是*q = *p;。可以把这一行理解为b = akey;,即把akey的值赋值给b

Example 3:

void main(){
  int *p1, *p2, *p;
  int a,b;
  cin>>a>>b;
  p1 = &a; p2 = &b;
  if (a < b){
    p = p1;
    p1 = p2;
    p2 = p;
  }
  cout<<"a = "<<a<<", b = "<<b<<endl;
  cout<<"max = "<<*p1<<", min = "<<*p2<<endl;
}

这里,我们输入3 5,会打印出

a = 3, b = 5
max = 5, min = 3

这个程序的核心逻辑在如果a < b,则将小数a的指针p1和大数b的指针p2交换。交换后,p1会指向大数,p2会指向小数。(注意,只是交换了指针,并未交换指针所指向的内容。)

Discussion of *&a

定义整型变量a:int a = 3;&a代表我把它取得整型变量a的地址;*&a表示取地址&a处相应的内容(变量a);所以,*&a等价于a

Discussion of &*pointer

定义整型变量a:int a = 3;并且定义一个指向变量a的指针变量pointerint *pointer = &a;*pointer等价于整型变量a&*pointer等价于&a(*pointer)++等价于a++

Discussion of iPtr++

假设iPtr所代表的地址是0x00000100
iPtr指向一个整型元素(占4字节),则iPtr++等于iPtr+1*4=0x00000104
iPtr指向一个实型元素(占4字节),则iPtr++等于iPtr+1*4=0x00000104
iPtr指向一个字符元素(占1字节),则iPtr++等于iPtr+1*1=0x00000101

指针与数组

指向数组元素的指针的定义、赋值、使用与基本变量完全相同。我们可以看如下的例子:

Example 4

void main(){
  int a[5] = {1,2,3,4,5};
  int *p = &a[3];
  cout<<*p<<endl;
  *p = 100;
  cout<<a[3]<<endl;
}

程序的的核心在int *p = &a[3];*p = 100;。这里,*p = 100;相当于a[3] = 100;。所以打印出:

4
100

以上是指向数组元素的指针的使用,而我们需要关注的是指向数组的指针。

在C++中,数组名代表数组首元素的地址。定义int a[10],则数组名a代表数组a[10]中第一个元素a[0]的地址;即a&a[0]等价;若有int *p,则p = &a[0]p = a等价。(注意,a是地址常量,不能给a赋值)

在定义int a[10]存放10个int类型的连续空间之后,我们可以使用a + n来获得数组a中第n+1个元素的地址。(a+1是数组a[10]中第二个元素a[1]的地址。)同时,指向数组元素的指针可以用做下标:[]*的作用相同,比如p[i]*(p+i)等价。(使用*(p+i)要注意数组下标越界的情况!)

Discussion

如果定义int a[5] = {1,2,3,4,5}; int *p;,假设当前i=3, a[4] = 4,则t = *p--相当于t = a[i--],先做*p运算。

  • *++p相当于a[++i],先将p自加,然后再做*运算;
  • *--p相当于a[--i],先将p自减,然后再做*运算;
  • *p++相当于a[i++],先做*运算,在做p自加;
  • *p--相当于a[i--],先做*运算,在做p自减;

Example 5

利用指针实现数组a的输入和输出:

int main(){
  int *p, i, a[10];
  p = a;
  for(i = 0; i < 10; i++)
    cin>>*p++;
  p = a;
  for(i = 0; i < 10; i++)
    cout<<*p++;
  return 0;
}

输入1 2 3 4 5 6 7 8 9 10
输出1 2 3 4 5 6 7 8 9 10

Example 6

void main(){
 int a[5] = {1,2,3,4,5};
 int *p = &a[3];
 *p = 100;
 cout<<*p++<<endl;
 cout<<*p--<<endl;
 cout<<*--p<<endl;
}

这个例子主要看*操作和++或者--的优先级。*p++表明先计算*p,之后再p++,此时输出100*p等价于a[4];*p--先输出a[4]的值:5,再自减,此时*p等价于a[3]*--p首先执行--p,此时*p等价于a[2],再输出a[2]的值:3。故最后的输出为

100
5
3

以上是指针和一维数组之间的一些问题。下一篇将会简单介绍指针和二维数组之间的一些操作。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容