计算机的CPU读取数据时是从内存中读取,处理完数据,也是放到内存中

内存分为一个个小的内存单元,一个内存单元的大小取一个字节,类比学校的宿舍,给房间编号,给每个内存单元编上号,CPU才能快速的找到一个内存空间


CPU是如何拿数据又把数据拿回来的?
计算机中的编址是通过硬件设计来完成的,不需要把地址给存起来 地址信息被下达给内存,在内存上,就可以找到该地址对应的数据,将数据在通过数据总线传入CPU内寄存器。

控制总线传输的是做什么操作(’是‘读还是’写‘),地址总线,把地址传过去,找到是读哪里的数据或写到哪里的数据(找到地方),数据通过数据总线传入CPU寄存器中

创建变量就是申请空间,每一个字节都有自己的空间

怎么访问变量a的地址
&a
虽然有四个地址,但是&a取出的是a所占4个字节中地址较小的字节的地址。
我们知道了第一个地址,顺藤摸瓜可以访问其余的地址。
&a也是值,该用什么存储
因为编号== 地址 ==指针,p=&a中的p就叫指针变量,它的类型int *
怎么理解指针变量

只要存放到指针变量里面去,都会当成地址处理
为了有朝一日能再次访问指针变量操作符里面的地址,
*p可以找到地址指向的变量*p==a
提供了更多的手段来改变变量a的值
a*p指针变量是用来存放地址的,其大小跟地址有关系
传地址是由地址线传过去的,32根地址总线产生的是32个0/1,32个0/1当成内存单元编号了
32位机器上,有32个地址线,需要32个比特位,4个字节
同理,64位机器上,有64个地址线,需要64个比特位,8个字节
无论是那种类型,地址都是32位的,长度不变

地址和里面的数据 打印为了方便,不打印2进制(太长了),打印16进制

既然指针变量的大小一样,为啥要有这么多指针类型(char、int、float等)
指针变量类型让他觉得自己是个指向什么类型的指针,只访问该类型大小的字节 对比图:


指针类型决定了指针进行解引用操作符的时候访问几个字节,也就是决定指针的权限!
选择适当的指针来访问不同的字节长度,如果想访问1个字节,就用char类型的指针,想访问2个字节可以用short类型,想访问4个字节的整形可以用int类型,想访问4个字节的浮点型的可以用float类型

指针类型决定了指针加1或减1时,能走多远的距离

void*是无类型指针,不能解引用操作和指针加减

应用场景:
void*当作一个垃圾桶,什么类型的地址都可以传(不同类型的地址相互传给会报错),当你在这个地方传地址不确定传什么类型的地址就可以用void


但是在C++中编译没有报错,因为在C++中const修饰的变量就是常量
应用场景:有一个变量不想让别人直接去修改就可以用,但是这种情况可以通过指针来修改
有没有方法限制指针无法修改呢?
补充知识:


*的右边
限制的是p变量本身,变成常变量了

const限制的是指针变量本身,指针变量不能再指向其他变量了,但是可以通过指针变量,修改指针变量指向的内容
*的左边
限制的是指针指向的内容不能通过指针来修改,但是可以修改指针变量本身的值



指针的作用就是访问内存,如何访问内存访问的更好?

同理,减号就是向回跳
作用:访问数组 (前提条件:数组在内存中连续存放的)
p在移动int main()
{
int arr[] = { 1,2,3,4,5,6,7,8 };
int sz = sizeof(arr) / sizeof(arr[0]);
int* p = &arr[0];
for (int i = 0; i < sz; i++)
{
printf("%d ", *p);
p++;
}
return 0;
}只要理解了指针,就有多种写法

i在移动int main()
{
int arr[] = { 1,2,3,4,5,6,7,8 };
int sz = sizeof(arr) / sizeof(arr[0]);
int* p = &arr[0];
for (int i = 0; i < sz; i++)
{
printf("%d ", *(p + i));
}
return 0;
}类比日期

并且,指针加指针没有任何的意义 注意:指针减指针的前提条件是两个指针指向同一块空间 否则:(如图所示)

应用:模拟strlen()函数的实现
方法一(传统方法):
int my_strlen(char* str)
{
int count = 0;
while (*str != '\0')
{
str++;
count++;
}
return count;
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d", len);
}方法二:指针减指针
int my_strlen(char* str)
{
char* start = str;
while (*str != '\0')
{
str++;
}
return str - start;
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d", len);
}也就是地址与地址比较大小

int main()
{
int arr[] = { 1,2,3,4,5 };
int sz = sizeof(arr) / sizeof(arr[0]);
int* p = arr;
while (p < arr + sz)
{
printf("%d ", *p);
p++;
}
return 0;
}野指针是什么? 野指针是指针指向的位置不可知的(随机、不正确的、没有明确限制的)
那些是野指针?



这么多的野指针,该这么规避它们?
NULL是标识符常量,值是0,0也是地址,但是该地址无法使用,读写该内存会报错

if (p != NULL)
{
……
}assert.h头文件定义了宏assert,用于在程序运行时符合特定的条件,否则会报错终止运行,这个宏成为”断言“,为了避免野指针,可以用assert(p!=NULL),如果括号为假,会报错


注意:在Release版本中assert自动优化掉了(禁用),样在debug版本写有利于程序员排查问题,在Release版本不影响用户
使用时程序的效率。

更标准:
size_t my_strlen(const char * p)//防止函数内通过p来修改字符
{
size_t count = 0;
assert(p != NULL);//更安全
while (*p != '\0')
{
count++;
p++;
}
return count;
}
int main()
{
char arr[] = "abcdef";
size_t len = my_strlen(arr);
printf("%zd", len);
return 0;
}有什么问题非指针不可
写一个函数交换a和b的值

void Fuc(int *p1,int *p2)
{
int tmp = 0;
tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
int main()
{
int a = 10;
int b = 20;
printf("a=%d,b=%d\n", a, b);
Fuc(&a, &b);
printf("a=%d,b=%d\n", a, b);
return 0;
}