C语言的数组名和对数组名取地址

***************************************************

更多精彩,欢迎进入:http://shop115376623.taobao.com

***************************************************


相信不少的C语言初学者都知道,数组名相当于指针,指向数组的首地址,而函数名相当于函数指针,指向函数的入口地址。

现在有这样一个问题,如果对数组名取地址,那得到的会是什么呢?很多人立刻会想到:给指针取地址,就是指针的指针,

即二级指针嘛!当然这样的结论是错误的,不然这篇笔记也就没有意义了。


下面我们来逐步分析,下面是一段验证这个问题的代码

Code:
  1. #include<stdio.h>   
  2. int main()   
  3. {   
  4.     int a[10];   
  5.   
  6.     printf("a:/t%p/n", a);            
  7.     printf("&a:/t%p/n", &a);          
  8.     printf("a+1:/t%p/n", a+1);        
  9.     printf("&a+1:/t%p/n", &a+1);     
  10.   
  11.     return 0;   
  12. }  

 

大家可以编译运行一下,我的输出的结果是:

Code:
  1. /*   
  2. a:          0012FF20  
  3. &a:         0012FF20  
  4. a+1:        0012FF24  
  5. &a+1:       0012FF48  
  6. */  

a和&a指向的是同一块地址,但他们+1后的效果不同,a+1是一个元素的内存大小(增加4),而&a+1增加的是整个数组的内存

大小(增加40)。既a和&a的指向和&a[0]是相同的,但性质不同!

读到这里,有很多朋友已经明白其中的机制了,如果还是有些模糊,请继续往下看

Code:
  1. int main()   
  2. {   
  3.     int a[10];   
  4.     printf("%d/n",sizeof(a));   
  5.     return 0;   
  6. }  

这段代码会输出整个数组的内存大小,而不是首元素的大小,由此我们是否联系到,sizeof(a)这里的a和
&a有些相同之处呢?!  是的,没错,&a取都得是整个数组的地址!既数组名取地址等价于对数组取地址。


好了,让我们总结一下,如果你还是不太理解,不用担心,下面的概念很清晰


其实a和 &a结果都是数组的首地址,但他们的类型是不一样。
a表示&a[0],也即对数组首元素取地址,a+1表示首地址+sizeof(元素类型)。
&a虽然值为数组首元素地址,但类型为:类型 (*)[数组元素个数],所以&a+1大小为:首地址+sizeof(a)。


还有这篇文章最初提到的指针的指针的那个错误结论,其实即使不懂上述内容,也应该判断出结论是错误的,大家应该在了解数组名

即是数组的首地址的同时,也要知道,数组名仅仅是“相当”于指针,而并非真的是指针,数组名是只是个常量(一个值为数组首元素

地址的常量),所以不能进行++或者--运算。而常量更是无法取地址的,而之所以有&a,其实这里的a的意义早已经不是当初那个数组

名了,它此时代表了整个数组。





C语言数组首地址和数组名取地址区别
2010年11月24日 11:51

申明:本文系原创,转载时请注明出处,本人保留追究责任的权利。

原文地址:http://hi.baidu.com/surfmygod/blog/item/53d44914cdb8a5d6a7ef3f13.html


本文适用于机器为32位,编译器为VC6.0

先来看下面一个例子:
main()
{
int a[5]={0x11121314,0x21222324,0x31323334,0x41424344,0x51525354};
int *ptr1=(int *)(&a+1);
int *ptr2=(int *)(a+1);
printf("%x,%x",ptr1[-1],*ptr2);
getch();
}
打印输出的结果是多少?第4行&a是不是写错了?数组名怎么还取地址呢?
你可以试着在软件中编译运行一下,结果是51525354,21222324,没错,就是它了。你可以试着写以下程序
再在计算机中编译运行下:

main()

{

int a[5]={0x11121314,0x21222324,0x31323334,0x41424344,0x51525354};

printf("%p\n%p\n",a,&a);

printf("%d\n%d\n",sizeof(a),sizeof(&a));

printf("%p\n%p",&a+1,a+1);

getch();

}

你可以看到前两行a和&a打印的结果是一样的(比如0012FF6C),后两行的结果是都是20,而&a+1的结果是0012FF6C,

即a的起始地址后移20字节。看到这里对于a和&a的区别是不是有些眉目了?不错,a和&a的值虽然一样,但是前者表示

