[C]*和&
一 、&
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。
『完』
随机推荐
- Coding语言强弱类型且动静态类型简单解析。附图解
话不多说,上图: (以下均以Java来说明) 对于语言的强弱类型: 1.强类型语言:通俗的点来讲,就是对于数据类型,如果开发者定义了一个int数据类型的变量,那么虚拟机就会特别坚定该变量为int,坚决 ...
- 使用js请求Servlet时的路径
项目结构如下: 全是web的html页面 js部分重要代码: function ajaxValidate() { var flag=false; $.ajax({ "url":&q ...
- 二十一、Linux 进程与信号---进程资源限制
21.1 进程资源限制 在操作系统中,我们能够通过函数getrlimit().setrlimit()分别获得.设置每个进程能够创建的各种系统资源的限制使用量. 21.1.1 函数 #include & ...
- asp.net上传图片,上传图片
想必很多人工作中经常需要实现上传图片的功能. 先引用此插件 http://files.cnblogs.com/files/hmYao/jquery-form.js. 前台代码 <form dat ...
- Java SE之XML<二>XML DOM与SAX解析
[文档整理系列] Java SE之XML<二>XML DOM与SAX解析 XML编程:CRUD(Create Read Update Delete) XML解析的两种常见方式: DOM(D ...
- luogu P4931 情侣?给我烧了!
双倍经验 传送门 首先坐在一起的cp和不坐在一起的cp是相对独立的,可以分开考虑,然后方案数相乘 坐在一起的cp,方案为\(\binom{n}{k}*\binom{n}{k}*k!*2^k\).首先选 ...
- 理解position定位
使用css布局position非常重要,语法如下: position:static | relative | absolute | fixed | center | page | sticky 默认值 ...
- 数据库并发控制及SQL Server的并发控制机制
在多用户和网络环境下,数据库是一个共享资源,多个用户或应用程序同时对数据库的同一数据对象进行读写操作,这种现象称为对数据库的并发操作.显然并发操作可以充分利用系统资源,提高系统效率.虽然如此,但是如果 ...
- java导出csv文件使用Excel打开乱码问题
写一个csv文件,发现使用 notpad++ 打开是没有问题的,但是使用 Excel 打开之后显示乱码 刚开始的代码是这样子的: ByteArrayOutputStream os = new Byte ...
- whatis命令,一个非常有用的命令
比如我不知道yum的配置文件yum.conf怎么用,就可以whatis yum.conf,