美文网首页
可爱的指针(二)

可爱的指针(二)

作者: SeanC52111 | 来源:发表于2020-11-22 22:02 被阅读0次

可爱的指针(二)

在上一篇可爱的指针(一)中,我们了解了指针的基本内容。在这一篇中,我们主要了解指针与字符串、二维数组之间的操作。

字符串和指针

在具体讲字符串和指针之间的操作以前,我们首先回顾一下字符串。在C\C++中(抛开字符串string类),字符串是结尾为\0的一个字符数组。比如,我们可以用一下几个方式定义并初始化字符串:

char A[8] = "Beijing";
char B[] = "Beijing";
char c[10] = "include"; //虽然定义了长度为10的字符数组,但实际上最后3位均为‘\0’

分析以下程序:

#include<iostream>
using namespace std;
int main(){
  char h[] = "Peking";
  h[0] = 'a'; h[1] = 'b';
  h[2] = 'c'; h[3] = '7';
  h[4] = 'c';
  cout<<h<<endl;
  return 0;
}

此程序的逻辑不难,主要的核心就是替换h[0]h[4]最后程序会打印出abc7cg。有意思的地方在cout<<h<<endl;。之前我们提到数组名字等价于指向这个数组的指针(数组第一个元素的地址),但是使用cout语句却没有打印出地址,而是字符串的内容(直到找到\0)。这就是cout对字符数组特殊的处理

简单介绍过字符串之后,我们来看看指向字符串的指针。其实和常规数组的指针一样,指向字符串的指针变量可以这样定义:char a[10]; char *p; p = a;

Example 1

int main(){
  char a[] = "How are you?", b[20];
  char *p1, *p2;
  for(p1 = a, p2 = b; *p1 != '\0'; p1++, p2++)
    *p2 = *p1;
  *p2 = '\0';
  cout<<"string a is: "<<a<<endl;
  cout<<"string b is: "<<b<<endl;
  return 0;
}

这个程序的核心在*p2 = *p1;,即把所有a字符串的内容赋值给b。所以程序会打印出:

string a is: How are you?
string b is: How are you?

Example 2

int main(){
  char buffer[10] = "ABC";
  char *pc;
  pc = "hello";
  cout<<pc<<endl;
  pc++;
  cout<<pc<<endl;
  cout<<*pc<<endl;
  pc = buffer;
  cout<<pc<<endl;
  return 0;
}

这段程序主要考察使用cout输出指向字符串的指针。cout<<pc<<endl;可以直接打印出hello,在pc++之后,指针指向字符'e',所以再打印pc会输出ello。对于cout<<*pc<<endl;,只会打印单独的字符e,因为*pc此时等价于hello中第二个字符(数组的名字是指向数组的第一个元素的指针,在pc自增后,指向第二个元素)。pc = buffer;意味着我们可以将另一个字符串指针赋值给pc,因为pc是指针变量,可以进行更新。综上,程序的运行结果是:

hello
ello
e
ABC

二维数组与指针

之前我们提到的指针与数组(无论是普通数组还是字符数组),都是考虑的一维的情况。在指针指向一维数组的情况时,指向数组的指针等价于指向数组第一个元素的指针。当指针指向二维数组时,这个规律依旧成立。我们先回顾一下二维数组的相关概念。

  • 定义二维数组:int a[3][4],表示定义了三个存放a[4]型数据的存储单元。他们的名字分别为a[0], a[1], a[2]
  • 二维数组a[3][4]包含三个元素:a[0], a[1], a[2]。每个元素都是一个“包含四个整型元素”的数组。

[图片上传失败...(image-66b17d-1606053716702)]
这里,二维数组a[3][4]中的a代表指向第一个元素a[0]的指针(注意这里的表述,虽然指向a[0]的指针和指向a[0][0]的指针的值是相同的,但如果把这两个指针分别加一,指针变量的变化是不一样的)。

总结一下,定义一个二维数组:int a[3][4] = {{1,3,5,7}, {9,11,13,15}, {17,19,21,23}};

  • 由对一维数组的分析可知:数组名是指向数组第一个元素的指针。
  • 且二维数组的第一个元素是a[0]a[0]是一个包含四个整型元素的一维数组)。
  • 则可以做出判断:(1)a&a[0]等价;a[0]&a[0][0]等价;(2)a[0]*a等价;a[0][0]**a等价

