【C】【笔记】《C语言深度剖析》第四章 指针和数组

本文为个人读书笔记,仅供记录学习过程中遇到的日后需要留意的问题,如有相关版权问题请及时通知作者。

指针

指针的内存布局
    一个基本的数据类型,包括结构体等自定义类型加上 * 号就构成了一个指针类型,这个类型的大小是一定的,与 * 号前面的数据类型无关。* 号前面的数据类型只是说明指针所指向的内存里存储的数据类型。所以,在32位系统下(64位测试相同结果),不管什么样的指针类型,其大小都为4byte。

int *p=NULL与*p=NULL
          int *p=NULL;
     定义一个指针变量p,其指向的内存里面保存的是int类型的数据;在定义变量p的同时把p的值设置为0x00000000,而不是把*p的值设置为0x000000.这个过程叫做初始化,是编译时进行的。(个人理解:也就说把指针位置初始化,而不是把指针指向的内容清空) 

          int *p;
          *p=NULL;
     定义一个指针变量p,其指向的内存里保存的是int类型的数据;此时p本身的值不确定,可能是一个非法的地址。第二行给*p赋值为NULL,即给P指向的内存赋值为NULL;但是由于p指向的内存可能是非法的,所以调试的时候,编译器可能会报告一个内存访问错误。
     
     NULL就是NULL,被宏定义为0,但和0不同。要注意大小写。

如何将数值存储到指定的内存地址
          int *p=(int*)0x12ff7c
          *p=0x100;
     为了取一个合法的地址,可以建立变量编译时查看地址,目的是避免使用了不合法的地址。
          *(int*)0x12ff7c=0x100;同理

数组

数组的内存布局
          int a[5];
     sizeof(a)的值为sizeof(int)*5 =20
     sizeof(a[0])的值为sizeof(int)=4
     sizeof(a[5])的值为4,没有出错。因为sizeof是关键字,不是函数。函数求值是在运行的时候,而关键字sizeof求值是在编译的时候。虽然并不存在a[5]这个元素,但是这里也没有真正访问a[5],而是仅仅根据数组元素的类型来确定其值。
     sizeof(&a[0]) 值为4。取元素a[0]的首地址。
     sizeof(&a)值为4 。取数组a的首地址 。但VC++6.0的结果是20.

数组名作为左值与右值的区别
     x=y;
     左值:在这个上下文环境中,编译器认为x的含义是x所代表的地址。由编译器管理。
     右值:在这个上下文环境中,编译器认为y的含义是y所代表的地址里面的内容。
     C语言规定,出现在赋值符左边的符号所代表的低智商的内容一定是可以被修改的。也就是说,只能给非只读变量赋值。

     a作为右值时等价于&a[0],代表的是数组首元素的首地址,而不是数组的首地址。但这仅仅是代表,编译器并没有为数组a分配一块内存来存其地址。

     a不能作左值。只能访问数组的某个元素而无法把数组当一个总体进行访问。

指针与数组的关系。

     指针与数组没有关系。
     指针变量在32位系统下,永远占4个byte,其值为某一个内存的地址,指针可以指向任何地方,但不是任何地方都能通过指针变量访问到。
     数组的大小与元素的类型和个数有关。定义数组时必须指定元素类型和个数。数组可以存任何类型的数据,但不能存函数。

以指针的形式和以下标的形式访问指针。
     对于 char *p=“abcdef”;
     如果要取字符e,使用*(p+4)与p[4]都可以实现。编译器总是把以下表的形式的操作解析为以指针的形式的操作。

     以下标的形式访问在本质上与以指针的形式访问没有区别,只是写法不同。

以指针的形式和以下标的形式访问数组
     数组本身在栈上。对数组的访问必须现根据数组的名字找到数组首元素的首地址,然后根据偏移量找到相应的值。这是一种典型的“具名+匿名”的访问。

     指针和数组都可以 以指针形式 或 以下标形式进行访问。但指针是完全的匿名访问,数组是典型的具名+匿名访问。

a和&a的区别          
main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
}
     对指针进行加1操作,得到的是下一个元素的地址。一个类型为T的指针的移动,以sizeof(T)为单位。
     &a是数组的首地址,因此&a+1相当于&a+5*sizeof(a),即&a+5*sizeof(int),也就是下一个数组的首地址。
     a是数组首元素的首地址,也就是a[0]的首地址,a+1就是数组下一元素的地址,即a[1]的地址。

指针和数组的定义与声明