的是数组a的首地址,进阶为数组元素长度,而后者也是表示数组a的首地址(或许有些人不同意我这个观点,对地址

取地址应该是指向指针的指针呀。不过你注意了没有,a和&a值是一样的,试想如果这里表示的是指向指针的指针,

那么a的地址和指向a的指针的地址可能一样么?

两个指针都指向数组首地址,怎么会是指向指针的指针?还有一点需要强调,对一个指针进行sizeof运算,32位系统

下应该得到4,而对数组名进行sizeof运算得到的结果却是20,这说明了什么?很显然,数组名虽然能够拿出来代表

一个地址,但是它和指针还是有区别的,对它进行sizeof运算也不会得到指针的大小。不信?你可以试试sizeof(&a[0])

和sizeof(a),看看结果是不是相同),

但是是将整个数组作为一个对象来看待的,进阶为整个数组长度。也就是说,a和&a虽然值相同,但是a是将所有数组

元素看成一个个不同的个体来对待的,而&a是将整个数组作为一个整体来对待的。这里要强调的是,a+1和&a[1]其实

是一样的,都是代表a数组向后偏移一个元素的地址,你可以再用sizeof关键字打印一下两个的值。但是a和&a[0]的

意义相同么?若打印地址的话,两者确实是一样的,但是你也用sizeof打印下两者,一样么?再试试a+0呢?很显然,

a和a+0是有区别的,但是a+0和&a[0]是含义相同的。所以,你可以说a+i和&a[i]含义相同,但是绝不能说a和&a[0]

或a+0含义相同。所以&a+1后移20位为&a+sizeof(&a),而a+1却是a+sizeof(a[i])。

(《C语言深度解剖》认为在32为系统下sizeof(&a)的值仍为4,我觉得是不对的。他觉得是VC6.0错了,其实不止VC,

其他很多编译器得到的结果也不会是4,这说明a和&a在C中本来就不是作为指针来用的,只是具有指针的部分性质而已。)



ptr1是将&a+1强转为int类型指针,此时打印ptr1[-1]即将ptr指针前移sizeof(int)个字节,故打印结果是5。

这样一来后面的也明了了,a+1的值为在数组a的首地址上后移sizeof(int)个字节,然后强转为int类型指针

(其实强转并没有改变什么,原来类型即为整型指针,可以去掉强转),最后输出结果为21222324。


再想一下,如果将第一例第五行改为int *ptr2=(int *)((int)a+1);打印结果会是什么?

这里要考虑数据在计算机中的存储模式:大端模式和小端模式。解释一下:

大端模式(Big_endian):字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中。
小端模式(Little_endian):字数据的高字节存储在高地址中,而字数据的低字节则存放在低地址中。

在大端模式下,a在计算机中存储如下(从低地址到高地址,一个十六进制数代表内存的一个字节,下同):
0x11 0x12 0x13 0x14 0x21 0x22 0x23 0x24 0x31 0x32 0x33 0x34 0x41 0x42 0x43 0x44 0x51 0x52 0x53 0x54

在小端模式下,a在计算机中存储如下:
0x14 0x13 0x12 0x11 0x24 0x23 0x22 0x21 0x34 0x33 0x32 0x31 0x44 0x43 0x42 0x41 0x54 0x53 0x52 0x51

(int)a表示将a的首地址强转为整型数据(若原来是0012FF6C,转换后仍为0012FF6C,但是这时已经不是表示地址而是一个
十六进制整型数了),这时+1代表整型数(int)a加1(变为0012FF6D),再把结果强转为整形指针,故指向的数据地址为0012FF6D,
即上述存储去的第二个字节开始处。此时输出*ptr2,即输出a数组存储区中第二到第五字节组成的一个整型数,若为大端模式则输出
12131421,若为小端模式则输出24111213。



补充说明下,在vc6.0上,上面sizeof(&a)才是20,而在GCC ,以及之后的vc版本(如vs2005及之后版本)则是将&a完全视作一个指针,sizeof(&a)为4 (32位机器)



二维数组名问题 
转自:  http://zhidao.baidu.com/question/386658092.html

int  *p1[3],     (*p2)[2], ** p,    a[3][2];a) p1=a;是否语法正确?  b)  p2=a;呢? ?  为什么?请详述原因。        c)  p=a;  是否正确???可不可以认为二维数组名是一个指向指针的指针变量?  
 
 
 
