一 、&

c的&被称为“寻址运算符”,作用是指向某变量的指针;

请看以下代码:

int main(void){

	int int_1 = 16;
printf("%d\n", int_1);
printf("%p\n", &int_1);
return 0;
}

输出的第一行会输出变量int_1的值,即16.

第二行会输出变量int_1的内存地址,即0x7ffd2fb152dc;

二 、*

*被称为“间接访问操作符”,作用是访问指针的变量指向的内容(因为指针的变量保存的是一个内存地址);

请看以下代码:

int main(void){

	int *int_2;
*int_2 = 32;
printf("%p\n", int_2);
printf("%d\n", *int_2);
return 0;
}

代码的第一行声明了一个int类型的指针(如果你不明白什么是指针,请先参考一下c语言指针的相关介绍文章).

第二行实际上是,运用*访问了这个指针指向的内存空间,给这个这个指针指向的内存空间赋值了32,理论上这两个操作同等于

int int_2 = 32;

此时你回头看看&,可能会发觉这两个操作符颇有一对反义词的味道;

再来看看输出了什么,

输出的第一行输出了int_2的值,因为int_2是一个指针,它的值就是一个内存地址,所以这里输出了一个内存地址

第二行运用了*操作符,输出了这个指针指向的变量,即32

三 、 进阶

我们来创建一个多维数组,叫做int_3

int int_3[3][3] = {
{-2 ,-1, 0},
{1 ,2, 3},
{4 ,5, 6}
};

如果你对c语言的数组有所了解,你肯定知道int_3,或者int_3[x],x是一个指针偏移量,它的意思是,基于原指针指向内存区域的长度n,内存地址偏移x*n个byte.(如果你不了解这个,不要紧,先看看『c语言入门经典』这本书,我也是看这本学的c).

要进一步了解,请看看以下代码:

int int_4 = {-2 ,-1, 0};
printf("%d\n", *(int_4+1));

它的意思类似于,指针int_4偏移1个量(实际上内存地址偏移了4个byte,因为它是一个int类型的数组)并输出这个指针指向的结果,这里是-1;

如果我们现在尝试把这个语法运用于多维数组int_3,看看会有什么有趣的事情发生:

printf("%p\n", *(int_3+1));

没错,这里输出了一个内存地址,它实际上是多维数组里面的sub数组的指针,

*(int_3)或者说是*int_3,是数组{-2 ,-1, 0};
*(int_3+1),是数组{1 ,2, 3};
*(int_3+2),是数组{4 ,5, 6};

但是这个指针跟指针变量会有一点点区别

printf("%p\n", *(int_3+2));
printf("%p\n", &(*(int_3+2)));

上面两条语句,会输出同一个地址,因为*(int_3+2)不是指针变量,它本身就是一个内存地址,而之指针变量实际上也是变量,只是这个变量保存了一个指针(内存地址)

int *Pint_3 = (int*)int_3;
printf("%p\n", Pint_3); //输出0x7fffd68ca700
printf("%p\n", int_3); //输出0x7fffd68ca700
printf("%p\n", &(Pint_3)); //输出0x7fffd68ca6f8

这里我们新建一个指针变量,并把它指向了int_3,用&地址访问符可以直接输出这个指针变量的地址

如何访问sub数组里面的item?我想你已经猜到了:

printf("%d\n", *(*(int_3+2)+2) );

*(*(int_3+2)+2)实际上跟int_3[2][2]是等价操作,这里自然就输出了6;

自然地,我们利用寻址运算符&就可以轻易的输出6所在的内存地址

printf("%p\n", &(*(*(int_3+2)+2)));

当然,这里的等价操作是&int_3[2][2].

我们尝试强行解析一番这个操作都经历了什么:

