C++指针和数组

目录:

3、数组与指针

4、指针的潜在危险

``

3.数组与指针

3.1一维数组与指针

定义指针变量指向数组首元素,以指针变量名代替数组名,实现数组操作。(指针所指位置不变)
指针变量从前到后依次指向数组各元素,通过指针的取内容运算得到对应元素。(指针所指位置不断变化)
例:用下列数据初始化一维数组,并通过指针变量求元素的最大值。
8.2 6.5 3 9.7 12 2.8 7.6 15 10.3
定义实型指针p指向数组b的首元素,max 表示最大值;
以p 代替b,通过循环语句输出数组的各元素;
指针p 从第二个元素开始遍历数组,遍历过程中将比max 大的元素赋给max。

#include<iostream>
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<<p[i]<<'\t'; 	 // 指针变量名p代替数组名b
		if((i+1)%5==0)cout<<'\n';
	}
	cout<<endl;
    p++; 	// p 指向b[1],等同于p =&b[1]
	for(int i=0;i<9;i++)
    {  // 求最大元素
		if(*p>max)max=*p;  // *p是指针p所指元素的值
		p++; 	// p 后移一个元素
	}
	cout<<"元素的最大值为:"<<max<<"\n";
	return 0;
}

l指针变量只能代表其所指向的数组。当指针不再指向数组的首元素时,不能代表原数组。

3.2二维数组与指针

3.2.1元素指针与行指针

指向元素的指针简称元素指针。(指向元素)
二维数组元素指针与一维数组元素指针的定义方式相同,使用方法相似。如:

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列的元素
3.2.2元素指针使用二维数组

将二维数组作为一个行数×列数的一维数组
定义元素指针指向二维数组的第一行第一列元素;
一维数组名为指针变量名;
一维数组大小为二维数组的行数×列数。

3.2.3行指针使用二维数组

定义行指针指向二维数组的首行
行指针变量名代替二维数组名,实现二维数组的操作;
行指针取值运算得到元素地址,然后元素地址取值运算得到元素,完成对二维数组的操作。
注意元素指针与行指针使用的区别,指针所指的位置。

例:通过指针输出下列二维数组,并求各元素的和。
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<iostream>
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<<p1[i][j]<<'\t';
		cout<<endl;
	}
	for(i=0;i<3*5;i++)            // 求二维数组各元素的和
		sum+=p2[i];
	cout<<"和为:"<<sum<<'\n';
	return 0;
}
3.2.4字符数组与指针

字符型指针变量指向字符串
定义时用字符串对其初始化;
(1)用字符串对指针变量赋值。
如:

char *s1=" C++ Program",*s2; 
s2=" This is a string."; 

(2)直接引用字符型指针变量所指的字符数组

#include <iostream>
#include <cstring>
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<<s3;                                                       // 输出字符数组
strcpy(s3,s1);                                                 // 复制字符数组
*s3=*s2;  
return 0;
}

结合前面讲过的二级指针,我们来看看使用的实例。

#include<iostream>
#include<string>
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<<"]point to";
		cout<<*p<<endl;
	}
    return 0;
}

例:设计一个程序,将字符串中的字符逆序。如将“I am a student.”逆序为“.tneduts a ma I”。
数组str 存储字符串,指针s1 指向首元素,s2 指向尾元素。
当s1在s2前面时,将s1 和s2 所指的元素互换;然后s1 后移一个元素,s2 前移一个元素。

#include<iostream>
#include<string>
using namespace std;
int main(void) {
char str[100],*s1=str,*s2=str,t;
cout<<"请输入一个字符串:";
cin.getline(s1,100);
cout<<"输入的字符串是:";
cout<<s2<<endl; 			// s2等同str、s1

while(*s2) s2++;       // s2 指向结束标志(循环条件的含义?)
s2--;                                                 //前移一位,指向尾元素
while(s1<s2) {                                           // 当s1 在s2 前面时
t=*s1,*s1=*s2,*s2=t;                  // 交换s1 和s2 所指元素
s1++,s2--;   // s1 后移、s2前移(指针前有没有*的区别?)
}
cout<<"逆序后的字符串是:";
cout<<str<<endl; 
return 0;
}