a)不正确!p1是指针数组,他的元素是指针,但是他是数组,数组名不可以写在赋值号左边。b)正确!p2是数组指针,他可以指向一个数组。在这里他可以指向一个包含2个元素的数组。而二维数组的本质是指针数组,每个元素是一个 数组指针(这点是核心)。a[3][2] 的实质是:一个有3个元素的数组,每个元素是数组指针,该指针指向一个含有2个元素的数组(因为内存是个大的1维数组,所有东西在内存里都是1维数组)。#include <stdio.h>int main(void){    int (*p1)[2];    int a[3][2];    p1=a;    printf("%p, %p\n",p1+2,a+2);    while(1);    return 0;}以上程序可以说明b是正确的。c:不正确!如果你做p++那么p的值只增加了4(一个指针大小),而不是增加8(一个 p[2] 大小) 
 
 
其他网址: http://topic.csdn.net/u/20100106/15/e5fa8fa6-555e-4729-a435-d1f8fdac5612.html



示例程序:

 #if 1

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



int main()
{
int a[] = {1,2,3,4,5};
int *p1 = (int *)(a+1);
int *p2 = (int *)(&a+1); 
int *p3 = (int *)((int)a + 1);
int *p4 = a; 
printf("a is %p \n",a);
printf("&a is %p \n",&a);
printf("sizeof(a) = %d\n",sizeof(a));
printf("sizeof(&a) = %d\n",sizeof(&a));
printf("sizeof(p4) = %d \n",sizeof(p4)); 
printf("p1 = %p \n",p1);
printf("p2 = %p \n",p2);
printf("*p1 = %d\n",*p1);
printf("p2[-1] = %d\n",p2[-1]);
printf("*p3 = %d \n",*p3);
printf("*(p2-1) = %d \n",*(p2-1));
        
    system("PAUSE");
    return 0;
}

#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/458843.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小米 android 8,小米华为们谁最良心?10大手机厂商安卓8.0升级情况盘点

3月8日&#xff0c;谷歌放出了首个安卓9.0开发者预览版的固件包&#xff0c;不出意外的话&#xff0c;它的正式版会在今年正式亮相。但对广大安卓用户来说&#xff0c;想要立刻用上最新系统并非易事。目前来说&#xff0c;安卓碎片化问题依然严重&#xff0c;我们不妨现实点&am…

窥探Swift之数组安全索引与数组切片

在Swift中的数组和字典中下标是非常常见的&#xff0c;数组可以通过索引下标进行元素的查询&#xff0c;字典可以通过键下标来获取相应的值。在使用数组时&#xff0c;一个常见的致命错误就是数组越界。如果在你的应用程序中数组越界了&#xff0c;那么对不起&#xff0c;如果由…

大小端模式的快速判断方法

*************************************************** 更多精彩&#xff0c;欢迎进入&#xff1a;http://shop115376623.taobao.com *************************************************** 大小端的问题剖析&#xff1a; 嵌 入式系统开发者应该对Little-endian和Big-endian模…

【RAC】How to Proceed from Failed 11gR2 CRS Installation

Applies to: [ID 942166.1] Oracle Server – Enterprise Edition – Version: 11.2.0.1 to 11.2.0.2 – Release: 11.2 to 11.2 Generic UNIX Generic Linux Goal This goal of this note is to provide steps to proceed from failed 11gR2 Grid Infrastructure installat…

WinForm支持拖拽效果

有一个MSDN客户提问在WinForm中如何实现拖拽效果——比如在WinForm中有一个Button&#xff0c;我要实现的效果是拖拽这个Button到目标位置后生成一个该控件的副本。 其实这个操作主要分成三步走&#xff1a; 1&#xff09;确定被拖拽的对象&#xff1a; 这里是Button&#xff0…

win7 64位出现桌面右键鼠标显示忙碌

*************************************************** 更多精彩&#xff0c;欢迎进入&#xff1a;http://shop115376623.taobao.com *************************************************** 将下面绿色内容复制到txt文本中&#xff0c;然后另存为1.bat 双击运行即可 【针对64位…

android tee,Android 9.0的新增安全特性与TEE

Android P&#xff0c;预计将于 2018 年第三季度发布最终版本。特别是Android8.0以来&#xff0c;安全性是Android版本变更的一个重要因素。从安全性增强方面来看&#xff0c;本次Android9.0版本主要有以下几个方面&#xff1a;统一的指纹身份验证对话框Android P 中&#xff0…

哪些要素会让咱们呈现抑郁症的病症

依据最新研讨标明&#xff0c;一自个的性情怎样&#xff0c;本来是天然生成的&#xff0c;后天的日子&#xff0c;仅仅对咱们的性情进行批改&#xff0c;但在咱们潜意识中&#xff0c;违反自个性情的行动&#xff0c;会让咱们感到格外累&#xff0c;所以&#xff0c;不少人即是…

