对于数组名取地址强制转换的操作

偶然在晚上学了C语言指针后网页闲逛找题时,被一个数组名取地址搞糊涂了,在自己试验加探索后我稍微悟了一点东西。

代码如下:

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

这里设置了一个长度为5的数组,之后定义一个int类型的指针将对a的首地址求地址后加1然后再次强制转换成int类型的指针传递给ptr,我第一反应是a不就是代表指向首个元素的地址吗,为什么还要对它求地址另外求完地址之后+1操作再次把一个指向地址转换成指针类型给了ptr,这让我十分费解,我们先来看输出结果

输出案例1:



之后我首先删除了(int *)试着查看结果:

	int* ptr = (&a + 1);

输出案例2:



发现输出案例是没有变化了,所以说明这里强制转化实质上是没有起到任何效果的,但是对于指针的强制类型转换真的没有用吗?

探究强制转换

无论任何类型的指针都是占四个字节的,只不过指向的值的类型不同从而定义为不同的类型,所以这里的强制类型转化应该是为了抱着把数组名这个指针转化成int类型的指针。所以我又做了如下测试:

把数组a改成char类型

(忽略那个没有刷新的缺少;分号)对于int的初始化使用char,会产生警告,所以这里强制转化我们是可以理解了。

探究对于数组名取地址

在网上翻阅其他博客后查阅得知,因为数组名是一个右值,而求址运算符&是需要有具体的内存空间,也就是变量

//另外我们需要明确数组名和指针有一个区别是:数组名是符号地址常量,只是代表了数组中首个元素的地址,而没有明确的内存空间去存储它(也就是为什么不把数组名直接称为指针),在编译时求值并存在编译器的符号表里面,其值就是个内存地址,而指针是指向某一片区域,并且有一个内存空间存储这个指针,因此有了二级指针三级指针的概念,而对于数组求地址还是它自己。

所以对于数组名取地址在早期的编译器当中是非法的,但是现在是未定义的,因此我们改变代码后查看结果:

int* ptr = (int *)(a + 1);

输出案例3:



这里去掉&后得到的答案却变了,这是因为含&时,对于一个t类型的地址a将进行a+长度**运算数*sizeof(t) ,而这里不含&时,将只是简单的对于地址进行加减 运算数 操作。

加减过程

如上所说的运算过程,这里我们只需要注意一个点也就是含&时的运算

这里我们对代码进行修改供参考。

数组a的长度为5时



数组a的长度为4时



(可以看到这里地址的加减是和长度有关的)

至于和操作数和sizeof()的关系各位可以下去试一试。

------男儿何不带吴钩,收取关山五十州。

by二十岁的编程男神王大爷

