|
其实都不是,上面最快的内存(40G/s),速度依旧不够快。
答案是缓存(cache):
而缓存一般是多级缓存,其速度比内存快得多。
缓存与内存都称为RAM(Random Access Memory),其中:缓存一般都是SRAM,内存为DRAM。
不同类型的变量会存放在SRAM的不同区域,如堆区、栈区、静态区:
1.栈区(stack)— 由编译器自动分配释放 ,存放为运行函数而分配的局部变量、函数参数、返回数据、返回地址等。该栈的最大存储是有大小的,该值固定,超过该大小将会造成栈溢出。
2.堆区(heap) — 一般由程序员分配释放, 用来存储数组,结构体,对象等。若程序员不释放,程序结束时可能由OS回收。
3.全局区(静态区)(static)— 存放全局变量、静态数据、常量。程序结束后由系统释放。
用一个黄色方块表示一位SRAM存储区,一个字节则需要8个小方块,它们共用一根地址线。
一个字节数据读写时,先给地址线高电平(写1),再给数据线相应的电平(看你要写什么了)。
两个字节读写时:则可以使用非门来选择对哪一个字节进行读写。
而对多个字节进行读写,则可以使用译码器,使用很少的地址线就可以确定对哪一个字节进行读写,如下图的38译码器,3根地址线可以操作8个字节。
而16根地址线就可以控制64KB字节的读写:
我们来定义简单定义一个变量和指针:
char a = 10;
char* p = &a;
上面:我们定义了一个char型变量a,它的值是10,&a是a的地址(也就是a在SRAM中的存储位置,&是取地址运算符),我们把a的地址(&a)赋值给了p。其中char* p
和char *p
是一样的,不过在你的代码中要统一才好(看)。
假设我们的存储空间只有16个字节。存储char型变量a需要一个字节空间,假设他存储在第16个字节中,那么他的地址就是1111(二进制),即0xF(十六进制)。
将a的地址赋值给指针p:char* p=&a
。也就是char型指针p的值是0xF,再使用间接运算符就可以获得该地址的值。
先来点简单的:
#include
int main()
{
char a = 10;
char* p = &a;
//变量的值
printf("变量a的值是:%d\n", a);
//变量的地址
printf("a的地址是:%p\n",&a);
//指针的值即地址处存放的值
printf("指针p指向地址存储的值是:%d\n", *p);
//指针的值是变量地址
printf("指针的值(即变量地址)是:%p\n", p);
//变量的地址处存放的是变量的值
printf("a的地址存放的值是a的值:%d\n",*(&a));
//指针的地址
printf("指针p的地址是:%p\n",&p);
//指针的地址处存放的是a的地址;
printf("指针的地址处存放的是a的地址:%p\n",*(&p));
return 0;
}
输出:
变量a的值是:10
a的地址是:000000A801CFF9C8
指针p指向地址存储的值是:10
指针的值(即变量地址)是:000000A801CFF9C8
a的地址存放的值是a的值:10
指针p的地址是:000000A801CFF9C0
指针的地址处存放的是a的地址:000000A801CFF9C8
注:
- char从技术层面讲是(8位)整数类型;
- 64(x64)位的电脑,地址则是16位16进制数,32位(x86)则是8为16进制数。
- 指针变量本身也是有地址的,这个地址存放的是指针指向变量的地址。
一个变量通常包含这些要素:
变量存储在缓存中,那变量名呢?
在C语言中,变量名存放在符号表(symbol table)中。符号表是一个数据结构,用于保存程序中定义的所有变量、函数等符号的名称、数据类型以及在内存中的地址等信息。在程序编译过程中,编译器会将变量名添加到符号表中,以便在程序执行时能够正确地访问变量。
在程序运行时,变量名不再存在于内存中,只有变量的值和地址才会被存储在内存中。当程序需要访问变量时,编译器会根据变量名在符号表中查找变量的信息,然后使用该信息来生成相应的汇编代码,从而访问变量的值或地址。
即:
char* p;
char *p;
不同类型的指针操作不同类型的变量。
定义后最好进行初始化。
如果没有显式初始化指针变量,它的值将是不确定的,也就是一个随机的值。如果你试图在没有初始化指针变量的情况下对其进行解引用操作,程序可能会导致不可预知的结果,甚至可能崩溃。
在某些情况下,如果你还不确定要分配内存,您可能希望在稍后的代码中初始化指针变量。在这种情况下,建议将指针变量初始化为NULL。这样做可以确保指针变量不会被用于解引用操作,直到分配了相应的内存。
int *ptr; // 未初始化的指针变量
int *ptr = NULL; // 初始化为NULL的指针变量
本文先介绍指针简单的使用,能看懂下面这段就ok了。
int a=5;
int* pa=&a;
*&a可以理解为*(&a),&a表示取变量 a 的地址(等价于 pa),*(&a)表示取这个地址上的数据(等价于 *pa),绕来绕去,又回到了原点,*&a仍然等价于 a。
&*pa可以理解为&(*pa),*pa表示取得 pa 指向的数据(等价于 a),&(*pa)表示数据的地址(等价于 &a),所以&*pa等价于 pa。
指针存储的是它指向的变量的地址,是一个数(我们通常使用%p来输出,即左侧带补0的十六进制),因此也可以做一些运算,如加减、比较等。
定义如下变量并赋值:
char a = 10;
int arr[4] = { 5,2,3,4 };
int b = 20;
char* pa = &a;
int* pb = &b;
先打印a、b以及地址:
printf("a = %d\n",a);
printf("*pa = %d\n\n", *pa);
printf("b = %d\n",b );
printf("*pb = %d\n\n", *pb);
printf("&a = %p\n",&a );
printf("pa = %p\n\n",pa );
printf("&b = %p\n", &b);
printf("pb = %p\n\n", pb);
这似乎没有什么问题,输出:
a = 10
*pa = 10
b = 20
*pb = 20
&a = 00000047880FF770
pa = 00000047880FF770
&b = 00000047880FF774
pb = 00000047880FF774
再来对指针变量进行加法运算:
printf("pa = %p\n",pa);
printf("pa+1 = %p\n", ++pa);
printf("pb = %p\n",pb);
printf("pb+1 = %p\n\n", ++pb);
输出:
pa = 00000047880FF770
pa+1 = 00000047880FF771
pb = 00000047880FF774
pb+1 = 00000047880FF778
这里可以看到,指针变量pa加1之后,结果确实加1了,而pb加1之后,输出值却增加了4
这其实与指针变量的类型有关:指针变量pa是char型变量,加1就加1个字节;而指针变量pb是int型变量,加1则会加4个字节,
也就是说加1指的是加一个存储单元,这就是必须声明指针所指向对象类型的原因之一。
指针变量的比较运算:
printf("pa!=pb的结果是:%d\n",pa!=pb);
输出:
pa!=pb的结果是:1
数组:
数组的一些操作,下篇文章完整介绍:
注意:* arr,*(arr+1),*arr+1
printf("*arr = %d = arr[0] = %d\n",*arr,arr[0]);
printf("*(arr+1) = %d = arr[1]=%d\n", *(arr+1),arr[1]);
printf("*arr+1 = %d = arr[0]+1 = %d\n\n",*arr+1,arr[0]+1);
输出:
*arr = 5 = arr[0] = 5
*(arr+1) = 2 = arr[1]=2
*arr+1 = 6 = arr[0]+1 = 6
————————————————
参考视频1:https://www.bilibili.com/video/BV1o8411T7K5?t=5.9
参考视频2:https://www.bilibili.com/video/BV1Gi4y1w7yG?t=105.7