数组与指针

一、数组

数组中的元素可以是各种简单数据类型,如char,int等,数组中的元素在连续的内存空间中顺序存放。数组名代表数组首元素的地址,对数组名应用地址运算符时得到的是整个数组的地址,例如

 short tell[20];

若short占两个字节,则tell+1将地址值加2,而&tell+1将地址加20,因为&tell指向的是整个数组(即20个short)的地址。

换句话说tell是个short指针,即short*。而&tell是一个这样的指针,它指向包含20个元素的short数组,即short(*)[20];(注意不能丢掉括号)。

数组在作为参数使用时数组名退化为指针,这也是为什么指针作为参数传递时经常还需要一个长度参数的原因。注意这里退化的意思,暗含的意思是数组名并不完全等同与指针。如上,对tell采用运算符sizeof得到其长度是整个数组所占控件,即20*2 =40字节,而对short *p采用sizeof得到4(指针类型所占空间,与系统有关)

二、指针

指针中存放的是地址,可以通过*操作符取得指针所指向地址存放的变量(或常量),注意:在使用*运算符之前一定要保证指针已初始化为一个确定的适当的地址。指针变量所占空间与系统有关,在32位系统下为4字节,64位系统下为8字节。

指针的真正用武之地在于,在运行阶段分配未命名的内存以存储值(动态内存分配),此情况下只能通过指针来访问内存。

以字符串为例比较指针和数组的特性如下:

1 修改内容

char a[] = “hello”;

a[0] = ‘X’;

cout << a << endl;

char *p = “world”; // 注意p 指向常量字符串

p[0] = ‘X’; // 编译器不能发现该错误

cout << p << endl;

如上,字符数组a 的容量是6 个字符,其内容为hello\0,。a 的内容可以改变。

指针p 指向常量字符串“world”(位于静态存储区,内容world\0),常量字符串的内容是不可以被修改的。从语法上看,编译器并不觉得语句p[0]= ‘X’有什么不妥,但是该语句企图修改常量字符串的内容而导致运行错误。 

2内容复制与比较

不能对数组名进行直接复制与比较。示例7-3-2 中,若想把数组a 的内容复制给数组b,不能用语句 b = a ,否则将产生编译错误。应该用标准库函数strcpy 进行复制。同理,比较b 和a 的内容是否相同,不能用if(b==a) 来判断,应该用标准库函数strcmp进行比较。

语句p = a 并不能把a 的内容复制指针p,而是把a 的地址赋给了p。要想复制a的内容,可以先用库函数malloc 为p 申请一块容量为strlen(a)+1 个字符的内存,再用strcpy 进行字符串复制。同理,语句if(p==a) 比较的不是内容而是地址,应该用库函数strcmp 来比较。

3计算内存容量(sizeof)

用运算符sizeof 可以计算出数组的容量(字节数)。例如:

char a[] = "hello world";

char* p = a;

sizeof(a)的值是12(注意别忘了’\0’)。指针p 指向a,但是sizeof(p)的值却是4。这是因为sizeof(p)得到的是一个指针变量的字节数,相当于sizeof(char*),而不是p 所指的内存容量。C++/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。

注意数组名作为参数传递时退化为指针,因此此时需注意对数组名采用sizeof时会得到4,如下:

void Func(char a[100])

{

cout<< sizeof(a) << endl; // 4 字节而不是100 字节,此时数组名退化为指针

}

三、数组指针与指针数组

数组指针也是指针,只不过其指向的是数组,因此数组指针相当于二级指针(因为数组也相当于指针)

如: int(*a)[4]:指向由4个int组成的数组的指针(即指向指针的指针)

指针数组就是数组,只是数组中的元素都是指针。如: int*a[4];4个指向int的指针组成的数组

举例说明如下

指针数组:

char *cc[]={"hello","c++","world","I'm","coming!"};

int sz=sizeof(cc);

此处sz为20,因为cc是一个指针数组,它包含5个指针,而每个指针占4个字节,因此cc总共占20个字节。

数组指针:

int a[2][3] = { {1,2,3}, {4,5,6} };

int(*pp)[3]=ia;//行指针,指向二维数组的一行,[]中的数字表示每一行的元素个数

cout<<pp[1][1]<<endl;//通过二级指针去访问数组元素pp[1][1]<=>*(*(pp+1)+1)

行指针可以描述指向数组的元素个数,以行为单位,加1就是指针指到下一行。注意pp+1和*(pp+1)都是第二行首元素的地址。

虽然数组指针可以理解为二级指针,但二者也不是完全等同的。如:

int(*p1)[3]-->p1的类型是int[3], p1+1,走3个int,一个数组的长度

int **p2-->p2的类型是int* ,p2+1,走1个int

四、常量指针与指针常量

常量指针指向常量(const或字面常量,如“hello”),不能通过指针改变它所指向的常量的值。当然,这不妨碍将指针修改为指向其他变量。

指针常量是说指针是常量,不能修改指针,即不能让指针指向其他值。

比较:const int*p:常量指针

            int* const p:指针常量

方法:看const离谁更近则谁不能改。const int* p 离int近因此不能通过指针改常量,为常量指针。int* const p离p近,即不能改指针,为指针常量。

另外不用const时也会出现常量指针:

char *p="Hello"; //这就是常量指针

p[2]=‘s’;//错误,指针指向一个常量,不能改变

strcat(p,"W

要想改变指针指向的字符串,可按下面的方式使用:

char *p;

char ch[6]="world";

p=ch;

p[2]='h';//正确,这样将p指向的字符串改为wohld

orld");//错误,指针指向一个常量,不能改变,所以指针后面不能添加东西

五、C++中的指针使用规则

c++禁止将const的地址赋给非const指针,如下:

const float f=1.55;

float *p=&f;//invalid

因此将常量数组的地址赋给非常量指针也是不允许的,这样就意味这不能将常量数组的数组名作为参数传递给使用非常量形参的函数。

如果非要用,必须使用强制类型转换(const_cast)。另外,仅当只有一层间接关系(如指针指向基本数据类型,不能是指针)时,才可以将非const地址或指针赋给const指针。也就是说,如果数据类型本身并不是指针,则可以将const数据或非const数据的地址赋给指向const的指针,但只能将非const数据的地址赋给非const指针

在函数中尽量使用const指针做参数,理由如下:

这样可以避免由于无意间修改数据而导致的编程错误;

使用const使得函数能够处理const和非const实参,否则将只能接收非const数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值