乍一看可能有些晕。没关系,我们先看一下一维数组的情况,然后通过一维数组扩展到二维数组。
给定一个一维数组int a[4] = {1,3,5,7};

  • a是指向数组第一个元素的指针,即a等价于&a[0]。如果我们将a自加1,则a会指向a[1],跨越4字节。
  • *a是数组的第一个元素a[0],即*a等价于a[0]。这里我们可以看出*a相当于“下沉”了一级。
  • &a是指向数组的指针,&a+1将跨越16字节。所以,&a相当于“上浮”了一级。

Example 3

#include<iostream.h>
void main(){
  int a[4] = {1,3,5,7};
  cout<<"a = "<<a<<endl;
  cout<<"&a[0] = "<<&a[0]<<endl;
  cout<<"a+1 = "<<a+1<<endl;
  cout<<"&a[0]+1 = "<<&a[0]+1<<endl;
  cout<<"&a = "<<&a<<endl;
  cout<<"&a+1 = "<<&a+1<<endl;
}

这个程序的运行结果是:

a = 0x7fffd5f41480
&a[0] = 0x7fffd5f41480
a+1 = 0x7fffd5f41484
&a[0]+1 = 0x7fffd5f41484
&a[1] = 0x7fffd5f41484
&a = 0x7fffd5f41480
&a+1 = 0x7fffd5f41490

原因如下:

  • 因为a是指向数组第一个元素的指针常量,所以a&a[0]等价,故第一行和第二行打印的值相同。
  • 第三、第四、第五行打印的值相同,因为a+1为指向数组第二个元素的指针,和&a[0]+1&a[1]等价。
  • &a相当于“上浮”了一级。虽然&a的值与a&a[0]相同,但&a+1会从a跨越16个字节,所以&a+1a16

Example 4

#include<iostream.h>
void main(){
   int a[3][4] = {{1,3,5,7}, {9,11,13,15}, {17,19,21,23}};
   cout<<"a="<<a<<endl;
   cout<<"&a[0]="<<&a[0]<<endl<<endl;

   cout<<"a+1="<<a+1<<endl;
   cout<<"&a[0]+1="<<&a[0]+1<<endl;
   cout<<"&a[1]+1="<<&a[1]+1<<endl<<endl;
   cout<<"*a="<<*a<<endl;
   cout<<"a[0]="<<a[0]<<endl;
   cout<<"&a[0][0]="<<&a[0][0]<<endl<<endl;

   cout<<"*a+1="<<*a+1<<endl;
   cout<<"a[0]+1="<<a[0]+1<<endl;
   cout<<"&a[0][0]+1="<<&a[0][0]+1<<endl<<endl;

   cout<<"a[1]="<<a[1]<<endl;
   cout<<"*(a+1)="<<*(a+1)<<endl;
   cout<<"a[1]+1="<<a[1]+1<<endl;
   cout<<"*(a+1)+1="<<*(a+1)+1<<endl<<endl;

   cout<<"&a="<<&a<<endl;
   cout<<"&a+1="<<&a+1<<endl;
}

这个程序的输出结果如下:

a=0x7fffca660460
&a[0]=0x7fffca660460

a+1=0x7fffca660470
&a[0]+1=0x7fffca660470
&a[1]+1=0x7fffca660480

*a=0x7fffca660460
a[0]=0x7fffca660460
&a[0][0]=0x7fffca660460

*a+1=0x7fffca660464
a[0]+1=0x7fffca660464
&a[0][0]+1=0x7fffca660464

a[1]=0x7fffca660470
*(a+1)=0x7fffca660470
a[1]+1=0x7fffca660474
*(a+1)+1=0x7fffca660474

&a=0x7fffca660460
&a+1=0x7fffca660490

