数组在很多情况下是和指针等价的,数组的下标运算和指针的解引用也有等价形式:arr[i] == *(arr + 1);但是也有一些情况下数组和指针是不一样的:extern int arr[]; extern int *arr;

这里持续记录一下指针和数组的异同(以下来自于C专家编程)

首先明确一下几个定义:

  • 声明和定义:C语言中的对象必须有且只有一个定义,但是可以有多个extern声明。
定义 只能出现在一个地方 确定对象的类型并分配内存,用于创建新的对象。例如:int my_array[100]
声明 可以多次出现 描述对象的类型,用于指代其他地方定义的对象(例如在其他文件里)例如:extern int my_array[]
    • 区分定义和声明:

      • 声明相当于普通的声明:它所说明的并非自身,而是描述其他地方的创建的对象
      • 定义相当于特殊的声明:它为对象分配内存
  • 左值和右值(地址和地址的内容):

注:C语言引入了"可修改的左值"这个术语,可修改的左值指的是可以放在赋值语句左边。这个术语是为了与数组名区分,数组名也用于确定对象在内存中的位置,也是左值,但它不能作为赋值的对象。因此,数组名是个左值但不是可修改的左值。

  1. 指针与数组的不同:
    • 编译器为每个变量分配一个地址(左值),这个地址在编译时可知,而且该变量在运行时一直保存于这个地址。相反,存储于变量中的值(它的右值)只有在运行时才可知。如果需要用到变量中存储的值,编译器就要发出指令从指定地址读入变量值并将它存于寄存器中。所以,如果编译器需要一个地址来执行某种操作,它就可以直接进行操作(因为符号的地址在编译时可知),并不需要增加指令首先取得具体的地址。相反,对于指针,必须首先在运行时取得它的当前值(取得指针本身所存的右值),然后才能对它进行解除引用操作。
    • 故:int a[100] 和 extern int a[]都表明a是一个数组,也就是一个内存地址,数组内的字符可以从这个地址找到。从数组提取一个字符,只要简单的从符号表显示的a的地址加上下标,需要的字符就位于这个地址中。相反,如果声明extern int *p,它告诉编译器p是一个指针,它指向的对象时一个字符。为了取得这个字符,必须得到地址p的内容(注意数组a本身就是一个地址),把它作为字符的地址并从这个地址中取得这个字符,相比数组a来说多了一次额外的提取。取a中的字符和p所指的字符见下图:

    • 由上可知,int a[100] 告诉编译器a是一个数组,本身就是一个地址。int *p告诉编译器p是一个指针,p所在的地址中存的是一个int的地址。

下面继续对数组和指针进行解释:"当定义为指针,但以数组方式引用"时会发生什么

    • 这时编译器所执行的是对内存进行间接引用。之所以会如此是因为我们告诉编译器我们拥有的是一个指针。

对照上图的访问方式:
                    char *p = "abcdefg";    ...... p[3]
                    和
                    char a[] = "abcdefg";    ...... a[3]
                    这两种情况都可以取得字符'd',但两者的途径却很不一样。

当写了extern char *p的时候,编译器将会:
                     a.取得符号表中p的地址,提取存储于此处的指针
                     b.把下标所表示的偏移量与指针的值相加,产生一个地址
                     c.访问上面这个地址,取得字符。

    • 考虑如果p被声明为extern char *p;但是它原先的定义却是char p[10];这种情形。当用p[i]这种形式提取这个声明的内容的时候,实际上得到的是一个字符。但是按照上面的方法,编译器确把它当成是一个指针,就会先去取这个地址中所存的地址,但是其实p的地址中现在存的其实已经是一个int型了,吧ASCII字符解释为地址显然是驴唇不对马嘴。相反的,如果p被声明为extern char p[];但是它原先定义却是int *p;这种情形的话,那么p[i],编译器会直接取地址(p + i),显然这也是不对的,因为此时直接把p的地址和i相加其实是一个不存在的地址。
    • 可见数组和指针在这种情况下是不同的。在C语言中,对数组的引用其实引用的是地址本身(不可变左值),但是对指针的引用其实是引用指针所在地址中的内容(右值)。

数组和指针的其他区别

指针 数组
保存数据的地址 保存数据

间接访问数据,首先取得指针的内容,把它作为地址,然后从这个地址提取数据。

如果指针有一个下标[I],就把指针的内容加上I作为地址,从中提取数组

直接访问数据,a[I]只是简单的一a + I为地址取得数据
通常用于动态数据结构 通常用于存储固定数目且数据类型相同的元素
相关的函数为malloc(),free() 隐式分配和删除
通常指向匿名数据 自身即为数据名

2.数组和指针的相同点:


除了上面的几种不同的情况以外,很多情况下数组和指针是可以等同看待的,例如在作为函数的形参的时候,数组和指针是等价的:void foo(int *); == void foo(int[]);

很多情况下我们使用数组和指针的时候也是非常类似的,例如 arr[n] == *(arr + n)

