C/C++ 第七讲 指针和数组

7.1 指针的基本概念

概念

每个变量在内存中存放都对应一段地址,其中首字节即为变量的地址,将存放地址的变量称为指针变量。

&--取地址运算

&x--变量x的地址

如:

1
2
3
4
int x=4;
x的地址为1001
&x的值为1001
*(&x)的值为4

*--取内容运算

*(&x)代表到x存放的地址中取内容

b&b[0]同义。

指针变量的定义

数据类型 * 标识符;

  • “数据类型”代表指针所指向数据的类型
  • *不是变量名的一部分,仅仅是指针变量的一个标志。

例如:

int *p;,p指向可存放一个int型变量的地址

float *q;,q指向可存放一个float型变量的地址。

初始化

在定义指针变量的同时为其赋一个地址值。

int a=5, *p=&a 等价于 int a=5, *p; p=&a;

  • 注意:此处被赋值的是p,不是*p
  • p是指向变量a的指针变量,它会到a 的地址中取数据。
  • *(&a), *p皆代表a的值。(数据的间接访问)

常用运算

赋值运算

其他运算的前提。

1
2
3
4
5
6
7
int a, *p,*p1,*p2;
p=NULL;//指针被赋值为NULL(0),表示不指向任何对象
p=&a;//p指向变量a
p1=&a;
p2=p1;//同类型的指针变量相互赋值
p=new int;//动态为p分配存放一个整数的空间
p=new int[10];//动态为p分配存放10个整数的空间

假设有定义:

int a,*p;

float f;

需避免以下错误:

  • 随意将一个整数值赋值给指针变量;p=100
  • 为指针变量赋数据类型不一致的变量的地址;p=&f

加减整数的运算

假设p为指针变量,n为整数,

p+n(p-n) :指向p后面(前面)的第n个元素。

自加自减运算

p++p-- :指向p后面(前面)的一个元素。

指针相减运算

两个同类型指针变量相减的结果为这两个地址差之间能存放的数据个数。

如:

int *p1, *p2;

假设p1指向1000,p2指向1008,则p2-p1的值为:

(1008-1000)/sizeof(int)=2

  • sizeof() :求字节数运算
    • sizeof(int)=4
    • sizeof(char)=1
    • sizeof(float)=4
    • sizeof(double)=8

7.2 指针与一维数组的关系

设有定义:

int a[10], *p=a;

根据指针运算有如下等价关系:

  • p<=>a<=>&a[0]
  • p+i<=>a+i<=>&a[i]
  • *(p+i)<=>*(a+i)<=>a[i]

数组元素的表示

  1. 下标表示:数组名[下标]
  2. 地址方式:*(地址)
  3. 指针方式:*指针变量名
  • 指针与一维数组的关系
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
int main()
{
int a[10],i,*p=a;
for (i=0;i<5;i++)
cin>>*p++; //顺序从右向左;等价于cin>>*p; p++;
for (i=0;i<5;i++)
cout<<a[i]<<' ';
system("pause");
return 0;
}

说明:

  • p与a的区别:

    • p是地址变量,a是地址常量
  • *p++
    
    1
    2
    3



    (*p)++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
        
    的区别

    * `*p++`的`++`运算符作用于指针变量,该运算的作用相当于先取出\*p的内容作为表达式的值,然后p再指向下一个元素。
    * `(*p)++`的`++`运算符作用于指针变量所指内容,运算等价于先取出_p的内容作为表达式的值,然后_p的值再+1

    对比如下:

    ```cpp
    #include <iostream>
    using namespace std;
    int main()
    {
    int a[3]={10,20,30},*p;
    p=a;
    cout<<*p++<<endl; //先取p,再地址增加
    cout<<*p<<endl; //这时p地址已增加
    system("pause");
    return 0;
    }
    #include <iostream>
    using namespace std;
    int main()
    {
    int a[3]={10,20,30},*p;
    p=a;
    cout<<(*p)++<<endl; //先取p,再对p指向的数据增加
    cout<<*p<<endl; //这时10已增加为11
    system("pause");
    return 0;
    }
  • 指针和字符串

字符指针也可以处理字符串,其与字符数组处理的区别如下:

字符数组

字符指针

定义

char s[6];

char *p

初始化

chars[]=”china”;

char p=”china”; char *p=s;

赋值

s[0]=’c’; s[1]=’h’; cin>>s; gets(s);

p=”china”; 先p=new char[6];或p=s;之后再cin>>p;或gets(p);

运算

字符数组名s不能进行自增、自减运算

指针变量p可以进行自增、自减运算

例:输入一字符串,用指针方式逐一显示字符,并求其长度

要点:

  • 用字符指针处理字符串,在输入前要先为其申请存储空间;

  • 利用指针移动逐一访问数组元素时该指针最终指向’\0’;

  • 利用指向字符串尾部和头部的两个指针相减运算可以求得字符串长度。

  • 指针与一维数组的关系

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
int main()
{
int a[10],i,*p=a;
for (i=0;i<5;i++)
cin>>*p++; //顺序从右向左;等价于cin>>*p; p++;
for (i=0;i<5;i++)
cout<<a[i]<<' ';
system("pause");
return 0;
}

说明:

  • p与a的区别:

    • p是地址变量,a是地址常量
  • *p++
    
    1
    2
    3



    (*p)++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
        
    的区别

    * `*p++`的`++`运算符作用于指针变量,该运算的作用相当于先取出\*p的内容作为表达式的值,然后p再指向下一个元素。
    * `(*p)++`的`++`运算符作用于指针变量所指内容,运算等价于先取出_p的内容作为表达式的值,然后_p的值再+1

    对比如下:

    ```cpp
    #include <iostream>
    using namespace std;
    int main()
    {
    int a[3]={10,20,30},*p;
    p=a;
    cout<<*p++<<endl; //先取p,再地址增加
    cout<<*p<<endl; //这时p地址已增加
    system("pause");
    return 0;
    }
    #include <iostream>
    using namespace std;
    int main()
    {
    int a[3]={10,20,30},*p;
    p=a;
    cout<<(*p)++<<endl; //先取p,再对p指向的数据增加
    cout<<*p<<endl; //这时10已增加为11
    system("pause");
    return 0;
    }
  • 指针和字符串