指针使用数组
搞清指针所指位置
分清操作对象是指针本身还是指针所指内存空间
分清所使用的是元素指针还是行指针
充分理解指针的含义:地址;代表所指向的数组。

3.2.5指针数组

各元素为指针变量的数组。
普通数组中存储的是普通数据(数值),指针数组中存储的是地址。
定义:

存储类型 数据类型* 数组名[数组大小];

如:

float *p1[5];
#include <iostream>
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;
}

4.指针的潜在危险

指针的让我们对内存的操作有了很大的自由性,同时也带来了潜在的危险。

4.1产生的原因:

1.定义指针变量的同时未对其进行初始化:指针在被定义的时候,如果程序不对其进行初始化的话,它会指向随机区域,因为任何指针变量(除了static修饰的指针变量)在被定义的时候是不会被置空的,它的默认值是随机的。

2.指针所指向的内存空间被释放时,却没有对该指针变量的值(即该指针原来指向的内存空间的地址)进行置空:我们在用库函数malloc开辟内存空间时,要检查返回值是否为空,如果为空,则开辟失败;如果不为空,则指针指向的是开辟的内存空间的首地址。指针指向的内存空间在用free()或者delete(注意delete只是一个操作符,而free()是一个函数)释放后,如果程序员没有对其置空或者其他的赋值操作,就会使其成为一个野指针。

3.指针操作超越变量作用域.

4.2危害:

上述问题在于,指针指向的内存空间已经无效了,而该指针变量的值(即该指针原来指向的内存空间的地址)没有被置空,解引用一个非空的无效指针是一个未被定义的行为,也就是说不一定导致段错误,野指针很难定位到是哪里出现的问题,在哪里这个指针就失效了,不好查找出错的原因。所以调试起来会很麻烦,有时候会需要很长的时间。

4.3规避的方法:

1.在定义一个指针时同时初始化为NULL;

int *p=NULL;

2.释放指针指向的内存空间时,将指针重置为NULL。

free(p1);			//只释放了p1指向的堆区空间  并没有将指针p1置为空
p1 = NULL;

3.使用时不要超出变量作用域,如使用数组时:

int a[3];
int*p=a;
cout<<p[5];
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,以下是几道C++指针数组的选择题,希望能帮到你: 1. 下列哪个选项声明了一个指向整数的指针? A. int *p; B. int p; C. int &p; D. int []p; 答案:A 解析:选项A声明了一个指向整数的指针,选项B声明了一个整数变量,选项C声明了一个整数的引用,选项D声明了一个整数的数组。 2. 下列哪个选项声明了一个整数数组? A. int *p; B. int p; C. int &p; D. int []p; 答案:D 解析:选项D声明了一个整数数组,选项A声明了一个指向整数的指针,选项B声明了一个整数变量,选项C声明了一个整数的引用。 3. 假设有一个名为array的整数数组,下列哪个选项是正确访问第二个元素? A. array[0] B. array[1] C. array D. &array[2] 答案:B 解析:数组下标从0开始,因此第二个元素的下标是1,所以选项B是正确的。 4. 假设有一个名为ptr的指向整数的指针,下列哪个选项是正确访问指针所指向的整数? A. *ptr B. &ptr C. ptr D. ptr++ 答案:A 解析:选项A访问了指针所指向的整数,选项B访问了指针本身的地址,选项C访问了指针本身,选项D将指针自增了一次。 5. 假设有一个名为array的整数数组,下列哪个选项是正确访问数组最后一个元素? A. array[size-1] B. array[size] C. array[size+1] D. &array[size] 答案:A 解析:数组下标从0开始,因此最后一个元素的下标是size-1,所以选项A是正确的。 希望这些题目能够帮助你巩固指针数组的知识。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值