《MIT 6.828 Lab 1 Exercise 4》实验报告
本实验链接:mit 6.828 lab1 Exercise 4。
题目
Exercise 4. Read about programming with pointers in C. The best reference for the C language is The C Programming Language by Brian Kernighan and Dennis Ritchie (known as 'K&R'). We recommend that students purchase this book (here is an Amazon Link) or find one of MIT's 7 copies.
Read 5.1 (Pointers and Addresses) through 5.5 (Character Pointers and Functions) in K&R. Then download the code for pointers.c, run it, and make sure you understand where all of the printed values come from. In particular, make sure you understand where the pointer addresses in printed lines 1 and 6 come from, how all the values in printed lines 2 through 4 get there, and why the values printed in line 5 are seemingly corrupted.
解答
题目包括两部分:一是阅读《The C Programming Language》,二是运行pointers.c文件并理解其输出。
一、阅读《The C Programming Language》
已阅读完成《The C Programming Language》第5.1~5.5节的内容,并输出学习笔记。
二、 运行pointers.c文件并理解其输出
void f(void)
{
int a[4];
int *b = malloc(16);
int *c;
int i;
printf("1: a = %p, b = %p, c = %p\n", a, b, c);
c = a;
for (i = 0; i < 4; i++)
a[i] = 100 + i;
c[0] = 200;
printf("2: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
a[0], a[1], a[2], a[3]);
c[1] = 300;
*(c + 2) = 301;
3[c] = 302;
printf("3: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
a[0], a[1], a[2], a[3]);
c = c + 1;
*c = 400;
printf("4: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
a[0], a[1], a[2], a[3]);
c = (int *) ((char *) c + 1);
*c = 500;
printf("5: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
a[0], a[1], a[2], a[3]);
b = (int *) a + 1;
c = (int *) ((char *) a + 1);
printf("6: a = %p, b = %p, c = %p\n", a, b, c);
}
运行前我先写出自己对6个输出的猜测,运行后发现第1和第5个输出猜错了,其他4个猜对了。
第1个输出是打印3个局部变量的地址,我以为a,b,c的内存地址是紧挨着的,因此猜测b的地址比a的大16,c的地址比b的大4.运行结果却是:
1: a = 0x7ffc06689160, b = 0x556fb6ccc260, c = 0xf0b2ff
。问题出在哪里?后来我才意识到指针的值实质上是它所指向的内存地址,而不是指针本身的内存地址。要想获取指针本身的内存地址,要在指针前面加上取址符号&。于是我对指针b和c加上&后再编译运行,结果为1: a = 0x7ffef6a4c1c0, &b = 0x7ffef6a4c1b0, &c = 0x7ffef6a4c1b8
。可见变量a,b,c的内存地址是在栈内紧挨着的。注意由于我用的是64位系统,指针是用8个字节存储。不过有个问题没想明白:定义局部变量的顺序是a -> b -> c,但在栈中的地址从小到大却是b -> c -> a,为什么不一致?有待研究。第2个输出是直接对数组元素赋值后再打印数组内容,很简单。此处的目的应该是展示最直接的访问数组元素的方式:数组名加下标。
第3个输出是使用各种方式对数组元素赋值后再打印数组内容,也很简单。值得注意的是
3[c]
的写法居然也是合法的,因为C编译器直接将其转换成*(3+c)
。第4个输出展示了:对指向数组的指针加上(或减去)N,相当于访问数组中当前元素的后面(或前面)第N个元素。
第5个输出有点意思,指针c原来指向a[1],接下来被修改为指向a[1]的第2个字节,然后再修改c的值,这时a[1]和a[2]的值都会受影响。修改前a[1]=0x00000190, a[2]=0x0000012b. 而500=0x000001f4,因此我猜测修改后a[1]=0x00000001,a[2]=0xf400012b.运行结果却是a[1]=0x0001f490, a[2]=0x00000100. 为什么?原来是字节序在作怪!我电脑是小端字节序,而我按照大端字节序来做了。
第6个输出表明指针加减某个整数对应的内存偏移量取决于指针的类型。
《MIT 6.828 Lab 1 Exercise 4》实验报告的更多相关文章
- [操作系统实验lab3]实验报告
[感受] 这次操作系统实验感觉还是比较难的,除了因为助教老师笔误引发的2个错误外,还有一些关键性的理解的地方感觉还没有很到位,这些天一直在不断地消化.理解Lab3里的内容,到现在感觉比Lab2里面所蕴 ...
- Ucore lab1实验报告
练习一 Makefile 1.1 OS镜像文件ucore.img 是如何一步步生成的? + cc kern/init/init.c + cc kern/libs/readline.c + cc ker ...
- ucore操作系统学习(三) ucore lab3虚拟内存管理分析
1. ucore lab3介绍 虚拟内存介绍 在目前的硬件体系结构中,程序要想在计算机中运行,必须先加载至物理主存中.在支持多道程序运行的系统上,我们想要让包括操作系统内核在内的各种程序能并发的执行, ...
- 《ucore lab3》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 练习1:给未被映射的地址映射上物理页 题目 完成do_pgfault(mm/vmm.c)函数,给未被映射的地址映射上物理页.设置访问权限的时候需 ...
- 《ucore lab1 exercise5》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 题目:实现函数调用堆栈跟踪函数 我们需要在lab1中完成kdebug.c中函数print_stackframe的实现,可以通过函数print_s ...
- 《ucore lab8》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 练习1: 完成读文件操作的实现(需要编码) 题目 首先了解打开文件的处理流程,然后参考本实验后续的文件读写操作的过程分析,编写在sfs_inod ...
- 《ucore lab7》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 练习1: 理解内核级信号量的实现和基于内核级信号量的哲学家就餐问题(不需要编码) 题目 完成练习0后,建议大家比较一下(可用meld等文件dif ...
- 《ucore lab6》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 练习1: 使用 Round Robin 调度算法(不需要编码) 题目 完成练习0后,建议大家比较一下(可用kdiff3等文件比较软件) 个人完成 ...
- 《ucore lab5》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 练习1: 加载应用程序并执行(需要编码) 题目 do_execv函数调用load_icode(位于kern/process/proc.c中) 来 ...
- 《ucore lab4》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 练习1:分配并初始化一个进程控制块 题目 alloc_proc函数(位于kern/process/proc.c中) 负责分配并返回一个新的str ...
随机推荐
- jvm参考(生产使用)
#4g JAVA_OPTS=-Xms3g -Xmx3g -XX:+PrintFlagsFinal -XX:+UnlockDiagnosticVMOptions -XX:NewRatio=2 -XX:P ...
- flutter布局-1-column
1.mainAxisAlignment:主轴布局方式,column主轴方向是垂直的方向 mainaxis.png 默认值:MainAxisAlignment.start: start ,沿着主轴方 ...
- linux中fork--子进程是从哪里开始运行
转自 http://blog.csdn.net/koches/article/details/7787468 fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值 ...
- MySQL数据分析-(8)SQL基础操作之库操作
前面我们讲了学习SQL的两个逻辑框架,jacky说了这样一个逻辑:库是为了存储表的,所以一定是先有库才有表:同样的道理,有表才有表中的数据,是吧,肯定是这个逻辑:那么,今天jacky就捋着这个逻辑从库 ...
- 七、find 文件查找
在文件系统上查找符合条件的文件 locate :依赖于事先构建的索引,索引的构建是在系统较为空闲时自动进行(周期性任务) 手动更新数据库(updatedb) 非实时查找 模糊查找 索引构建过程需要遍历 ...
- CF1200C
CF1200C 题意: 问内圆和外圆分别分成n.m份,每份有标号,问是否可以从一个部分走到另一个部分,12点钟位置一定有个线. 解法: 如果有一堵墙贯穿1和2,那么会使得两边不连通.这样的墙会显然出现 ...
- CF1208C
CF1208C 这场杜老师大战tourist的比赛怎么这么多人类智慧题... 题意: 构造一个 $ n \times n $ 的矩阵,使得该矩阵每一行与每一列的元素的异或和全部相等. 解法: 异或的神 ...
- open suse tumbleweed安装记录
zypper install imagewriter cmake blender fontforge gimp digikam inkscape kontact pitivi smplayer si ...
- Chisel-LLDB命令插件,让调试更Easy
http://blog.cnbluebox.com/blog/2015/03/05/chisel/ LLDB 是一个有着 REPL 的特性和 C++ ,Python 插件的开源调试器.LLDB 绑定在 ...
- hibernate-validator校验框架学习
1.引入jar包 <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate ...