浅谈C中的指针和数组(三)
上一个博客我们得到了一个结论:
指针和数组根本就是两个完全不一样的东西。只是它们都可以“以指针形式”或“以下标形式”进行访问。一个是完全的匿名访问,一个是典型的具名+匿名访问。一定要注意的是这个“以XXX 的形式的访问”这种表达方式。
下面就说说两种东西在“以指针形式”访问和“以下标形式”访问的两种情况在指针和数组上的应用。
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+i所在单元的内容。由此就可以解释为什么C语言中数组的下标可以为负,而且在我看来,C语言中不检查数组的下标是否越界同样跟这个有关,如下面这段程序:
#include<stdio.h> int main(void)
{
int a[]={,,};
int *p=(a+);
printf("%d\n",p[-]);
return ;
}
程序执行结果为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[]);
}
int main(void)
{
int a[]={,,};
int *p1,*p2;
int b=;
p1=a;
p2=&b;
fun(a);
fun(&a[]); //注意这句话输出的是2
fun(p1);
fun(p2);
fun(&b);
return ;
}
区分几个表达式的含义:
&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,我认为是错误的,因为其类型是数组指针,就是一个指针,编译时期确定,大小就是4)
虽然a和&a的值相同,但是所表达的含义完全不同,a表示取数组第一个元素的地址,而&a表示取数组的首地址。它们所代表的类型也完全不同,a是一个int型指针,而&a是一个int (*p)[]型指针,即数组指针(在后续文章中会作解释)。所以a+1和&a+1得到的结果不同,a+1表示将指向该数组的第一个元素的指针向后移一个步长(这里的步长为数组元素类型所占的字节数);而&a+1表示将指向该数组的指针向后移动一个步长(而此处的步长为数组元素个数*元素类型所占的字节数)。
#include<stdio.h>
#include<stdlib.h> int main(void)
{
int a[]={,,};
int *p=a;
printf("%08x\n",&p);
printf("%08x\n",p);
printf("%08x\n",&p+);
printf("%08x\n",p+);
printf("%08x\n",a);
printf("%08x\n",&a);
printf("%08x\n",a+);
printf("%08x\n",&a+); //注意输出结果
system("pause");
return ;
}
浅谈C中的指针和数组(三)的更多相关文章
- 浅谈C中的指针和数组(一)
本文转载地址:http://www.cnblogs.com/dolphin0520/archive/2011/11/09/2242138.html 在原文的基础上加入自己的想法作为修改. 指针是C/C ...
- 浅谈C中的指针和数组(五)
前面写了一些C指针和数组的一些知识,但是还有一些很重要的知识没有交代,这里做一个补充. 首先看一下,普通变量(指针也是变量)和数组名查看地址的方式是不同的. 查看数组变量的地址,不需要使用 & ...
- 浅谈C中的指针和数组(二)
原文转载地址:http://see.xidian.edu.cn/cpp/html/475.html 在原文的基础上增加自己的想法作为修改 很多初学者弄不清指针和数组到底有什么样的关系.我现在就告诉你: ...
- 浅谈C中的指针和数组(四)
原文转载地址:http://see.xidian.edu.cn/cpp/html/476.html 在原文的基础上增加自己的思想作为自己的修改 指针数组和数组指针的内存布局 初学者总是分不出指针数组与 ...
- 浅谈C中的指针和数组(七)
现在到揭露数组名本质的时候了,先给出三个结论: (1)数组名的内涵在于其指代实体是一种数据结构,这种数据结构就是数组: (2)数组名的外延在于其可以转换为指向其指代实体的指针,而且是一个指针常量: ( ...
- 浅谈C中的指针和数组(六)
数组和指针,原本不想在写了,觉得这部分差不多了,但是自己在写程序的时候还是发现了一个错误.首先说一下我的要求: 给一个函数传递一个二维数组,然后我想在这个函数里面计算这个数组的行数. 写个类似的错误D ...
- 浅谈C语言 extern 指针与数组
/* * d.c * * Created on: Nov 15, 2011 * Author: root */ #include "apue.h" int a[] = {3,2}; ...
- 浅谈Linux中的信号处理机制(三)
一晃眼,已经到9月底了,都来不及去感慨时间匆匆.最近常常会想明年的今天我将会在那里干着什么样的工作?对未来又是憧憬又是担忧,压力山大.无论如何现在还是踏踏实实的学习吧,能这样安安静静学习的日子也不多了 ...
- 浅谈musql中using的使用---高性能(三)
转载地址:https://blog.csdn.net/lppl010_/article/details/79429657 mysql中using的用法为: using()用于两张表的join查询,要求 ...
随机推荐
- IOS 开展 分别制定了iphone 和 ipad 好? 或开发一个 Universal好?
最近因为工作的需要,.因为时间短的开发周期 开发的需要 积 至iphone 和 ipad 台 执行 优势的版本号 1.安装包,轻松管理,分布 2.您下载iphone,ipad 会自己主动下载 3.审核 ...
- 畅通project(杭电1863)
畅通project Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- Mysql Binlog Dump原理
Register 首先,我们需要伪造一个slave,向master注册,这样master才会发送binlog event.注册很简单,就是向master发送COM_REGISTER_SLAVE命令,带 ...
- Windows系统的安装
一.写在前面 笔者最近因为换工作,在家待业甚感无聊,于是想要整理一些在Windows系统的一些安装方法和下载资源,一来给自己做个备忘,二来把一些不成熟的想法分享出去,希望大家予以指正. ...
- asp.net 一个简单的登录控制
如果说一个网站需要用户登录后才能浏览,那么用户登录控制就不可避免.但是对于几百个以上的页面,不可能每个页面都做一次登录验证.因此,这需要在母版页中进行登录控制,这样就可以使得每一个使用这个母版页的子页 ...
- jQuery Uploadify上传插件
jQuery Uploadify在ASP.NET MVC3中的使用 1.Uploadify简介 Uploadify是基于jQuery的一种上传插件,支持多文件.带进度条显示上传,在项目开发中常被使用. ...
- 禁止select下拉框的其中某个选择项不能被选择
<select name='Grade' class='s8'> <option value=''>— 请选择 —</option>? <optgroup l ...
- Flink Program Guide (7) -- 容错 Fault Tolerance(DataStream API编程指导 -- For Java)
false false false false EN-US ZH-CN X-NONE /* Style Definitions */ table.MsoNormalTable {mso-style-n ...
- php redis数据库操作类
<?php namespace iphp\db; use iphp\App; /** * redis操作类 * 说明,任何为false的串,存在redis中都是空串. * 只有在key不存在时, ...
- python2.X和python3.X在同一平台下的切换技巧
python2.X和python3.X在同一平台下的切换技巧 最近在自己的电脑上同时安装了python2.7.11和python3.5.1 在网上搜了一些答案,主要还是参照<learning p ...