C中 数组和指针的异同
数组在很多情况下是和指针等价的,数组的下标运算和指针的解引用也有等价形式:arr[i] == *(arr + 1);但是也有一些情况下数组和指针是不一样的:extern int arr[]; extern int *arr;
这里持续记录一下指针和数组的异同(以下来自于C专家编程)
首先明确一下几个定义:
- 声明和定义:C语言中的对象必须有且只有一个定义,但是可以有多个extern声明。
定义 | 只能出现在一个地方 | 确定对象的类型并分配内存,用于创建新的对象。例如:int my_array[100] |
声明 | 可以多次出现 | 描述对象的类型,用于指代其他地方定义的对象(例如在其他文件里)例如:extern int my_array[] |
- 区分定义和声明:
- 声明相当于普通的声明:它所说明的并非自身,而是描述其他地方的创建的对象
- 定义相当于特殊的声明:它为对象分配内存
- 区分定义和声明:
- 左值和右值(地址和地址的内容):
注:C语言引入了"可修改的左值"这个术语,可修改的左值指的是可以放在赋值语句左边。这个术语是为了与数组名区分,数组名也用于确定对象在内存中的位置,也是左值,但它不能作为赋值的对象。因此,数组名是个左值但不是可修改的左值。
- 指针与数组的不同:
- 编译器为每个变量分配一个地址(左值),这个地址在编译时可知,而且该变量在运行时一直保存于这个地址。相反,存储于变量中的值(它的右值)只有在运行时才可知。如果需要用到变量中存储的值,编译器就要发出指令从指定地址读入变量值并将它存于寄存器中。所以,如果编译器需要一个地址来执行某种操作,它就可以直接进行操作(因为符号的地址在编译时可知),并不需要增加指令首先取得具体的地址。相反,对于指针,必须首先在运行时取得它的当前值(取得指针本身所存的右值),然后才能对它进行解除引用操作。
- 故: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中 数组和指针的异同的更多相关文章
- C语言中数组与指针的异同之处!你不知道的编程奥秘~
C语言的数组和指针一直是两个容易混淆的东西,当初在学习的时候,也许为了通过考试会对指针和数组的一些考点进行突击,但是很多极其细节的东西也许并不是那么清楚.本篇侧重点在于分析数组与指针的关系,什么时候数 ...
- C/C++中数组与指针的关系探究
数组与指针 长期以来,在C/C++中,数组名和指向数组首元素的指针常量到底是以一种什么关系,一直困扰着很多人.很多地方,甚至是一些教科书中都在说,"数组名就是一个指向数组首元素的指针常量&q ...
- 《挑战30天C++入门极限》新手入门:C/C++中数组和指针类型的关系
新手入门:C/C++中数组和指针类型的关系 对于数组和多维数组的内容这里就不再讨论了,前面的教程有过说明,这里主要讲述的数组和指针类型的关系,通过对他们之间关系的了解可以更加深入的掌握数组和指 ...
- 由strcat函数引发的C语言中数组和指针问题的思考
问题一 首先,来看一下下面这段代码: #include <stdio.h> #include <string.h> int main() { char *str = " ...
- c语言中数组,指针数组,数组指针,二维数组指针
1.数组和指针 ] = {,,,,};// 定义数组 // 1. 指针和数组的关系 int * pa = array; pa = array; // p[0] == *(p+0) == array[0 ...
- C中数组与指针【转】
在这里随便定义一个数组 int arr[5]; arr现在就是数组名, arr 代表的是该数组整块内存,即sizeof(arr) == 20 (假设sizeof(int) == 4), arr 里的内 ...
- C 中数组和指针的区别
联系: 1,一个通过数组和下标实现的表达式可等价地通过指针和偏移量实现. 2,当数组名传递给一个函数时,实际上传递的是该数组第一个元素的地址. 区别: 1,指针是一个变量,因此,在C语言中,语句pa= ...
- php中数组的指针
利用PHP内置的函数 key() 获得键. current()获得值, next(); prev();移动到上一个 reset();//重置,移动到第一个元素 end();//移动到最后一个元素上 注 ...
- 深入理解C/C++数组和指针
C语言中数组和指针是一种很特别的关系,首先本质上肯定是不同的,本文从各个角度论述数组和指针. 一.数组与指针的关系数组和指针是两种不同的类型,数组具有确定数量的元素,而指针只是一个标量值.数组可以在某 ...
随机推荐
- 原生javascript实现call、apply和bind的方法
var context = {id: 12}; function fun (name, age) { console.log(this.id, name, age) } bind bind() 方法会 ...
- [Luogu] P1441 砝码称重
题目描述 现有n个砝码,重量分别为a1,a2,a3,……,an,在去掉m个砝码后,问最多能称量出多少不同的重量(不包括0). 题目分析 因为读错题WAWA大哭. 先dfs枚举选的砝码,满足条件时进行d ...
- Mac使用Aria2下载百度网盘,突破下载限速的方法教程
百度网盘目前可以说是在国内网盘环境中一枝独秀,日常使用触及在所难免,尤其是对于喜欢下载资源的朋友来说,但是一些限制让它的使用越来越难,尤其是下载速度,普通用户的下载往往远低于自己的预期,特别是对于 M ...
- SQL-如何使用 MongoDB和PyMongo。
先决条件 在开始之前,请确保已经安装了 PyMongo 发行版. 在 Python shell 中,下面的代码应该在不引发异常的情况下运行: >>> import pymongo 假 ...
- LeetCode(50) Pow(x,n)
题目 Implement pow(x, n). Show Tags Show Similar Problems 分析 一个不利用标准幂次函数的,求幂算法实现. 参考了一个很好的解析博客:Pow(x,n ...
- 洛谷 3871 [TJOI2010]中位数
[题解] 平衡树模板题,不过因为可以离线,所以有别的做法.把询问倒着做,变成删掉数字.求中位数,于是可以二分+树状数组. #include<cstdio> #include<cstr ...
- 集训第四周(高效算法设计)J题 (中途相遇法)
Description The SUM problem can be formulated as follows: given four lists A, B, C, D<tex2html_ ...
- 一个简单的模板了解css+div网页布局
直接附上最终效果图: index.html内容: <html> <!--20170730 soulsjie--> <head> <meta http-equi ...
- conflunce安装配置
下载 下载Confluence-v5.4.4.zip包,其中包含 atlassian-confluence-5.4.4-x64.bin #程序二进制文件 confluence5.x-crack.z ...
- SQL Server 2008如何创建定期自动备份任务
我们知道,利用SQL Server 2008数据库可以实现数据库的定期自动备份.方法是用SQL SERVER 2008自带的维护计划创建一个计划对数据库进行备份,下面我们将SQL SERVER 200 ...