字符指针也可以处理字符串,其与字符数组处理的区别如下:

字符数组

字符指针

定义

char s[6];

char *p

初始化

chars[]=”china”;

char p=”china”; char *p=s;

赋值

s[0]=’c’; s[1]=’h’; cin>>s; gets(s);

p=”china”; 先p=new char[6];或p=s;之后再cin>>p;或gets(p);

运算

字符数组名s不能进行自增、自减运算

指针变量p可以进行自增、自减运算

例:输入一字符串,用指针方式逐一显示字符,并求其长度

要点:

  • 用字符指针处理字符串,在输入前要先为其申请存储空间;
  • 利用指针移动逐一访问数组元素时该指针最终指向’\0’;
  • 利用指向字符串尾部和头部的两个指针相减运算可以求得字符串长度。
  • 指针与一维数组的关系
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
int main()
{
int a[10],i,*p=a;
for (i=0;i<5;i++)
cin>>*p++; //顺序从右向左;等价于cin>>*p; p++;
for (i=0;i<5;i++)
cout<<a[i]<<' ';
system("pause");
return 0;
}

说明:

  • p与a的区别:

    • p是地址变量,a是地址常量
  • *p++
    
    1
    2
    3



    (*p)++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
        
    的区别

    * `*p++`的`++`运算符作用于指针变量,该运算的作用相当于先取出\*p的内容作为表达式的值,然后p再指向下一个元素。
    * `(*p)++`的`++`运算符作用于指针变量所指内容,运算等价于先取出_p的内容作为表达式的值,然后_p的值再+1

    对比如下:

    ```cpp
    #include <iostream>
    using namespace std;
    int main()
    {
    int a[3]={10,20,30},*p;
    p=a;
    cout<<*p++<<endl; //先取p,再地址增加
    cout<<*p<<endl; //这时p地址已增加
    system("pause");
    return 0;
    }
    #include <iostream>
    using namespace std;
    int main()
    {
    int a[3]={10,20,30},*p;
    p=a;
    cout<<(*p)++<<endl; //先取p,再对p指向的数据增加
    cout<<*p<<endl; //这时10已增加为11
    system("pause");
    return 0;
    }
  • 指针和字符串

字符指针也可以处理字符串,其与字符数组处理的区别如下:

字符数组

字符指针

定义

char s[6];

char *p

初始化

chars[]=”china”;

char p=”china”; char *p=s;

赋值

s[0]=’c’; s[1]=’h’; cin>>s; gets(s);

p=”china”; 先p=new char[6];或p=s;之后再cin>>p;或gets(p);

运算

字符数组名s不能进行自增、自减运算

指针变量p可以进行自增、自减运算

例:输入一字符串,用指针方式逐一显示字符,并求其长度

要点:

  • 用字符指针处理字符串,在输入前要先为其申请存储空间;

  • 利用指针移动逐一访问数组元素时该指针最终指向’\0’;

  • 利用指向字符串尾部和头部的两个指针相减运算可以求得字符串长度。

  • 指针与一维数组的关系

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
int main()
{
int a[10],i,*p=a;
for (i=0;i<5;i++)
cin>>*p++; //顺序从右向左;等价于cin>>*p; p++;
for (i=0;i<5;i++)
cout<<a[i]<<' ';
system("pause");
return 0;
}

说明:

  • p与a的区别:

    • p是地址变量,a是地址常量
  • *p++
    
    1
    2
    3



    (*p)++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
        
    的区别

    * `*p++`的`++`运算符作用于指针变量,该运算的作用相当于先取出\*p的内容作为表达式的值,然后p再指向下一个元素。
    * `(*p)++`的`++`运算符作用于指针变量所指内容,运算等价于先取出_p的内容作为表达式的值,然后_p的值再+1

    对比如下:

    ```cpp
    #include <iostream>
    using namespace std;
    int main()
    {
    int a[3]={10,20,30},*p;
    p=a;
    cout<<*p++<<endl; //先取p,再地址增加
    cout<<*p<<endl; //这时p地址已增加
    system("pause");
    return 0;
    }
    #include <iostream>
    using namespace std;
    int main()
    {
    int a[3]={10,20,30},*p;
    p=a;
    cout<<(*p)++<<endl; //先取p,再对p指向的数据增加
    cout<<*p<<endl; //这时10已增加为11
    system("pause");
    return 0;
    }
  • 指针和字符串

