目录:
3、数组与指针
4、指针的潜在危险
``
定义指针变量指向数组首元素,以指针变量名代替数组名,实现数组操作。(指针所指位置不变)
指针变量从前到后依次指向数组各元素,通过指针的取内容运算得到对应元素。(指针所指位置不断变化)
例:用下列数据初始化一维数组,并通过指针变量求元素的最大值。
8.2 6.5 3 9.7 12 2.8 7.6 15 10.3
定义实型指针p指向数组b的首元素,max 表示最大值;
以p 代替b,通过循环语句输出数组的各元素;
指针p 从第二个元素开始遍历数组,遍历过程中将比max 大的元素赋给max。
#include
using namespace std;
int main(void)
{
double b[]={8.2,6.5,3,9.7,12,2.8,7.6,15.6,10.3};
double *p=b,max=b[0]; //p指向b的首元素,b即&b[0]
cout<<"数组为:\n";
for(int i=0;i<9;i++)
{ // 输出数组
cout<max)max=*p; // *p是指针p所指元素的值
p++; // p 后移一个元素
}
cout<<"元素的最大值为:"<
l指针变量只能代表其所指向的数组。当指针不再指向数组的首元素时,不能代表原数组。
指向元素的指针简称元素指针。(指向元素)
二维数组元素指针与一维数组元素指针的定义方式相同,使用方法相似。如:
float b[3][4],*p; // 定义二维数组b 和元素指针p
p=&b[0][0]; // p指向二维数组首元素
行指针定义:
指向二维数组某行的指针简称行指针。(指向一行)
二维数组数组名b 是b[0]的地址(&b[0]),b[0]是二维数组的第一行,即b是指向二维数组第1行的行指针;且b[0]是由5 个元素组成的一维数组,故行指针也称为指向一维数组的指针。
数据类型 (*指针变量名)[二维数组列数];
数据类型与所指向的二维数组的数据类型相同;
下标为二维数组的列数,通常为整型常量表达式;
必须用“()”将指针变量名括起来。
如:
float (*p2)[5];
二维数组行地址、元素地址和元素之间的关系
对行地址进行取值运算可以得到元素地址;
对元素地址进行取值运算可得到二维数组的元素。
分类 | 表示方法 | 备注 |
---|---|---|
行指针 | p2+i,&p2[i] | 下标为i行的行地址 |
元素指针 | *(p2+i)+j,p2[i]+j | 下标为i行j列的元素地址 |
元素 | * (* (p2+i)+j),*(p2[i]+j),p2[i] [j] | 下标为i行j列的元素 |
将二维数组作为一个行数×列数的一维数组
定义元素指针指向二维数组的第一行第一列元素;
一维数组名为指针变量名;
一维数组大小为二维数组的行数×列数。
定义行指针指向二维数组的首行
行指针变量名代替二维数组名,实现二维数组的操作;
行指针取值运算得到元素地址,然后元素地址取值运算得到元素,完成对二维数组的操作。
注意元素指针与行指针使用的区别,指针所指的位置。
例:通过指针输出下列二维数组,并求各元素的和。
2 3 1 4 10
6 2 5 8 3
7 8 9 6 12
行指针p1:&b[0];p1+1:&b[1]
元素指针p2:&b[0] [0];p2+1:&b[0] [1]
#include
using namespace std;
int main(void)
{
int b[3][5]={{2,3,1,4,10},{6,2,5,8,3},{7,8,9,6,12}},sum=0;
int (*p1)[5]=b,*p2=&b[0][0],i,j;//p1=&b[0][0];p2=b; 语法错误
for(i=0;i<3;i++)
{ // 输出二维数组
for(j=0;j<5;j++)
cout<
字符型指针变量指向字符串
定义时用字符串对其初始化;
(1)用字符串对指针变量赋值。
如:
char *s1=" C++ Program",*s2;
s2=" This is a string.";
(2)直接引用字符型指针变量所指的字符数组
#include
#include
using namespace std;
int main(void) {
char *s1,*s2;
s2=" This is a string.";
char str[50],*s3=str;
cin.getline(s3,50); // 输入字符数组cin.getline(字符数组名,字符个数,结束标志)
cout<
结合前面讲过的二级指针,我们来看看使用的实例。
#include
#include
using namespace std;
int main()
{
char *name[3]={"China","Japan","England"};//name数组中的元素分别定义为指向三个字符串的指针
char **p; //name[0]:China,
for(int i=0;i<3;i++)
{
p=name+i;
cout<<"name["<
例:设计一个程序,将字符串中的字符逆序。如将“I am a student.”逆序为“.tneduts a ma I”。
数组str 存储字符串,指针s1 指向首元素,s2 指向尾元素。
当s1在s2前面时,将s1 和s2 所指的元素互换;然后s1 后移一个元素,s2 前移一个元素。
#include
#include
using namespace std;
int main(void) {
char str[100],*s1=str,*s2=str,t;
cout<<"请输入一个字符串:";
cin.getline(s1,100);
cout<<"输入的字符串是:";
cout<
指针使用数组
搞清指针所指位置
分清操作对象是指针本身还是指针所指内存空间
分清所使用的是元素指针还是行指针
充分理解指针的含义:地址;代表所指向的数组。
各元素为指针变量的数组。
普通数组中存储的是普通数据(数值),指针数组中存储的是地址。
定义:
存储类型 数据类型* 数组名[数组大小];
如:
float *p1[5];
#include
using namespace std;
int main(void) {
double d[4]={1.0,1.1,1.2,1.3};
double * p[4];
for(int i=0;i<4;i++)
p[i]=&d[i];
for(int i=0;i<4;i++)
cout<<*p[i]<<',';
return 0;
}
指针的让我们对内存的操作有了很大的自由性,同时也带来了潜在的危险。
1.定义指针变量的同时未对其进行初始化:指针在被定义的时候,如果程序不对其进行初始化的话,它会指向随机区域,因为任何指针变量(除了static修饰的指针变量)在被定义的时候是不会被置空的,它的默认值是随机的。
2.指针所指向的内存空间被释放时,却没有对该指针变量的值(即该指针原来指向的内存空间的地址)进行置空:我们在用库函数malloc开辟内存空间时,要检查返回值是否为空,如果为空,则开辟失败;如果不为空,则指针指向的是开辟的内存空间的首地址。指针指向的内存空间在用free()或者delete(注意delete只是一个操作符,而free()是一个函数)释放后,如果程序员没有对其置空或者其他的赋值操作,就会使其成为一个野指针。
3.指针操作超越变量作用域.
上述问题在于,指针指向的内存空间已经无效了,而该指针变量的值(即该指针原来指向的内存空间的地址)没有被置空,解引用一个非空的无效指针是一个未被定义的行为,也就是说不一定导致段错误,野指针很难定位到是哪里出现的问题,在哪里这个指针就失效了,不好查找出错的原因。所以调试起来会很麻烦,有时候会需要很长的时间。
1.在定义一个指针时同时初始化为NULL;
int *p=NULL;
2.释放指针指向的内存空间时,将指针重置为NULL。
free(p1); //只释放了p1指向的堆区空间 并没有将指针p1置为空
p1 = NULL;
3.使用时不要超出变量作用域,如使用数组时:
int a[3];
int*p=a;
cout<