定义为数组,声明为指针
          文件1:char a[100];
          文件2:extern char *a;
     是错的。当声明extern char *a;时,编译器认为a是一个指针变量,占4个byte。这4个byte里存放了一个地址,这个地址上存的是字符类型数据。

定义为指针,声明为数组
     同样错误。

指针和数组的对比。
     在一个地方定义为指针,在别的地方也只能声明为指针;在一个地方定义为数组,在别的地方也只能声明为数组。

指针 数组
保存数据的地址,任何存入指针变量的数据都会被当做地址来处理。指针本身的地址由编译器另外存储,存储位置未知 保存数据,数组名a代表数组首元素的首地址。&a代表整个数组的首地址。a本身的地址由编译器另外存储,存储位置未知
间接访问数据,首先取得指针变量的内容,把它作为地址,然后从这个地址提取数据或向这个地址写入数据。指针可以以指针或下标的形式访问。但本质上都是先取p的内容然后再加偏移量*sizeof(类型)个byte 直接访问数据,数组名a是整个数组的名字,数组内每个元素没有名字。只能通过具名+匿名的方式来访问某个元素。数组可以以指针的形式或下表的形式访问。但本质上都是a所代表的数组首元素的首地址加上偏移量*sizeof(类型)个byte
通常用于动态数据结构 通常用于存储固定数目且数据类型相同的元素
相关函数 malloc free 隐式分配和删除
通常指向匿名数据,也可以指向具名数据 自身即为数组名

指针数组和数组指针
     指针数组:是一个数组,数组的元素都是指针。数组占多少个字节由数组本身决定。全称是 存储指针的数组
     数组指针:是一个指针,指向一个数组。32位系统下永远是4个字节,指向的数组占多少个字节未知。全称是 指向数组的指针。
          int *p1[10];
          int (*p2)[10];
    [ ]的优先级高于*,所以p1先与[ ]结合,构成一个数组的定义,所以它是一个名为p1的数组,数组元素是int *。也就是指针数组。
     ()的优先级比[ ]高,所以p2与*结合构成指针的定义,指针变量名为p2,int修饰的是数组的内容。数组在这里没有名字,是个匿名数组。所以p2是一个指针,指向一个包含10个int类型数据的数组,即数组指针。

     数组指针原本的定义形式为:int (*)[10]  p2;

     因为数组指针是指向数组的,所以赋值应当=&a 而不是 =a

地址的强制转换

     指针变量与一个证书相加减并不是用指针变量里的地址直接加减这个整数。这个整数的单位是元素个数。

多维数组与多级指针
     
     二维数组初始化是花括号嵌套花括号

二级指针
     二级指针保存的是一级指针的地址

数组参数与指针参数
     
一维数组参数
     无法向函数传递一个数组。
     C语言中,当一维数组作为函数参数的时候,编译器总是把它解析成一个指向其首元素首地址的指针。
     函数本身是没有类型的,右值函数的返回值才有类型。
     函数的返回值也不能是一个数组,而只能是指针。
     实际传递的数组大小与函数形参指定的数组大小没有关系。

一级指针参数
     无法把指针变量本身传递给一个函数,传递过去的是实参的一个备份。如果需要在函数中操作指针,如malloc,那么需要在函数中把指针变量return回来。

二维数组参数与二维指针参数
     
数组参数 等效的指针参数
数组的数组:char a[3][4] 数组的指针:char (*p)
指针数组:char *a[5] 指针的指针:char **P

     C语言中,当一维数组作为函数参数的时候,编译器总是把它解析成一个指向其首元素首地址的指针。这条规则并不是递归的,也就是说只有一维数组才是如此,当数组超过一维时,将第一维改写为指向数组首元素首地址的指针后,后面的维再也不可改写。

函数指针
     函数指针就是函数的指针。是一个指针,指向一个函数
     VC++6.0里,给函数指针赋值时,可以用&fun或直接用函数名fun。这是因为函数名被编译之后就是一个地址。所以这两种用法没有本质的差别。

函数指针数组
     char * (*pf)(char *p)定义的是一个函数指针pf。既然pf是一个指针,那就可以存储在一个数组里。
          char *(*pf[3])(char *p);
     这是定义一个函数指针数组。它是一个数组,名为pf,数组内存储了3个指向函数的指针。这些指针指向一些返回值类型为指向字符的指针、参数为一个纸箱字符的指针的函数。

函数指针数组的指针
          char *(*(*pf)[3])(char *p);
     这里的pf是指针,指向一个包含了3个元素的数组;这个数组里存的是指向函数的指针;这些指针指向一些返回值类型为指向字符的指针、参数为一个纸箱字符的指针的函数。
,,




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值