C语言 指针大法

C语言 指针大法

基本数据类型大致按照使用的类别的话可以分为大致两类,有符号和无符号两种类型

如下所示:
数据的存储方式:
-1 = 1000 0001
存储的是补码形式
①反码是1111 1110【符号位不变,其他位取反】
②补码是1111 1111【反码加1】
然后std::hex以十六进制显示【1111 1111】

[有符号] [无符号]

int 整数类型 unsigned int

float 单精度 unsigned float

char 字符型 unsigned char

short 短整型 unsigned short

long 长整型 unsigned long

double 双精度 unsigned double

先看有符号和无符号的区别 :

相同点:

首先都是以二进制的方式进行存储的,所以在内存存储单元中存储的数据都是一样的

例如:

unsigned int a= 100;

int b = -100;

(实际上存储的数据只有100,而有无符号是通过补码方式进行区分 )

不同点:

1.如果是无符号类型的数就不在需要补码,如果是有符号类型的数就需要进行补码 (在附录中有关于补码简单的介绍)

2.所表示的数据的极限范围不一样 :

以int和unsigned int为例:

unsigned int的范围是 0 到 2的 32 次方

int 的范围是:

(-2的31次方) 到( 2的31次方+1)

具体算的过程是这样的,同样试用于其他的数据类型范围计算(由于不同的平台内存对齐方式不一样,所以我讲的是最常见的内存对齐方式)

unsigned int 类型为例:

可以分配的内存大小为 4字节,一个字节是8bit ,那什么是8bit,1111 1111,简单理解就是8个二进制数,每个2进制数的可能性是两种,只有0或者1,所以可表示的范围就出来了,0 到 2的32次方(最通俗的讲一共有32个2相乘吗)

基本数据类型的内存对齐方式(由于不同的平台内存对齐方式不一样,所以我讲的是最常见的内存对齐方式)

float, int 分配内存 4个字节 32位

char 1个字节 8位

double, long 8个字节 64位

short 2个字节 16位

数据类型所使用的格式控制

%c 单个字符

%s 字符串

%d 整数或者短整数

%ld 长整数

%p 地址16进制数

%x 16进制数

%#x 格式控制的16进制数

%f 单精度 %.1f 小数点后1位,以此类推

%lf 双精度 %.1lf 小数点后1位 ,以此类推

枚举,结构体和 联合(联合现在可以直接用强制类型转换替代,不需要多了解)

强制类型转换的作用就是 : 和目标数据类型,进行内存对齐

例子:

​ int a = 3;

​ char b = 4;

​ a = (int) b;

枚举主要是列出了一堆常量,用名字去替代,常量数字 当然也可以使用相关的宏定义,进行宏展开

例如:

enum{

flase=0,

true=1

};

然后在你的程序里,flase就代表着数字0,true就代表着数字 1,bool类型的源码就是这么玩的

在C代码中枚举和结构体用的是最多的

结构体就是对同类操作的数据类型进行了相关的分类,是对象操作的基础 ,可以这样理解,描述了对象的属性

例子:

struct student{

​ int age;

char name[0];

};

位运算在驱动和服务程序 中的数据解析用的多,所以,基本概念 可以上网查,我说几个关键和经常用的几个掩码:

[16进制] [2进制]

0x1 0001

0x2 0010

0x4 0100

0x8 1000

0xf 1111

0x7 0111

0xd 1110

具体的这个得多练习才能熟练使用,所以没啥好方法

但是 16进制数是最接近2进制的数,在程序中

我说一下换算关系

16进制数 2的4次方 为什么呢,那是2进制数只有两张表示方式0和1, 满16进一位,也就是说一位16进制数单个位上最大是16,你用2进制表示就是 1111 , 所以现在你就可以讲多位的16进制数进行分解,得到2进制

例子:

0xf8 【16进制】

1111 1000 【2进制】

所以这道这个就ojbk了