有了一维数组的结果做铺垫,二维数组的例子就更好理解了。

  • a&a[0]等价。
  • 由于a为指向数组第一个元素的指针,并且数组第一个元素占16字节,所以a+1&a[0]+1等价,比a16字节。&a[1]+1同理。
  • 由于*a下沉了一级,所以*a代表a[0]a[0]等价于&a[0][0]*a+1等价于a[0]+1(比a[0]的地址大4字节,只跨越了1个数)。&a[0][0]+1等价于a[0]+1
  • *(a+1)下沉一级,所以等价于a[1]a[1]+1a[1]4字节,因为此时级别在a[1]这个数组,自增1只会跨越1个数。*(a+1)+1a[1]+1等价。
  • &a上浮一级,所以&a+1会跨越整个二维数组,比&a12*4=48个字节。

Example 5

利用指针变量引用多维数组中的数组

  • 输入i,j; 输出a[i][j]
void main(){
  int a[3][4] = {1,3,5,7,9,11,13,15,17,19,21,23};
  int (*p)[4], i,j;
  p = a;
  cin>>i>>j;
  cout<<setw(4)<<*(*(p+i)+j);
}

这段程序主要是要关注int (*p)[4];的定义。这里,p是一个指向有四个元素的数组的指针。*(p+i)等价于a[i]*(p+i)+j等价于a[i]+j,即&a[i][j]。再在最前面加上**(*(p+i)+j)a[i][j]

指针数组

数组中各个数组元素均为指针类型的数据,组成的数组就是指针数组。int *pointer[10];
指针数组最频繁的用途就是存放很多字符串,比如下面这个例子:

Example 6

void main(){
   char *name[] = {"Follow me", "BASIC", "Great Wall", "FORTRAN", "Computer Design"};
   char **p = name;
   for(;p<name+5;p++){
      cout<<*p<<endl;
   }
}

这里,char *name[]就是一个指针数组。

指向指针的指针

前面提到我们可以用指针变量来存放地址,每一个变量也是对应一个地址。所以一定存在一个指针,它指向一个指针变量,我们可以把它看成指向指针的指针。在Example 6中,char *name是一个指针数组,它的每一个元素都是一个指针。如果我们想通过一个指针来访问每一个指针数组的元素,我们可以使用指向指针的指针char **p=name;。这里,p指向指针数组的第一个元素(为“Follow me”的指针)。

相关文章

  • 可爱的指针(二)

    可爱的指针(二) 在上一篇可爱的指针(一)中,我们了解了指针的基本内容。在这一篇中,我们主要了解指针与字符串、二维...

  • 可爱的指针(一)

    可爱的指针(一) 基本介绍 在互联网时代,几乎人人都会使用互联网来浏览信息。自互联网2.0以后,网页也变得越来越丰...

  • 指针

    一. 指针指向的是对象的地址//函数指针:指针指向函数//指针函数:函数返回指针 二.

  • 学习笔记3(指针运算,函数参数与指针,数组指针,二级指针)

    一、指针运算 二、数组与指针 三、指针和函数参数 java中: C/C++中: 四、指针数组 五、 二级指针 六、...

  • ndk02_指针运算,函数参数与指针,数组指针,二级指针

    一、指针运算 二、数组与指针 三、指针和函数参数 四、指针数组 五、 二级指针 六、知识要点 1、C语言中的函数如...

  • 二级指针

    关于二级指针,可以参考这篇文章[二级指针的作用详解] 所谓二级指针可以理解为:指向指针的指针函数通常会将参数拷贝一...

  • C语言的数组指针与指针数组(One)

    一、数组指针与指针数组: 数组指针<——>本质是指针 指针数组<——>本质是数组上图: 二、数组指针: int ...

  • 函数指针

    一.函数指针,指针指向函数 二.函数指针做参数

  • 02-C语言的指针

    02-C语言的指针 目标 C语言指针释义 指针用法 指针与数组 指针与函数的参数 二级指针 函数指针 指针在C中很...

  • C进阶3:二维指针

    1. 什么是二维指针 二维指针与一维指针一样都是保存地址的变量。 示例1 一维指针存放变量地址,二维指针存放一维指...

网友评论

      本文标题:可爱的指针(二)

      本文链接:https://www.haomeiwen.com/subject/fnupiktx.html