理解C指针: 一个内存地址对应着一个值
一个内存地址存着一个对应的值,这是比较容易理解的。
如果程序员必须清楚地知道某块内存存着什么内容和某个内容存在哪个内存地址里了,那他们的负担可想而知。
汇编语法对“一个内存地址存着一个对应的数”,作了简单的“抽象”:把内存地址用变量名代替了,对内存地址的取值和赋值方式不变。
c语言对此进行了进一步的抽象:变量 <==> (一个内存地址,对应的值)(这里忽略类型等信息)。
把C语言中的基本类型(int,long,float等),指针,数组等还原为(一个内存地址,对应的值)后,就能更清淅地理解它们了。
内存就相当于(addr,val)的大hash表,c语句的语义基本就是改变hash值。
为了下文的方便,特定义如下语义(遵循C的标准语义):
var <==> (addr, val) (var为一个变量名,addr为var在内存中的首地址,val为var 的值)
&var <==> addr
var <==> var作为左值出现(即等式左边)时,var等价于 addr;
var作为右值出现(即等式左边)时,var等价于 val;
*var <==> val
注:符号"<==>" 右边出的等式 x = y(x是一个内存地址,y是一个值); 表示将内存地址为x的内容置为值y,如addr = 3表示置内存addr里的值为3
现在利用上面的语义解释一下这些例子:
int i = 3;
假设 i的内存地址为 0x8049320 ,那么这句话的语义是0x8049320 = 3,经过i = 3后,i为(0x8049320,3)
int b = i;
假设 b的内存地址为 0x8049324 ,那么这句话的语义是0x8049324 = i对应的val = 3,此时b为(0x8049324,3)
int *p = &b
指针p也是一个变量,int **p,int *p[8],在这些申明中p都只是一个指针变量,它和其他的变量的不同之处在于它的大小是定的,它的类型信息只是编译器用来进行类型检查和其他一些作用的(如果没有类型检查,你可以用任何的方式对一个变量进行操作如int i; ****i = 3)。假设p的地址为0x8049328,则根据p = &b的语义p.addr = b.addr,p为(0x8049328,0x8049324)
*p = 5;
语义为 0x8049324 = 5,此时只改变了内存地址为0x8049324的值,即改变了b的值(0x8049324,5),而p的值并未改变
int **q = &p; //如果写为int **q = &&i; gcc编译不通过
假设q的内存地址为0x8049330,语义为 0x8049330 = addr(p) = 0x8049328;所以q为(0x8049330, 0x8049328)
(int **q = &&i, 要是编译过了则q应该表示为(0x8049330, x),内存地址为x的地方表示为(x,0x8049320),那么地址x为多少呢? )
**q = 6
语义为 val(val(q)) = val(0x8049328) = 0x8049324 = 6,将内存地址为0x8049324的内容置为6,即将b的值置为6,b为(0x8049324,6)
对于结构,这些语义也适用,因为结构里的成员也是有对应地址的,也能表示为(addr,val)的形式。
对“一个内存地址存着一个对应的值”的抽象程度越高,越不用关心底层,如java。
Haskell已经没有副作用之说了,更不用关心这些了。
参考:http://www.cppblog.com/hex108/archive/2011/06/18/124234.html
理解C指针: 一个内存地址对应着一个值的更多相关文章
- golang中内存地址计算-根据内存地址获取下一个内存地址对应的值
package main import ( "fmt" "unsafe" ) func main() { // 根据内存地址获取下一个字节内存地址对应的值 da ...
- python获取内存地址上存储的值
在python中,可以通过id()这个方法来获取对象的内存地址. 但是反过来,怎么获取内存地址上存储的值? 先看一段代码: from ctypes import string_at from sys ...
- 13深入理解C指针之---内存管理
该系列文章源于<深入理解C指针>的阅读与理解,由于本人的见识和知识的欠缺可能有误,还望大家批评指教. 内存管理对所有程序都很重要,主要包括显式内存管理和隐式内存管理.其中隐式内存管理主要是 ...
- 15深入理解C指针之---内存释放
一.手动申请的内存,必须及时进行内存释放,否则容易造成内存泄露.主要代码形式为: #include <stdio.h> #include <stdlib.h> int main ...
- C++ 如何重复利用一个内存地址块
#include<iostream> using namespace std; ; }; int main(int argv ,char * args[]) { double *p1,*p ...
- 46深入理解C指针之---内存分析
一.size_t:用于安全表示长度,所有平台和系统都会解析成自己对应的长度 1.定义:size_t类型表示C中任何对象所能表示的最大长度,是个无符号整数:常常定义在stdio.h或stdlib.h中 ...
- C之内存地址
计算机的内存地址 * 32位系统最多能识别4G内存 * 32位系统的地址总线长度是32位的,也就是说能分配给内存地址的数字是 2的32次方个 * 内存中每一个字节都需要一个内存地址 * 一个数字对用一 ...
- c语言中通过指针将数值赋值到制定内存地址
1.一种直观的方法 假设现在需要往内存0x12ff7c地址上存入一个整型数0x100.我们怎么才能做到呢? 我们知道可以通过一个指针向其指向的内存地址写入数据,那么这里的内存地址0x12ff7c其本质 ...
- C语言内存地址基础
来源:http://blog.jobbole.com/44845/ 从计算机内存的角度思考C语言中的一切东东,是挺有帮助的.我们可以把计算机内存想象成一个字节数组,内存中每一个地址表示 1 字节.比方 ...
随机推荐
- ROC曲线手画
绘图过程很简单:给定m个正例子,n个反例子,根据学习器预测结果进行排序,先把分类阈值设为最大,使得所有例子均预测为反例,此时TPR和FPR均为0,在(0,0)处标记一个点,再将分类阈值依次设为每个样例 ...
- 通过渲染器Shader实现图像变换效果
在上一篇文章中,一起学习了通过设定画笔风格来实现图形变换,没读过的朋友可以点击下面链接: http://www.cnblogs.com/fuly550871915/p/4886455.html 是不是 ...
- 牛客网多校训练第一场 I - Substring(后缀数组 + 重复处理)
链接: https://www.nowcoder.com/acm/contest/139/I 题意: 给出一个n(1≤n≤5e4)个字符的字符串s(si ∈ {a,b,c}),求最多可以从n*(n+1 ...
- [HNOI2007]紧急疏散EVACUATE
嘟嘟嘟 看数据范围,第一反应觉得爆搜是不是能骗点分,但发现爆搜太难写了,于是就开始想想正解…… 正解大概猜到了是网络流,但是怎么把时间这个条件加入到图的内容中,却困扰了我好半天,总是感觉把这种不同维度 ...
- Codeforces Round #540 (Div. 3) C. Palindromic Matrix 【暴力】
任意门:http://codeforces.com/contest/1118/problem/C C. Palindromic Matrix time limit per test 2 seconds ...
- php函数:call_user_func
前段时间浏览文档发现一个有意思的PHP函数:call_user_func [文档地址] 函数作用:该函数主要用于通过函数名去调用该函数 例如: function test(){ echo " ...
- 11、SpringBoot-CRUD-thymeleaf公共页面元素抽取
thymeleaf公共页面元素抽取 存在一种现象:两个文件的代码只有一部分代码不一样 其余的均相同,此时就可以提取公共的代码去简化开发 .抽取公共片段 <div th:fragment=&quo ...
- 2.spring:集合属性
1.list 配置java.util.List类型的属性,需要指定<list>标签,在标签里面包含有一些元素,这些标签 可以通过<value>指定简单的常量值,通过<r ...
- 面试准备——(二)专业知识(4)C/C++语言
1. 预处理 断言 assert的功能,assert(statement),如果statement为真则程序继续执行,为假则整个程序中断退出 3. #define [ #ifndef DISKSIM_ ...
- SpringMVC使用校验validator校验对象属性
1.pom.xm添加依赖 <dependency> <groupId>javax.validation</groupId> <artifactId>va ...