转: 浅谈C/C++中的指针和数组(二)
转自:http://www.cnblogs.com/dolphin0520/archive/2011/11/09/2242419.html
浅谈C/C++中的指针和数组(二)
前面已经讨论了指针和数组的一些区别,然而在某些情况下,指针和数组是等同的,下面讨论一下什么时候指针和数组是相同的。
C语言标准对此作了说明:
规则1:表达式中的数组名被编译器当做一个指向该数组第一个元素的指针;
注:下面几种情况例外
1)数组名作为sizeof的操作数
2)使用&取数组的地址
规则2:下标总是与指针的偏移量相同;
规则3:在函数参数的声明中,数组名被编译器当做指向该数组第一个元素的指针。
规则1和规则2结合在一起理解,就是对数组下标的引用总是可以写成“一个指向数组的起始地址的指针加上偏移量”。如a[i]总是被编译器解析为*(a+i)的形式。
规则1:表达式中的数组名总被编译器解析为指针,因此如下语句int a[3];int *p=a;是可以正确编译执行的。在表达式中a被解析为指向数组第一个元素的指针,那么赋值符号两边的类型匹配,因此可以正确编译执行。
规则2:下标总是和指针的偏移量相同。C语言中将数组的下标改写成指针偏移量的主要原因在于指针和偏移量是底层硬件所使用的基本类型。如a[i]中的i总被编译器解析为偏移量,所以a[i]总是被改写成*(a+i)的形式(因此a[i] 和 i[a] 是等价的),a是指向数组第一个元素的指针,加上偏移量i,表示该指针向后移i个步长,然后取a+i所在单元的内容。由此就可以解释为什么C语言中数组的下标可以为负,而且在我看来,C语言中不检查数组的下标是否越界同样跟这个有关,如下面这段程序:

#include<stdio.h> int main(void)
{
int a[3]={1,2,3};
int *p=(a+3);
printf("%d\n",p[-1]);
return 0;
}

程序执行结果为3,虽然下标为-1,但是被编译器解析为偏移量,因此相当于*(p-1)。
规则3:在函数参数的声明中,数组名被编译器当做指向该数组第一个元素的指针。在C语言中将形参的数组和指针等同起来是出于效率的考虑。假如不这么做,将整个数组的每个元素的值都拷贝一份进行传递,这样无论在时间上还是空间上的开销都可能是非常大的。但是又要能操作到数组中的元素,只需将数组第一个元素的地址传递给调用函数,然后通过指针去访问想要访问的空间,这样一来时空消耗将大大减少。因此在函数内部,编译器始终把参数中声明的数组名当做一个指向数组第一个元素的指针,这样一来,编译器可以产生正确代码,并不需要对数组和指针这两种情况作区分。因此void fun(int a[]);和void fun(int *a)两种形式的效果完全等同,在函数内部去引用a的话,始终都会被编译器认为是指针。因为void fun(int a[]);这种形式最终还是会被编译器解析为void fun(int *a);这种形式告诉我们调用时必须传递一个指向整型数据的指针。所以下面这段代码可以正确编译和执行:

#include<stdio.h> void fun(int a[])
{
printf("%d\n",a[0]);
}
int main(void)
{
int a[3]={1,2,3};
int *p1,*p2;
int b=4;
p1=a;
p2=&b;
fun(a);
fun(&a[1]);
fun(p1);
fun(p2);
fun(&b);
return 0;
}

区分几个表达式的含义:
&p,p,a,&a
&p:表示取存储指针变量p的内存单元的地址; sizeof(&p)=4;
p:表示取指针变量p存储的地址; sizeof(p)=4;
a:表示取数组第一个元素的地址; sizeof(a)=3*4=12;
&a:表示取整个数组的首地址; sizeof(&a)=4(在VC++6.0中该值为12,我认为是错误的,因为其类型是数组指针)
虽然a和&a的值相同,但是所表达的含义完全不同,a表示取数组第一个元素的地址,而&a表示取数组的首地址。它们所代表的类型也完全不同,a是一个int型指针,而&a是一个int (*p)[]型指针,即数组指针(在后续文章中会作解释)。所以a+1和&a+1得到的结果不同,a+1表示将指向该数组的第一个元素的指针向后移一个步长(这里的步长为数组元素类型所占的字节数);而&a+1表示将指向该数组的指针向后移动一个步长(而此处的步长为数组元素个数*元素类型所占的字节数)。

#include<stdio.h> int main(void)
{
int a[3]={1,2,3};
int *p=a;
printf("%08x\n",&p);
printf("%08x\n",p);
printf("%08x\n",&p+1);
printf("%08x\n",p+1);
printf("%08x\n",a);
printf("%08x\n",&a);
printf("%08x\n",a+1);
printf("%08x\n",&a+1); //注意输出结果
return 0;
}