如何定义一个只能在堆上(栈上)生成对象的类?

在C中&#xff0c;类的对象建立分为两种&#xff0c;一种是静态建立&#xff0c;如A a&#xff1b;另一种是动态建立&#xff0c;如A* ptrnew A&#xff1b;这两种方式是有区别的。 静态建立一个类对象&#xff0c;是由编译器为对象在栈空间中分配内存&#xff0c;是通过直接移…

canny算子的理论分析

****************************************************************************************************************************************** 红&#xff1a;数字图像处理视频教程&#xff08;两部&#xff09; {中科院版36讲视频教程 电子科大版70讲视频教程&#x…

Android为spinner设置适配器,Android Spinner与适配器模式详解及实例代码

最近做项目对Android Spinner 使用&#xff0c;这里简单写个小例子&#xff0c;来测试如何使用。Spinner是一个下拉列表&#xff0c;往安卓界面中拖拽一个Spinner控件&#xff0c;在属性中设置Android:entries“array/spinner_data”其中spinner_data为在string中设置的数组。数…

web框架-Struts开始

问题&#xff1a; 为什么有structs 作为一种框架&#xff08;frameset&#xff09;可以与传统的mvc进行比较&#xff1f; MVC是一种模式数据处理、显示和数据输入分开&#xff0c;来规范开发&#xff0c;但是却又并不规范。可以这样想&#xff1a;有三家公司&#xff0c;他们对…

加快上架方法

估计最近苹果app应用上架的比较多&#xff0c;审核比较慢&#xff0c;现在一个app从提交到上架短则7&#xff0c;8天&#xff0c;长则2&#xff0c;3个星期。我在实际上线应用时&#xff0c;总结了一个简单实用的小技巧&#xff0c;可以加快上架时间&#xff0c;最近使用这种方…

接口自动化测试 返回html,接口自动化测试实战(更新完毕)

前言自动化没练习的项目怎么办&#xff1f;自动化已经成为测试的必备技能之一了&#xff0c;所以&#xff0c;很多想跳槽的测试朋友都在自学&#xff0c;特别是最实用的接口自动化&#xff0c;但是很多人因为没有可以练手的项目而苦恼&#xff0c;最终导致缺乏实战经验&#xf…

Opencv 图像增强算法 图像检测结果及代码

****************************************************************************************************************************************** 红&#xff1a;数字图像处理视频教程&#xff08;两部&#xff09; {中科院版36讲视频教程 电子科大版70讲视频教程&#x…

php Hash Table(四) Hash Table添加和更新元素

HashTable添加和更新的函数&#xff1a; 有4个主要的函数用于插入和更新HashTable的数据: int zend_hash_add(HashTable *ht, char *arKey, uint nKeyLen,void **pData, uint nDataSize, void *pDest); int zend_hash_update(HashTable *ht, char *arKey, uint nKeyLen, void …

山寨“饿了么”应用中添加菜品数量按钮效果

山寨“饿了么”应用中添加菜品数量按钮效果 本人视频教程系类 iOS中CALayer的使用 最终效果&#xff1a; 山寨源头&#xff1a; 源码&#xff1a;&#xff08;此源码解决了重用问题&#xff0c;可以放心的放在cell中使用&#xff09; AddAndDeleteButton.h 与 AddAndDeleteBu…

html间数据传送,Express框架与html之间如何进行数据传递(示例代码)

关于Node.js 的Express框架介绍&#xff0c;推荐看菜鸟教程的Express框架&#xff0c;很适合入门&#xff0c;这里不再赘述&#xff0c;这里主要讲一下Express框架与html之间如何进行数据传递我采用的是JQuery的Ajax()向后台传参方式(url传参)1、Type属性为Get时&#xff1a;(1…

数字图像去噪典型算法及matlab实现

图像去噪是数字图像处理中的重要环节和步骤。去噪效果的好坏直接影响到后续的图像处理工作如图像分割、边缘检测等。图像信号在产生、传输过程中都可能会受到噪声的污染&#xff0c;一般数字图像系统中的常见噪声主要有&#xff1a;高斯噪声&#xff08;主要由阻性元器件内部产…

pat1100. Mars Numbers (20)

1100. Mars Numbers (20) 时间限制400 ms内存限制65536 kB代码长度限制16000 B判题程序Standard 作者CHEN, YuePeople on Mars count their numbers with base 13: Zero on Earth is called "tret" on Mars.The numbers 1 to 12 on Earch is called "jan, feb, …