《C语言深度解剖》学习笔记之指针和数组
第4章 指针和数组
1. int *p=NULL 和 *p=NULL 有什么区别
int *p = NULL;
第一句代码的意思是:定义一个指针变量p,其指向的内存里面保存的是 int类型的数据;在定义变量的同时把p的值设置为 0x00000000,而不是把 *p的值设置为 0x00000000,这个过程称为初始化,是在编译的时候进行的。
int *p;
*p = NULL;
第一行代码,定义了一个指针变量p,其指向的内存里面保存的是 int类型的数据,但是这时候p本身的是多少不得而知;第二行代码,给 *p赋值为NULL。
2.如何往内存地址 0x12ff7c 上存入一个整形数 0x100?
- 第一种方法
int *p = (int *)0x12ff7c; //p
*p = 0x100;- 第二种方法
*(int *)0x12ff7c = 0x100;
3.数组的内存布局
int a[] ;
a作为右值时,代表数组首元素的首地址,而非数组的首地址。
a[0],a[1]等为a的元素,但并非元素的名字,数组的每一个元素都是没有名字的。
sizeof(a[5])的值在32为系统下为4,为什么没有出错?
其实函数求值是在运行的时候,而sizeof求值是在编译的时候。虽然并不存在a[5]这个元素,但是这里也并没有真正访问a[5],而是仅仅根据数组元素的类型来确定其值。所以没有出错。
4.&a[0]和&a的区别
前者是数组首元素的首地址,而后者是数组的首地址。
5.数组名a作为左值和右值的区别
x = y;
左值:在这个上下文环境中,编译器认为x的含义是x所代表的地址。这个地址只有编译器知道,在编译的时候确定
右值:在这个上下文环境中。编译器认为y的含义是y所代表的地址里面的内容。这个内容运行的时候确定。
a作为右值时其意义与 &a[0] 是一样的,代表的是数组首元素的首地址,而不是数组的首地址。
a不能作为左值!编译器认为数组名作为左值代表的意思是a的首元素的首地址,但是这个地址开始的一块内存是一个总体,我们只能访问数组的某个元素,而无法把数组当成一个总体来进行访问。
6.以指针的形式访问指针和以下标的形式访问指针
char *p = "abcdef";
- 以指针的形式:*(p+4)。先取出p里面的地址值,假设为0x0000ff00,再加上4个字符的偏移量,得到新的地址0x0000ff04;然后再取出地址上的值。
- 以下标的形式:p[4]。编译器总是把下标的形式的操作解析为以指针的形式的操作。先取出p里存储的地址值;再加上4个元素的偏移量,计算出新的地址;然后再从新的地址中取出值。
7.以指针的形式访问数组和以下标的形式访问数组
对a的元素的访问必须先根据数组的名字a找到数组首元素的首地址,然后再根据偏移量找到相应的值。这是一种典型的“具名 + 匿名”的访问。
8.指针数组和数组指针
指针数组:储存指针的数组
数组指针:指向数组的指针
int *p1[]; //指针数组
p1先与“[]”结合,构成一个数组的定义,数组名为p1,int *修饰的是数组里的每个元素。也就是说,这是一个数组,其包含10个指向int类型数据的指针,即指针数组
int (*p2)[]; //数组指针
“*”和p2构成一个指针的定义,指针变量名为p2,int修饰的是数组的内容。数组在这里没有名字,是个匿名数组。也就是说,p2是一个指针,它指向一个包含10个int类型数据的数组,即数组指针。
9.再论a和&a之间的区别
int main()
{
char a[] = {'A','B','C','D'};
char (* p3)[] = &a;
char (* p4)[] = a;
return ;
}
编译器会给出警告。因为p4这个定义“=”两边的的数据类型不一致。左边的数据类型是指向整个数组的指针,右边的数据类型是指向单个字符的指针。
10.地址的强制转换
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[];
short sBa[];
}*p;
假设p的值为0x100000,那么
p + 0x1 = 0x100014
(unsigned long)p + 0x1 =0x100001
(unsigned int *)p + 0x1 = 0x100004
第一个表达式p + 0x1的值为 0x100000+sizeof(Test)*0x1。Test的大小为20字节
第二个表达式其实就是一个无符号的长整数加上另一个整数
第三个表达式的p被强制转换为指向无符号整型的指针
11.数组参数和指针参数
C语言中,当一维数组作为函数参数的时候,编译器总是把它解析成一个指向其首元素首地址的指针。
函数的返回值也不能是一个数组,而只能是指针。
void fun(char *p)
{
char c = p[];
}
void fun(char a[])
{
char c = a[];
}
两组代码等效,但第二个形式较好。
main函数内的变量不是全局变量,而是局部变量,只不过它的生命周期和全局变量一样长而已。全局变量一定是定义在函数外部的。
11.二维数组参数和二级指针参数
C语言中,当一维数组作为函数参数的时候,编译器总是把它解析成一个指向其首元素首地址的指针。所以下面两个函数声明是一样的:
void fun(char a[3][4]),void fun(char a[][4]) 和 void fun(char (*p)[4])
void fun(char *p[4])和void fun(char **p) 这是因为*p[4]是一个包含4个指针的一位数组,把这个一位数组也写成指针的形式,就得到第二种写法。
12.函数指针
函数指针就是函数的指针,它是一个指针,指向一个函数。
char * fun1(char * p1,char * p2);
fun1是函数名,p1,p2是参数,其类型为char *类型,函数的返回值是char *
char * * fun2(char * p1,char * p2);
与上例唯一不同的是,函数返回值类型为 char **
char * (* fun3)(char * p1,char * p2);
fun3是一个指针变量,它指向一个函数。这个函数有两个指针类型的参数,函数的返回值也是一个指针。
13.函数指针的例子
#include<stdio.h>
char * fun(char * p1,char * p2)
{
}
int main()
{
char * (* pf)(char * p1,char * p2);
pf = &fun;
(* pf)("aa","bb");
return ;
}
给函数指针赋值时,可以用&fun或字节使用函数名fun。
14. *(int *)&p
void fun()
{
}
int main()
{
void (* p)();
*(int *)&p = (int)fun;
(*p)();
return ;
}
void (* p)();这行代码定义了一个指针变量p,p指向一个函数,这个函数的参数和返回值都是void。
&p求指针变量p本身的地址。
(int)fun表示将函数的入口地址转换成指向int类型的指针
*(int *)&p = (int)fun;表示将函数的入口地址赋值给指针变量p
(*p)()就是对函数的调用。
15.(*(void(*)())0)()
void(*)(),这是一个函数指针类型
(void(*)())0,将0强制转换为函数指针类型。
(*(void(*)())0),取0地址开始的一段内存内存里面的内容,其内容就是保存在首地址为0的一段区域内的函数
(*(void(*)())0)(),函数的调用
16.函数指针数组
char * (*pf[])(char *p);
这里定义了一个函数指针数组。它是一个数组,数组名为pf,数组内存储了3个指向函数的指针,这些指针指向一些返回值类型为指向字符的指针,参数为一个指向字符的指针的函数。
17.函数指针数组指针
char * (*(*pf)[])(char * p)
这里的函数指针数组指针不就是一个指针嘛。只不过这个指针指向一个数组,这个数组里面存的是指向函数的指针。
《C语言深度解剖》学习笔记之指针和数组的更多相关文章
- C语言深度解剖读书笔记
开始本节学习笔记之前,先说几句题外话.其实对于C语言深度解剖这本书来说,看完了有一段时间了,一直没有时间来写这篇博客.正巧还刚刚看完了国嵌唐老师的C语言视频,觉得两者是异曲同工,所以就把两者一起记录下 ...
- C语言深度解剖读书笔记(6.函数的核心)
对于本节的函数内容其实就没什么难点了,但是对于函数这节又涉及到了顺序点的问题,我觉得可以还是忽略吧. 本节知识点: 1.函数中的顺序点:f(k,k++); 这样的问题大多跟编译器有关,不要去刻意追求 ...
- 【转】 C语言深度解剖读书笔记(1.关键字的秘密)
本文出处:http://blog.csdn.net/mbh_1991/article/details/10149805 开始本节学习笔记之前,先说几句题外话.其实对于C语言深度解剖这本书来说,看完了有 ...
- c语言深度解剖(笔记)
1.1最宽恒大量的关键字----auto 函数内部变量,限制作用域为这个 1.2.1最快的关键字---- register函数. 关键字请求编译器尽可能的将变量存在 CPU 内部寄存器中 1.2.2使 ...
- R语言与机器学习学习笔记
人工神经网络(ANN),简称神经网络,是一种模仿生物神经网络的结构和功能的数学模型或计算模型.神经网络由大量的人工神经元联结进行计算.大多数情况下人工神经网络能在外界信息的基础上改变内部结构,是一种自 ...
- go语言,golang学习笔记4 用beego跑一个web应用
go语言,golang学习笔记4 用beego跑一个web应用 首页 - beego: 简约 & 强大并存的 Go 应用框架https://beego.me/ 更新的命令是加个 -u 参数,g ...
- go语言,golang学习笔记3 用命令下载框架报错问题解决 设置环境变量
go语言,golang学习笔记3 用命令下载框架报错问题解决 设置环境变量 下载安装:go get github.com/astaxie/beego 首页 - beego: 简约 & 强大并存 ...
- go语言,golang学习笔记2 web框架选择
go语言,golang学习笔记2 web框架选择 用什么go web框架比较好呢?能不能推荐个中文资料多的web框架呢? beego框架用的人最多,中文资料最多 首页 - beego: 简约 & ...
- go语言,golang学习笔记1 官网下载安装,中文社区,开发工具LiteIDE
go语言,golang学习笔记1 官网下载安装,中文社区,开发工具LiteIDE Go语言是谷歌2009发布的专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速 ...
随机推荐
- beego 批量删除问题
o := orm.NewOrm() qs := o.QueryTable(new(ExecutionJobs)) javaTimestamp = 1557738394000 qs = ...
- Aspose Words、Excel导出等操作
/*Word先保存再输出-下载*/ strReportFilePath = Server.MapPath("~") + strReportFilePath; doc.Save(st ...
- 在C#应用中使用Common Logging日志接口
我在C#应用中一般使用log4net来记录日志,但如果项目中有个多个工程,那么没有工程都需要引用log4neg,感觉很不爽.不过今日在开spring.net的时候,看到了有个通用日志接口Common ...
- 文本流向 layout-flow
作用与语法 文本流向layout-flow用来定义网页中的文本流向方式. 即排列方式,主要有两个属性,分别是horizonta (水平的) 和vertical-ideographic (垂直的). 文 ...
- Binder对象死亡通知机制
本文參考<Android系统源码情景分析>,作者罗升阳. 一.Binder库(libbinder)代码: ~/Android/frameworks/base/libs/bin ...
- PHP--反射的方法
反射,直观理解就是根据到达地找到出发地和来源.比如,一个光秃秃的对象,我们可以仅仅通过这个对象就能知道它所属的类.拥有哪些方法. 反射是指�php运行状态中,扩展分析PHP程序,导出或提出关于类.方法 ...
- Linux系统下实现远程连接MySQL数据库的方法教程
1.在服务器端开启远程访问首先进入mysql数据库,然后输入下面两个命令: grant all privileges on *.* to 'root'@'%' identified by 'passw ...
- LintCode刷题笔记-- BackpackIV
标签: 动态规划 描述: Given an integer array nums with all positive numbers and no duplicates, find the numbe ...
- twisted(转)
reactor.protocol 这两个类都在 twisted.internet 命名空间中 reactor对象是Twisted编程当中的第一步,它就是一个反应器,专门负责与服务端的连接以及监听与服务 ...
- Linux下安装zookeeper-3.4.13
转载至:https://yq.aliyun.com/articles/662422 1.zookeeper官网下载安装包http://mirrors.hust.edu.cn/apache/zookee ...