盐城市网站建设,外贸数据平台有哪些,免费咨询海报,计算机系毕设代做网站文章目录 一、内存和地址1. 内存2. 如何理解编址 二、指针变量和地址2.1 取地址操作符()2.2 指针变量和解引用操作符(*)2.2.1 指针变量2.2.2 如何拆解指针变量2.2.3 解引用操作符 2.3 指针变量的大小 三、指针变量类型的意义3.1 指针的解引用3.2 指针 - 整数3.3 void*指针… 文章目录 一、内存和地址1. 内存2. 如何理解编址 二、指针变量和地址2.1 取地址操作符()2.2 指针变量和解引用操作符(*)2.2.1 指针变量2.2.2 如何拆解指针变量2.2.3 解引用操作符 2.3 指针变量的大小 三、指针变量类型的意义3.1 指针的解引用3.2 指针 - 整数3.3 void*指针 四、const 修饰指针4.1 const修饰变量4.2 const修饰指针变量 一、内存和地址
1. 内存
内存是计算机中用于存储数据和程序的硬件设备也被称为随机存取存储器RAM。内存具有较快的读写速度用于临时存储当前正在执行的程序和数据。
在计算机系统中内存扮演着至关重要的角色它直接影响着计算机的性能和运行效率。以下是一些关于内存的基本信息 作用内存用于存储当前正在运行的程序和数据包括操作系统、应用程序和用户数据等。当计算机启动时操作系统会将需要的程序和数据加载到内存中CPU 可以直接从内存中读取和写入数据而不需要像从硬盘那样慢速地进行输入和输出操作。易失性内存是一种易失性存储设备这意味着当计算机断电或重新启动时内存中的数据将丢失。因此重要的数据通常需要保存在持久性存储设备如硬盘、固态硬盘中。访问速度内存的访问速度通常比硬盘或固态硬盘快得多这使得计算机能够更快地读取和写入数据从而提高系统的性能和响应速度。单位内存容量通常以字节为单位进行衡量常见的单位有千兆字节GigabyteGB和千兆字节TerabyteTB等。 为了更方便理解我们举一个生活中的小案例 假设有⼀栋宿舍楼把你放在楼里楼上有100个房间但是房间没有编号你的⼀个朋友来找你玩 如果想找到你就得挨个房子去找这样效率很低但是我们如果根据楼层和楼层的房间的情况给 每个房间编上号如
⼀楼101102103...
⼆楼201202203....
...有了房间号如果你的朋友得到房间号就可以快速的找房间找到你。 这里的房间号就相当于地址。
计算机上CPU 中央处理器 在处理数据的时候 需要的数据是在内存中读取的 处理后的 数据也会放回内存中 那我们买电脑的时候 电脑上内存是8GB/16GB/32GB等 那这些内存空间如何 高效的管理呢 其实也是把内存划分为一个个的内存单元 每个内存单元的大小取1个字节。
补充计算机中常见的单位 一个比特位可以存储一个二进制位的0或1。
bit (比特位)
1 Byte (字节) 8 bit
1 KB 1024 Byte
1 MB 1024 KB
1 GB 1024 MB
1 TB 1024 GB
1 PB 1024 TB
...其中每个内存单元相当于一个学生宿舍一个字节空间里面能放8个比特位就好比同学们住的八人间每个人是一个比特位。 每个内存单元也都有一个编号这个编号就相当于宿舍房间的门牌号 有了这个内存单元的编号CPU就可以快速找到一个内存空间。 生活中我们把门牌号也叫地址在计算机中我们把内存单元的编号也称为地址。C语言中给地址起了新的名字叫指针。 也可以说内存单元的编号 地址 指针
2. 如何理解编址
在计算机科学和计算机网络中“编址”通常指的是为了标识和定位计算机或网络设备而给它们分配一个唯一的地址。这个地址可以用来在网络中准确定位设备以便进行数据传输、通信或者其他操作。 首先必须理解计算机内是有很多的硬件单元而硬件单元是要互相协同工作的。所谓的协同至少相互之间要能够进行数据传递。 但是硬件与硬件之间是互相独立的那么如何通信呢答案很简单用线连起来。而CPU和内存之间也是有大量的数据交互的所以两者必须也用线连起来。 我们可以简单理解32位机器有32根地址总线每根线只有两态表示0,1【电脉冲有无】那么⼀根线就能表示2种含义2根线就能表示4种含义依次类推。32根地址线就能表示2^32种含义每⼀种含义都代表⼀个地址。地址信息被下达给内存在内存上就可以找到该地址对应的数据将数据在通过数据总线传⼊CPU内寄存器。
二、指针变量和地址
2.1 取地址操作符()
在C语言中创建变量其实就是向内存申请空间比如
int main()
{int a 10;return 0;
}在上述代码中我们创建了一个整型变量a向内存中申请了4个字节用来存放整数10其中每个字节都有一个地址上面4个字节的地址分别是
0x0000004B0D2FF984
0x0000004B0D2FF985
0x0000004B0D2FF986
0x0000004B0D2FF987这里我们用取地址操作符
int main()
{int a 10;a; // 取a的地址printf(%p\n, a);return 0;
}按我们所学的知识可以知道打印的结果是0x0000004B0D2FF984 虽然整型变量占4个字节但我们只要知道了第一个字节的地址就可以顺藤摸瓜访问第4个字节的数据。
2.2 指针变量和解引用操作符(*)
2.2.1 指针变量
我们通过取地址操作符()拿到的地址是一个字符比如0x0000004B0D2FF984这个数值我们可以用指针变量把这个数值存储在指针变量中。
int main()
{int a 10;int* pa a; // 取出a的地址并存在指针变量pa中return 0;
}指针变量也是一种变量这种变量就是用来存放地址的存放在指针变量中的值都会理解为地址。
2.2.2 如何拆解指针变量
我们看到pa的类型是int*我们该如何理解指针的类型呢
int a 10;
int* pa a; // 取出a的地址并存在指针变量pa中这里pa左边写的是int* * 是在说明pa是指针变量而前面的int是在说明pa指向的是整型(int)类型的对象。
2.2.3 解引用操作符
在C语言中我们只要拿到了地址(指针) 就可以通过地址找到地址指向的对象这里必须学习一个操作符叫解引用操作符(*)。
#include stdio.h
int main()
{int a 10;int* pa a; // 取出a的地址并存在指针变量pa中*pa 0;printf(%d\n, a);return 0;
}*pa 的意思就是通过pa中存放的地址找到指向的空间 pa其实就是a变量了所以pa 0 这个操作符是把a改成了0。
2.3 指针变量的大小
前面的内容我们了解到32位机器假设有32根地址总线每根地址线出来的电信号转换成数字信号后是1或者0 那我们把32根地址线产生的2进制序列当做一个地址那么一个地址就是32个bit位需要4个字节才能存储。 如果指针变量是用来存放地址的 那么指针变的大小就得是4个字节的空间才可以。 同理64位机器假设有64根地址线一个地址就是64个二进制位组成的二进制序列存储起来就需要 8个字节的空间指针变量的大小就是8个字节。
#include stdio.h
int main()
{// 指针变量的大小取决于地址的大小// 32位平台下地址是32个bit位即4个字节// 64位平台下地址是64个bit位即8个字节printf(%zd\n, sizeof(int*));printf(%zd\n, sizeof(char*));printf(%zd\n, sizeof(short*));printf(%zd\n, sizeof(double*));return 0;
}x86环境输出结果 X64环境输出结果
结论
32位平台下地址是32个bit位指针变量大小是4个字节64位平台下地址是64个bit位指针变量大小是8个字节注意指针变量的大小和类型是无关的只要指针类型的变量在相同的平台下大小都是相同的。
三、指针变量类型的意义
3.1 指针的解引用 调试我们可以看到代码1会将n的4个字节全部改为0但是代码2只是将n的第一个字节改为0。 结论指针的类型决定了对指针解引用的时候有多大的权限一次能操作几个字节。 比如 char* 的指针解引用就只能访问一个字节而 int* 的指针的解引用就能访问四个字节。
3.2 指针 ± 整数
通过下面的代码观察地址的变化
#include stdio.h
int main()
{int n 10;char* pa (char*)n;int* pi n;printf(%p\n, n);printf(%p\n, pa);printf(%p\n, pa 1);printf(%p\n, pi);printf(%p\n, pi 1);return 0;
}我们可以看出char* 类型的指针变量1跳过1个字节 int* 类型的指针变量1跳过了4个字节。 这就是指针变量的类型差异带来的变化。指针1其实跳过1个指针指向的元素。指针可以1那也可以-1。 结论指针的类型决定了指针向前或者向后走一步有多大距离。
3.3 void*指针
在指针类型中有一种特殊的类型是void类型的可以理解为无具体类型的指针或者叫泛型指 针这种类型的指针可以用来接受任意类型地址。但是也有局限性 void类型的指针不能直接进 行指针的±整数和解引用的运算。
【举例】
int main()
{int a 10;int* pa a;char* pc a;return 0;
}在上面的代码中将一个int类型的变量的地址赋值给一个char类型的指针变量。编译器给出了一个警告如下图 是因为类型不兼容。而使用void类型就不会有这样的问题。
使用void*类型的指针接收地址
int main()
{int a 10;void* pa a;void* pc a;*pa 10;*pc 0;return 0;
}这里我们可以看到 void* 类型的指针可以接收不同类型的地址但是无法直接进行指针运算。 一般 void* 类型的指针是使用在函数参数的部分用来接收不同类型数据的地址这样的设计可以实现泛型编程的效果。使得一个函数来处理多种类型的数据。
四、const 修饰指针
4.1 const修饰变量
变量是可以修改的如果把变量的地址交给一个指针变量通过指针变量的也可以修改这个变量。 但是如果我们希望一个变量加上一些限制不能被修改怎么做呢这就是const的作用。
int main()
{int n 0;n 20; //n可以被修改const int m 10;m 20; //m不可以被修改return 0;
}上述代码中m是不能被修改的其实m本质还是变量只不过被const修饰后在语法上加了限制只要我们在代码中对m就行修改就不符合语法规则就报错致使没法直接修改m。
但是如果我们绕过m使用m的地址去修改m就能做到了虽然这样做是在打破语法规则。
#include stdio.h
int main()
{const m 0;int* p m;*p 20;printf(%d\n, m);return 0;
}我们可以看到这里一个确实修改了但是我们还是要思考一下为什么n要被const修饰呢就是为了不能被修改如果p拿到n的地址就能修改n这样就打破了const的限制这是不合理的所以应该让p拿到n的地址也不能修改n那接下来怎么做呢
4.2 const修饰指针变量
一般来讲const修饰指针变量 可以放在 * 的左边也可以放在 * 的右边意义是不一样的。
int * p;//没有const修饰
int const * p;//const 放在*的左边做修饰
int * const p;//const 放在*的右边做修饰测试const放在*的左边情况 通过上面几张图可以看到const在*号左边和在右边是有着不同作用的。
const如果放在 * 的左边修饰的是指针指向的内容保证指针指向的内容不能通过指针来改变。但是指针变量本身的内容可变。const如果放在*的右边修饰的是指针变量本身保证了指针变量的内容不能修改但是指针指向的内容可以通过指针改变。如果*号的左右两边都放const既修饰的是指针指向的内容保证指针指向的内容不能通过指针来改变。又修饰的是指针变量本身保证了指针变量的内容不能修改。