指针与数组的关系
指向数组的指针变量称为数组指针变量。一个数组是一块连续的内存单元组成的,数组 名就是这块连续内存单元的首地址。一个数组元素的首地址就是指它所占有的几个内存单元的首地址。一个指针变量即可以指向一个数组,也可以指向一个数组元素,可把数组名或第 一个元素的地址赋予它。如要使指针变量指向第 i 号元素,可以把 i 元素的首地址赋予它,或把数组名加 i 赋予它。
设有数组 a,指向 a 的指针变量为 pa,则有以下关系:pa、a、&a[0]均指向同一单元, 是数组 a 的首地址,也是 0 号元素 a[0]的首地址。pa+1、a+1、&a[1]均指向 1 号元素 a[1]。 类推可知 pa+i、a+i、&a[i]指向 i 号元素 a[i]。pa 是变量,而 a,&a[i]是常量,在编程时 应予以注意。
指向数组的指针
数组指针变量说明的一般形式为: 类型说明符 *指针变量名
引入指针变量后,就可以用两种方法访问数组元素了, 例如定义了 int a[5];int *pa=a; 第一种方法为下标法,即用 pa[i]形式访问 a 的数组元素。 第二种方法为指针法,即采用*(pa+i)形式,用间接访问的方法来访问数组元素。
【例 5】scanf 使用数组名,用数组名或指针访问数组。
#include<stdio.h>
#include<iostream>
using namespace std;
int main()
{
int a[5],i,*pa=a;//定义整型数组和指针,*pa=a也可以在下一行pa=a
for(i=0;i<5;i++)
scanf("%d",a+i);//可写成pa+i和&a[i]
for(i=0;i<5;i++)
printf("a[%d]=%d\n",i,*(pa+i)); //指针访问数组,可写成*(pa+i)或pa[i]或a[i]
return 0;
} 输入:1 2 3 4 5
输出:a[0]=1
a[1]=2
a[2]=3
a[3]=4
a[4]=5
【说明】
①、直接拿 a 当指针用,a 指向数组的开始元素,a+i 是指向数组的第 i 个元素的指针。
②、指针变量 pa 是变量,可以变的。但数组 a 是静态的变量名,不可变,只能当做常 量指针使用。例如:p=p+2;是合法的,a=a+2;是非法的。
③、最早在使用标准输入 scanf 时就使用了指针技术,读入一个变量时要加取地址运算 符’&’传递给 scanf 一个指针。对于数组,可以直接用数组名当指针。
指针也可以看成数组名
指针可以动态申请空间,如果一次申请多个变量空间,系统给的地址是连续的,就可以当成数组使用,这就是传说中的动态数组的一种。
【例 6】动态数组,计算前缀和数组。b是数组 a 的前缀和的数组定义:b[i]=a[1]+a[2] +…+a[i],即b[i]是 a 的 i 个元素的和。
#include<cstdio>
using namespace std;
int n;
int *a;//定义指针变量a,后面直接当数组使用
int main()
{
scanf("%d",&n);
a=new int[n+1];//向操作系统申请了连续的n+1个int型的空间
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=2;i<=n;i++)
a[i]+=a[i-1];
for(int i=1;i<=n;i++)
printf("%d ",a[i]);
return 0;
} 输入:
5
1 2 3 4 5
输出:
1 3 6 10 15
【说明】
动态数组的优点:在 OI 中,对于大数据可能超空间的情况是比较纠结的事,用小数组 只的部分分,大数组可能爆空间(得 0 分)。使用“动态数组”,可以在确保小数据没问题的 前提下,尽量满足大数据的需求。
指针与字符串
字符串的表示形式 在 C++中,我们可以用两种方式访问字符串。
(1)用字符数组存放一个字符串,然后输出该字符串。
int main()
{
char str[]="I love China!";
printf("%s\n", str);
} (2)用字符指针指向一个字符串。可以不定义字符数组,而定义一个字符指针。用字符指针指向字符串中的字符。
int main()
{
char *str="I love China!";
printf("%s\n", str);
} 在这里,我们没有定义字符数组,而是在程序中定义了一个字符指针变量 str,用字符串常量"I love China!",对它进行初始化。C++对字符串常量是按字符数组处理的,在内存中开辟了一个字符数组用来才存放该字符串常量。对字符指针变量初始化,实际上是把字符串第 1 个元素的地址(即存放字符串的字符数组的首元素地址)赋给 str。有人认为 str 是 一个字符串变量,以为在定义时把"I love China!"这几个字符赋给该字符串变量,这是不 对的。
实际上,
char *str="I love China!"; 等价于:
char *str;
str="I love China!"; 可以看到,str被定义为一个指针变量,指向字符型数据,请注意它只是指向了一个字符变量或其他字符类型数据,不能同时指向多个字符数据,更不是把"I love China!"这些字符存放到 str 中(指针变量只能存放地址)。只是把"I love China!"的第一个字符的地址赋给指针变量 str。
在输出时,要用:
printf(“%s\n”, str);其中“%s”是输出字符串时所用的格式符,在输出项中给出字符指针变量名,则系统先输出它所指向的一个字符数据,然后自动是 str 加 1,使之指向下一个字符,然后再输出一 个字符……如此知道遇到字符串结束标志“\0”为止。
注意:可以通过字符数组名或者字符指针变量输出一个字符串。而对一个数值型数组,是不能企图用数组名输出它的全部元素的。 例如:
int i[10];
…… printf(”%d\n”, i);这样是不行的,只能逐个输出。显然 %s 可以对一个字符串进行整体的输入和输出。
字符串指针作函数参数
将一个字符串从一个函数传递到另外一个函数,可以用地址传递的方法,即用字符数组 名作参数或用指向字符的指针变量做参数。在被调用的函数中可以改变字符串内容,在主调 函数中可以得到改变了的字符串。
【例 8】输入一个长度最大为 100 的字符串,以字符数组的方式储存,再将字符串倒序储存, 输出倒序储存后的字符串。(这里以字符指针为函数参数)
#include<cstdio>
#include<cstring>
using namespace std;
void swapp(char &a,char &b)
{
char t;
t=a;a=b;b=t;
}
void work(char* str)
{
int len=strlen(str);//strlen(str)返回str的长度
//需要包含头文件cstring 函数原型是"size_t strlen(const char* str)"
for(int i=0;i<=len/2;++i)
swapp(str[i],str[len-i-1]);
}
int main()
{
char s[110];
char *str=s;
gets(s);
work(str);
printf("%s",s);
return 0;
} 输入:
!anihC evol I
输出:
I love China!