C中 数组和指针的异同的更多相关文章

  1. C语言中数组与指针的异同之处!你不知道的编程奥秘~

    C语言的数组和指针一直是两个容易混淆的东西,当初在学习的时候,也许为了通过考试会对指针和数组的一些考点进行突击,但是很多极其细节的东西也许并不是那么清楚.本篇侧重点在于分析数组与指针的关系,什么时候数 ...

  2. C/C++中数组与指针的关系探究

    数组与指针 长期以来,在C/C++中,数组名和指向数组首元素的指针常量到底是以一种什么关系,一直困扰着很多人.很多地方,甚至是一些教科书中都在说,"数组名就是一个指向数组首元素的指针常量&q ...

  3. 《挑战30天C++入门极限》新手入门:C/C++中数组和指针类型的关系

        新手入门:C/C++中数组和指针类型的关系 对于数组和多维数组的内容这里就不再讨论了,前面的教程有过说明,这里主要讲述的数组和指针类型的关系,通过对他们之间关系的了解可以更加深入的掌握数组和指 ...

  4. 由strcat函数引发的C语言中数组和指针问题的思考

    问题一 首先,来看一下下面这段代码: #include <stdio.h> #include <string.h> int main() { char *str = " ...

  5. c语言中数组,指针数组,数组指针,二维数组指针

    1.数组和指针 ] = {,,,,};// 定义数组 // 1. 指针和数组的关系 int * pa = array; pa = array; // p[0] == *(p+0) == array[0 ...

  6. C中数组与指针【转】

    在这里随便定义一个数组 int arr[5]; arr现在就是数组名, arr 代表的是该数组整块内存,即sizeof(arr) == 20 (假设sizeof(int) == 4), arr 里的内 ...

  7. C 中数组和指针的区别

    联系: 1,一个通过数组和下标实现的表达式可等价地通过指针和偏移量实现. 2,当数组名传递给一个函数时,实际上传递的是该数组第一个元素的地址. 区别: 1,指针是一个变量,因此,在C语言中,语句pa= ...

  8. php中数组的指针

    利用PHP内置的函数 key() 获得键. current()获得值, next(); prev();移动到上一个 reset();//重置,移动到第一个元素 end();//移动到最后一个元素上 注 ...

  9. 深入理解C/C++数组和指针

    C语言中数组和指针是一种很特别的关系,首先本质上肯定是不同的,本文从各个角度论述数组和指针. 一.数组与指针的关系数组和指针是两种不同的类型,数组具有确定数量的元素,而指针只是一个标量值.数组可以在某 ...

随机推荐

  1. 原生javascript实现call、apply和bind的方法

    var context = {id: 12}; function fun (name, age) { console.log(this.id, name, age) } bind bind() 方法会 ...

  2. [Luogu] P1441 砝码称重

    题目描述 现有n个砝码,重量分别为a1,a2,a3,……,an,在去掉m个砝码后,问最多能称量出多少不同的重量(不包括0). 题目分析 因为读错题WAWA大哭. 先dfs枚举选的砝码,满足条件时进行d ...

  3. Mac使用Aria2下载百度网盘,突破下载限速的方法教程

    百度网盘目前可以说是在国内网盘环境中一枝独秀,日常使用触及在所难免,尤其是对于喜欢下载资源的朋友来说,但是一些限制让它的使用越来越难,尤其是下载速度,普通用户的下载往往远低于自己的预期,特别是对于 M ...

  4. SQL-如何使用 MongoDB和PyMongo。

    先决条件 在开始之前,请确保已经安装了 PyMongo 发行版. 在 Python shell 中,下面的代码应该在不引发异常的情况下运行: >>> import pymongo 假 ...

  5. LeetCode(50) Pow(x,n)

    题目 Implement pow(x, n). Show Tags Show Similar Problems 分析 一个不利用标准幂次函数的,求幂算法实现. 参考了一个很好的解析博客:Pow(x,n ...

  6. 洛谷 3871 [TJOI2010]中位数

    [题解] 平衡树模板题,不过因为可以离线,所以有别的做法.把询问倒着做,变成删掉数字.求中位数,于是可以二分+树状数组. #include<cstdio> #include<cstr ...

  7. 集训第四周(高效算法设计)J题 (中途相遇法)

    Description   The SUM problem can be formulated as follows: given four lists A, B, C, D<tex2html_ ...

  8. 一个简单的模板了解css+div网页布局

    直接附上最终效果图: index.html内容: <html> <!--20170730 soulsjie--> <head> <meta http-equi ...

  9. conflunce安装配置

    下载 下载Confluence-v5.4.4.zip包,其中包含   atlassian-confluence-5.4.4-x64.bin #程序二进制文件 confluence5.x-crack.z ...

  10. SQL Server 2008如何创建定期自动备份任务

    我们知道,利用SQL Server 2008数据库可以实现数据库的定期自动备份.方法是用SQL SERVER 2008自带的维护计划创建一个计划对数据库进行备份,下面我们将SQL SERVER 200 ...