搬运1:关于对C语言中数组名取地址加减等操作的一点探究的更多相关文章

  1. C语言 对数组名取地址

    作者 : 卿笃军 你有没有想过,对一个一维数组名取地址,然后用这个地址进行加减运算.这会出现什么样的结果呢? 演示样例: int a[5] = {1,2,3,4,5}; int *p = (int * ...

  2. C语言中对数组名取地址

    在C/C++中,数组名相当于一个指针,指向数组的首地址.这里“相当于”不代表等于,数组名和指针还是有很多区别的,这个在<C陷阱与缺陷>里有详尽的讲述.而这里要说的是对于数组名取地址的这么一 ...

  3. 对于C语言中数组名是指针的理解

    我们都知道,c语言中数组名是一个指针,比如下面这段代码 #include<iostream>using namespace std;int main(){ int a[4]={1,2,3, ...

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

    http://blog.csdn.net/zdcsky123/article/details/6517811 相信不少的C语言初学者都知道,数组名相当于指针,指向数组的首地址,而函数名相当于函数指针, ...

  5. 对数组名取地址 a[ ],&a

    C语言规定,数组名代表数组的首地址,也就是第0号元素的地址.所以a==&a[0] 但对数组名取地址时却要注意了,在理解“对数组名取地址”这一表达式的含义时一定要记住:数组名是“数组”这种变量的 ...

  6. 数组名取地址所算数运算应注意的&quot;trap&quot;

    数组名取地址所算数运算应注意的"trap" 直接看代码: #include <stdio.h> int main() { int array[5]; printf(&q ...

  7. 数组名和数组名取地址&

        在C中, 在几乎所有使用数组的表达式中,数组名的值是个指针常量,也就是数组第一个元素的地址. 它的类型取决于数组元素的类型: 如果它们是int类型,那么数组名的类型就是“指向int的常量指针“ ...

  8. 别人不会给你说的---C语言中数组名和指针的区别 及 sizeof用法

    引自: http://blog.csdn.net/tianyue168/article/details/5781924 #i nclude <iostream.h> int  main( ...

  9. c语言中数组名和指针变量的区别

    编译器工作原理:在64位的计算机中,当创建一个指针变量时,计算机会为它分配8个字节的存储空间.但如果创建的是数组呢?计算机会为数组分配存储空间,但不会为数组变量分配任何空间,编译器仅在出现它的地方把它 ...

随机推荐

  1. 排查dubbo接口重复注销问题,我发现了一个巧妙的设计

    背景 我在公司内负责自研的dubbo注册中心相关工作,群里经常接到业务方反馈dubbo接口注销报错.经排查,确定是同一个接口调用了两次注销接口导致,由于我们的注册中心注销接口不能重复调用,调用第二次会 ...

  2. Java-SpringBoot整合SpringCloud

    SpringBoot整合SpringCloud 1. SpringCloud特点 SpringCloud专注于为典型的用例和扩展机制提供良好的开箱即用体验,以涵盖其他情况: 分布式/版本化配置 服务注 ...

  3. 如何解决浮动元素高度塌陷---CSS

    解决高度塌陷问题的方法: 方法一. //给父元素添加声明 overflow:hidden; 缺点:回隐藏溢出的元素: 方法二. 在浮动的元素下添加空div标签,并给该元素添加声明: clear:bot ...

  4. PHP的switch和ifelse谁更快?

    对于多个if条件判断的情况下,我们使用switch来代替ifelse对于代码来说会更加的清晰明了,那么他们的效率对比呢?从PHP手册中发现有人已经对比过了,自己也用他的代码进行了实验: $s = ti ...

  5. javascript 享元模式 flyweight

    * 适应条件 ** 一个程序中使用了大量的相似对象 造成大的内存开销 ** 对象的大多数状态都可以变为外部状态 ** 剥离出对象的外部状态之后, 可以使用相对较少的共享对象取代大量对象 * 上传文件的 ...

  6. python接口自动化--json解析神器jsonpath

    前言 做接口测试的时候,大部分情况下返回的是json数据,我们需要对返回的json断言. 当返回的数据量比较大,并且嵌套的层级很深的时候,很多小伙伴不会取值,往往在返回结果取值上浪费很多时间.一直在寻 ...

  7. Winform 实现图片轮播(解决Image.FromFile内存不足)

    前言 最近项目中需要在winform中做一个类似于网页那种轮播的效果,这里做下记录. 实现 整体的实现思路如下: 读取图片文件夹. 建立一个集合存储Image对象. 定时器定时更换PictrueBox ...

  8. aizhan查询旁IP网站脚本

    <?php print_r("-------------------------\r\n"); print_r("-------爱站旁站查询------\r\n&q ...

  9. CI/CD-企业级DevOps

    CI/CD-企业级DevOps 什么是DevOps? DevOps是一种思想或方法论,它涵盖开发.测试.运维的整个过程! DevOps强调软件开发人员与软件测试.软件运维.质量保障(QA) 部门之间有 ...

  10. NOI 2017 Day1 题解

    被虐爆了... T1 整数 题目传送门 Description 有一个整数 \(x\),有 \(n\) 此操作,每次操作为以下两种情况: 给出 \(a,b\),将 \(x\) 加上 \(a\times ...