1.&(*(*(int_3+2)+2))

  int_3指针偏移了2个量,由于int_3的指针变量长度是12(3*4byte),实际上就是偏移了24(12*2)byte,此时指针指向了{4 ,5, 6}这个数组,实际上这个指针指向的地址不仅指向了这个数组,而且还指向了这个数组里面的4这个元素,但是int_3+2跟*(int_3+2)不是同一个指针!!!,因为他们的内存区块长度不一样,这导致了当你使用指针偏移量语法时(int_3+2)+2和*(int_3+2)+2明显不会一样(int_3+2)+2同等于int_3+4,而*(int_3+2)+2则是取int_3+2指向的内存地址保存的那个指针再偏移2哦

//输出数组的地址
printf("%p\n", int_3+2);
//输出数组的第一个元素
printf("%d\n", *(*(int_3+2)));

2.&(*(*(int_3+2)+2))

  输出int_3+2实际的值,因为int_3+2是一个指针,所以这里输出了一个指针,这个指针的类型是int数组,所以变量长度是4(1*4byte)。

3.&(*(*(int_3+2)+2))

  *(int_3+2)便宜了2个量,实际上就是偏移了8(2*4)byte,此时指针指向了6这个元素。

4.&(*(*(int_3+2)+2))

  输出*(int_3+2)+2实际的值,也就是6。

5.&(*(*(int_3+2)+2))

  输出6的内存引用地址,实际上同等于*(int_3+2)+2。

『完』

随机推荐

  1. HTTP 错误 500.21 - Internal Server Error 处理程序“WebServiceHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPipelineHandler”

    解决方案是 解决方案:只需要重新安装一下就可以了.在Frameworv4.0的目录中安装的程序以管理员权限重新运行一下就可以了. %windir%\Microsoft.NET\Framework\v4 ...

  2. 我的长大app开发教程第三弹:实现四个子页面绑定RadioButton

    在开始之前先上一张图 在上一节中我们实现了底部Button,这一弹我们要实现点击四个按钮分别切换到不同页面,我们可以把页面分为两部分,顶部栏和中间内容部分,我们可以通过线性布局包裹两部分内容,顶部栏又 ...

  3. Vue 限制input输入 限数字 或 小数点后两位number

    Vue 限制input输入 小数点后两位number <input type="number" @keydown="handleInput2" place ...

  4. Ext.net获取选中行数据

    两种方法 1.直接返回对象列表 <DirectEvents> <Click> <ExtraParams> <ext:Prameter Name="V ...

  5. Sqlserver远程过程调用失败

    这种情况一般是由于有高版本的SqlServer导致的,网上有删除Loaldb之类的建议,这样其实不太好,回头用高版本数据库的话还得装回来.其实可以通过计算机管理->服务和应用程序进行设置,用下面 ...

  6. vs2013 配置支持https的libcurl

    需求:在vs2013上配置支持https协议的libcurl. 环境:win7(64位),vs2013 一.安装openssl: 需要先安装nasm和ActivePerl. nasm需要手动配置环境变 ...

  7. 数据库范式:1NF,2NF,3NF,BCNF浅析

    在设计与操作维护数据库时,最关键的问题就是要确保数据能够正确地分布到数据库的表中.使用正确的数据结构,不仅有助于对数据库进行相应的存取操作,还可以极大地简化应用程序中的其他内容(查询.窗体.报表.代码 ...

  8. Debian Security Advisory(Debian安全报告) DSA-4414-1 libapache2-mod-auth-mellon security update

    Debian Security Advisory(Debian安全报告) DSA-4414-1 libapache2-mod-auth-mellon security update Package:l ...

  9. jdk环境配置以及java执行过程

    下载好jdk,并按照提示一步步安装,最后记下jdk所在的安装位置,这里假设在C:\Program Files (x86)\Java\jdk1.8.0_20 现在开始配置环境变量.鼠标右键点击“计算机” ...

  10. Kaldi中的Chain模型

    Chain模型的训练流程 链式模型的训练过程是MMI的无网格的版本,从音素级解码图生成HMM,对其使用前向后向算法,获得分母状态后验,通过类似的方式计算分子状态后验,但限于对应于转录的序列. 对于神经 ...