字符指针也可以处理字符串,其与字符数组处理的区别如下:

字符数组

字符指针

定义

char s[6];

char *p

初始化

chars[]=”china”;

char p=”china”; char *p=s;

赋值

s[0]=’c’; s[1]=’h’; cin>>s; gets(s);

p=”china”; 先p=new char[6];或p=s;之后再cin>>p;或gets(p);

运算

字符数组名s不能进行自增、自减运算

指针变量p可以进行自增、自减运算

例:输入一字符串,用指针方式逐一显示字符,并求其长度

要点:

  • 用字符指针处理字符串,在输入前要先为其申请存储空间;

  • 利用指针移动逐一访问数组元素时该指针最终指向’\0’;

  • 利用指向字符串尾部和头部的两个指针相减运算可以求得字符串长度。

  • 指针与一维数组的关系

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
int main()
{
int a[10],i,*p=a;
for (i=0;i<5;i++)
cin>>*p++; //顺序从右向左;等价于cin>>*p; p++;
for (i=0;i<5;i++)
cout<<a[i]<<' ';
system("pause");
return 0;
}

说明:

  • p与a的区别:

    • p是地址变量,a是地址常量
  • *p++
    
    1
    2
    3



    (*p)++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
        
    的区别

    * `*p++`的`++`运算符作用于指针变量,该运算的作用相当于先取出\*p的内容作为表达式的值,然后p再指向下一个元素。
    * `(*p)++`的`++`运算符作用于指针变量所指内容,运算等价于先取出_p的内容作为表达式的值,然后_p的值再+1

    对比如下:

    ```cpp
    #include <iostream>
    using namespace std;
    int main()
    {
    int a[3]={10,20,30},*p;
    p=a;
    cout<<*p++<<endl; //先取p,再地址增加
    cout<<*p<<endl; //这时p地址已增加
    system("pause");
    return 0;
    }
    #include <iostream>
    using namespace std;
    int main()
    {
    int a[3]={10,20,30},*p;
    p=a;
    cout<<(*p)++<<endl; //先取p,再对p指向的数据增加
    cout<<*p<<endl; //这时10已增加为11
    system("pause");
    return 0;
    }
  • 指针和字符串

字符指针也可以处理字符串,其与字符数组处理的区别如下:

字符数组

字符指针

定义

char s[6];

char *p

初始化

chars[]=”china”;

char p=”china”; char *p=s;

赋值

s[0]=’c’; s[1]=’h’; cin>>s; gets(s);

p=”china”; 先p=new char[6];或p=s;之后再cin>>p;或gets(p);

运算

字符数组名s不能进行自增、自减运算

指针变量p可以进行自增、自减运算

例:输入一字符串,用指针方式逐一显示字符,并求其长度

要点:

  • 用字符指针处理字符串,在输入前要先为其申请存储空间;
  • 利用指针移动逐一访问数组元素时该指针最终指向’\0’;
  • 利用指向字符串尾部和头部的两个指针相减运算可以求得字符串长度。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;
int main()
{
char *p,*q;
p=new char[100]; //为p申请能存放100个字符的空间
gets(p);
q=p; //q记录字符串的首地址
cout<<"输出每个字符:";
while(*p!='\0')
cout<<*p++<<' '; //退出循环后p指向串尾
cout<<"\n字符串长度:"<<p-q<<endl;
system("pause");
return 0;
}

7.3 字符指针数组

1
char *book[]={"Fortran","C++","Pascal"}
1
2
3
4
5
6
7
8
9
#include <iostream>
using namespace std;
int main()
{
char *book[]={"Fortran","C++","Pascal"};

system("pause");
return 0;
}

7.4 子串统计

例:统计字符串s中子串sub出现的次数。

从s首个字符起取和sub子串等长的子串,与sub比较

1
2
3
4
5
6
7
8
#include 
#deefine N 100
using namespace std;
int main()
{
char s[N],sub[N],s2[N];
int i,j,count(0);
cout<<"输入字符串"<

`

数制转换

1
do {cin>>m>>r;} while{(r>=2)(r<=16)m<0}

例2

输入仅由数字和字母组成的字符串,利用指针对其再排列(字符在前,数字在后,内序不变)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include "iostream"
#define N 256
using namespace std;
int main()
{
char s[N],t[N],m[N],* p=s, *p1=t,*p2=m;
gets_s(s);
while (*p)
{
if ((*p >= 'a' && *p <= 'z') (*p >= 'A' && *p <= 'Z'))
{
*p1 = *p;
p1++;
}
else
{
*p2 = *p;
p2++;
}
p++;
}
*p1 = '\0';
*p2 = '\0';
strcat_s(t, m);
puts(t);
system("pause");
return 0;
}

`