转: 浅谈C/C++中的指针和数组(二)的更多相关文章
- 转:浅谈C/C++中的指针和数组(一)
再次读的时候实践了一下代码,结果和原文不一致 error C2372: 'p' : redefinition; different types of indirection 不同类型的间接寻址 /// ...
- 浅谈c/c++中的指针问题
首先给出几种指针类型来作出区分,不看后面的解析如果可以自己分辨正确那么就算对指针有一个很好的掌握了,就没有必要再去看后面的解析,如果不能完全区分,那么就有必要仔细看看后面解析. 1 Char * p ...
- 浅谈 Swift 2 中的 Objective-C 指针
浅谈 Swift 2 中的 Objective-C 指针 2015-09-07 499 文章目录 1. 在 Swift 中读 C 指针 2. 在 Swift 中创建 C 指针 3. 总结 作者:Ja ...
- 浅谈C中的指针和数组(一)
本文转载地址:http://www.cnblogs.com/dolphin0520/archive/2011/11/09/2242138.html 在原文的基础上加入自己的想法作为修改. 指针是C/C ...
- c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程
c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...
- 浅谈C++11中的多线程(三)
摘要 本篇文章围绕以下几个问题展开: 进程和线程的区别 何为并发?C++中如何解决并发问题?C++中多线程的基本操作 浅谈C++11中的多线程(一) - 唯有自己强大 - 博客园 (cnblogs.c ...
- 浅谈C++11中的多线程(二)
摘要 本篇文章围绕以下几个问题展开: 进程和线程的区别 何为并发?C++中如何解决并发问题?C++中多线程的基本操作 浅谈C++11中的多线程(一) - 唯有自己强大 - 博客园 (cnblogs.c ...
- 转载 浅谈C/C++中的static和extern关键字
浅谈C/C++中的static和extern关键字 2011-04-21 16:57 海子 博客园 字号:T | T static是C++中常用的修饰符,它被用来控制变量的存贮方式和可见性.ext ...
- 浅谈C语言中的强符号、弱符号、强引用和弱引用
摘自http://www.jb51.net/article/56924.htm 浅谈C语言中的强符号.弱符号.强引用和弱引用 投稿:hebedich 字体:[增加 减小] 类型:转载 时间:2014- ...
随机推荐
- Codeforces Round #336 Zuma
D. Zuma time limit per test: 2 seconds memory limit per test: 512 megabytes input: standard input ...
- R2D2 and Droid Army(多棵线段树)
R2D2 and Droid Army time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- Power Network 分类: POJ 2015-07-29 13:55 3人阅读 评论(0) 收藏
Power Network Time Limit: 2000MS Memory Limit: 32768K Total Submissions: 24867 Accepted: 12958 Descr ...
- java中|与||,&与&&到底有什么区别呢?
&是位运算符.&&是布尔逻辑运算符.在运行上,&两边的条件都要判断(不管前面的是ture还是false),而&&先判断前面的,若为false,则后面的不 ...
- Android中直播视频技术探究之---桌面屏幕视频数据源采集功能分析
一.前言 之前介绍了Android直播视频中一种视频源数据采集:摄像头Camera视频数据采集分析 中介绍了利用Camera的回调机制,获取摄像头的每一帧数据,然后进行二次处理进行推流.现在我们在介绍 ...
- 推荐一款非常棒的谷歌插件---快速查看HTML页面元素的CSS样式
一.下载地址 http://chromecj.com/web-development/2015-05/456/download.html 二.简介 CssViewer是一款快速查看当前页面元素的CSS ...
- Struts2的标签库(四)——数据标签
Struts2的标签库(四) --数据标签 1.action标签 该标签用于在jsp页面直接调用一个Action,通过指定executeResult参数,还可以将Action的处理结果包含到此页面中来 ...
- BZOJ 2758 Blinker的噩梦(扫描线+熟练剖分+树状数组)
题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2758 题意:平面上有n个多边形(凸包和圆).任意两个多边形AB只有两种关系:(1) ...
- JavaWeb(一)
Web应用程序开发是目前软件开发领域的三大方向之一. 静态网页与动态网页 静态网页 表现形式:网页的内容是固定的,不会更新: 使用的技术:HTML,CSS 动态网页 表现形式:网页中的内容通过程序动态 ...
- 泛型之Dictionary
Dictionary<string, string>是一个泛型 他本身有集合的功能有时候可以把它看成数组 他的结构是这样的:Dictionary<[key], [value]> ...