接下来就是内存管理 ,但是内存管理的前提是,你对所有的数据类型了如指掌才行,没啥好方法,得多写写,多改点bug就知道了,C语言的内存管理模型比较抽象,也没必要非得掌握,硬讲也不是不可以,但是估计不会好理解,先接过去 ,我有时间会在写一片详细的,C的内存管理方法,但是看看汇编语言,会有助于理解c的内存管理模型

接下来最重要的就是指针了

指针第一阶段理解:

先理解这样一个问题

指针就是地址;

C的声明 (注意我注释的顺序,这个顺序就是 ,解读声明的顺序),我讲的例子就是 最基础的声明的例子,复杂声明的分析方法,和下面的分析方法相同;

有一个优先级的关系:

[ ] >() > *

例子:

int a ; //a是一个变量 ,int 类型的

int *a ; //a是一个指针,指向int类型的

int a[0x1000]; //a是一个数组,存储的数据类型是int型的

int *a[0x1000]; //a是一个数组, 存储的是指针,这个指针指向的是int类型的数据

int (*a)[0x1000]: //a是一个指针, 指向的是 int类型的数组

int a(); //a是一个函数,返回值的是一个int类型的数据

int *a();//a是一个函数,返回值是一个指向int类型的数据的一个指针

int (*a)();//a是一个指针,指向的是一个返回值是int类型的一个函数

如果总结出来了,恭喜你,那么,高级声明你就完全没问题了

那么开始进行指针理解:

*取值运算符: 读取内存空间的数据

&取地址运算符: 读取内存空间的地址信息

先看普通的声明定义 ;

int a = 3 ; //a 的内存空间,有两部分组成,标注内存空间的地址和所存储的数据

普通声明和定义的变量的地址信息是只读的 ,是不允许修改的

{那么就不可以修改吗 ,可以的,我喜欢在,直接在内存中修改,二进制代码病毒}

如图所示(大概实际的排列方式类似):

[ addr | data ]

那么再看

int *b = &a ;//b是一个指针变量,那么他的内存空间,也是主要包括两个部分:

标注的内存空间的地址和a的地址信息数据,

存储的是a的地址信息,

那么请看b的内存空间布局:

如下图:

[ b的地址 | a的地址信息 ]

如果理解上面的内容之后,恭喜你对指针进行了基础的理解了

为了帮助你理解 ,你可以这样想:

1.指针和数组很像(但不是完全等价的,为什么呢 ,百度上有很多)

2.如果内存太抽象,还可以这样理解

抽屉柜组 -> 单个抽屉柜 -> 单个抽屉,你在想想数组下标值,在想想指针 , 是不是若有所思了

指针第二阶段理解:

那么指针是如何操作地址读取数据的呢 ,那个是编译器的 责任,我只讲人可以理解的部分,

int *b = &a ;

首先编译器一看是指针变量,第一步先找到变量b,怎么找到b,当然是通过b的地址信息找到b的内存空间

然后读取b的数据空间的数据,然后发现存储的是a的地址信息,紧接着就根据a的地址的信息,找到a的内存空间,

然后再去读取,a的内存空间的存储的数据 ,

所以简单来说就是指针,是间接读取数据的 ,普通变量是直接读取的

第三阶段指针理解 :

多级指针

以2级指针为例:

int **c; //这是一个2级指针,wc,为啥多了一个,不要急,还是慢慢来搞他

2级指针说破天他存储的还是地址信息,但是存储的 一级指针的地址信息,so你懂的分析方法和上面的分析方法是一致的,读取的数据的方法还是不会变的 。

你理解了这个方法之后, 我再说说2级指针的使用方法,

int **c ; // 表明他是一个 二级的

*c //表示存储1级的数据空间

&c // 表示的是2级指针的空间地址信息

3级以上以此类推

第四阶段 指针理解

存储的是某个变量的空间的地址信息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值