数组和指针的区别

一:数组和指针可以相互替代吗?

有这样两个定义:

char *p  = “abcd”;

char data[] = “abcd”;

一直以来,以为数组和指针其实是相通的,也就是说,*(p+1)和data[1]是一样的,都能够取到字符’b’,从来没有考虑过内部是怎么实现的,这两天在看《C专家编程》,里面第4章的标题便是《令人震惊的事实:数组和指针并不相通》,那么实际上到底是怎么样的?大体归纳一下。

里面举了这样一个例子

文件1中有这样的定义: int mango[100];

文件2中有这样的声明: extern int *mango;

到底能不能正常工作呢?按照之前的理解,数组和指针是通用的,所以感觉应该是一样的,但实际上去并不是这样,这段程序没办法得到理想的结果,怎么回事?

这样分析:

对于数组来说,定义了变量 int mango[100];那么就意味着访问mango的时候,mango获取的地址指向的就是一个int的整数,而如果定义的是int * mango;的话,那么访问的时候,mango首先获取一个地址,该地址的内存中存有一个地址A,地址A中才是存放了int类型的变量。也就是说,适用指针来访问的时候,要多经过一步,才能够获取到实际的数据。

当然,其实上面这个例子在gcc下面是无法编译通过的,但可以更好的帮我们理解这个问题, int mango[100];和 extern int *mango;其类型是不相同的,不能够互相替代。

二、声明和定义到底有什么区别?

1、声明和定义的区别在于:

定义:只能出现在一个地方,确定对象的类型,并且为其分配内存,用来创建新的对象。

声明:可以多次出现,描述对象的类型,用来指代其他地方定义的对象。

换句话讲:

声明相当于普通的声明,其说明的并不是其本身,而是描述的其他的地方创建的对象

定义相当于特殊的声明,是为内存分配内存的。

理解:

因为声明不需要为内存分配空间,所以对于 int data[100];的声明 extern int data[];和extern int data[100],其本质上是一样的。

2、左值和右值:

有赋值表达式:

X = Y;

X是左值,在编译的时候可以知道,标识存储结果的地方;

Y是右值,在运行的时候才能够知道,如果没有特殊的说明,标识“Y的内容”;

左值可以分为:可修改的左值 和 不可修改的左值,比如数组名,是不能被修改的,因此不能直接给数组名赋值。只能够给可以修改的东西来赋值。

3、如果定义的指针,但以数组来引用

如果说有定义 char *p = “abcdefgh”;

那么在引用 *(p+i)的时候的,流程为

1、首先取得p的内存单元所保存的值,即5081,将5081作为地址

2、将5081+i作为新的地址

3、使用步骤2中得到的新的地址来获取数据内容

pointer

 

所以,这就很容易理解标题中出现的,如果定义成指针,但是一数组方式来引用的时候,会出现什么情况。

如上图所示,定义成指针的时候,p中保存的是保存这一组数据的内存单元的地址,但如果用数组的方式来引用的话,那么就会直接把4624作为数据的地址,那么如果取p[3]的时候,是从4624+3=4627的位置将数据取出,而此处的存储单元的定义是不明确的,因此也就不能确定程序到底取出了什么数据。就会出先莫名其妙的错误。

因此我们在使用的时候,要保证声明和定义是相互匹配的。

3、其他区别

指针 数组
保存数据的地址 保存数据
间接的访问数据,首先取得指针的内容,把它作为地址,然后从这个地址提取数据。如果指针如果有一个下标[I],将指针的内容加上I作为地址,从中提取数据 直接访问数据,a[I]只是简单的以a+I为地址取得数据
通常用于动态的数据结构 通常用于存储固定数目且数据类型相同的元素
相关的函数为malloc()free() 隐式的分配和删除
通常指向匿名数据 自身就是数据名

在定义指针的时候,编译器不会为其指向的对象分配内存空间,仅仅分配的是内存本身的空间,当然除了一种情况。(在定义指针的时候,同时赋值给它一个字符串常量来初始化,除此之外没有其他情况)。

比如 char *p = “abcdefg”;编译器会为其分配存储空间的

但是float *p  = 3.1415;编译器会报错!

如下段代码

#include <stdlib.h>
#include <stdio.h>

int main(void){

  char *p = "abcdefgh";
  float *pp = 3.1415;

  return 0;
}

 

在编译的时候会提示:

test.c:7:14: 错误: 用‘double’初始化‘float *’时类型不兼容。

 

 

About: happyhls


发表评论

电子邮件地址不会被公开。 必填项已用*标注