1.内存:电脑上的存储设备,程序运行的时候会加载到内存中,也会使用内存空间
![](https://img-blog.csdnimg.cn/img_convert/c3102e600ff744d2dd74b287ea7be48e.jpeg)
2.指针:
①:内存中一个最小单元的编号,也就是地址
②: 平时口语中说的指针,通常指的是指针变量,用来存放内存地址的变量
总结:指针就是地址,口语中说的指针通常指的是指针变量
3.
![](https://img-blog.csdnimg.cn/img_convert/edf2d276231070a130d098415c192a6f.jpeg)
总结:
①:int a 的含义是向内存申请4个字节的地址,存的是数值。②:&a取的是a最小的地址。
③:int * pa的含义是向内存申请4个字节的地址(和a的四个地址不同),存的是a的四个地址。
③:指针变量是用来存放地址的,地址是唯一表示一个内存单元的
int main()
{
int a = 10;
int* pa = &a;
printf("%p\n",&a);//0x0012ff40
printf("%p\n",pa);//0x0012ff40
printf("%d\n", a); //10
printf("%d\n",*pa);//10
*pa = 20;
printf("%d\n", *pa); //20
printf("%d\n", a); //20
}
图解:
![](https://img-blog.csdnimg.cn/img_convert/eabe91173ba8e658ea3df6b823921efc.png)
4.编号:并不真实存在,地址线产生电信号进而产生二进制序列,根据二进制序列找内存单元
![](https://img-blog.csdnimg.cn/img_convert/c29ed73ea79cea51c38cce26aa571271.png)
2^32bit=4GB//32位机器
2^64bit=171亿GB//64位机器
总结:
①:在32位的机器上,地址是32个0或者1组成的二进制序列,那地址就得用4个字节的空间来存储,所以一个指针变量的大小就应该是四个字节。
②:在64的机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地址。
5.指针类型意义:
①:指针类型决定了,指针进行解引用操作的时候,一次性访问几个字节。
如果是char*类型的指针,解引用访问一个字节
如果是int*类型的指针,解引用访问4个字节
![](https://img-blog.csdnimg.cn/img_convert/f2e78a09d17e6294664c8b1ca952b0ec.png)
![](https://img-blog.csdnimg.cn/img_convert/14cf5337c1ed99ddb6594f969631a0e8.png)
![](https://img-blog.csdnimg.cn/img_convert/0da2c24f308b6c2e27eec669b5f6c762.png)
②:指针类型决定指针的步长(指针+1到底跳过几个字节)
字符指针+1,跳过1个字节
整形指针+1,跳过4个字节
![](https://img-blog.csdnimg.cn/img_convert/29a3181a86269aa96eaa036095d93280.png)
![](https://img-blog.csdnimg.cn/img_convert/66646c828e208fb7a85bc9bad7db2a89.png)
实现对a一个字节一个字节的赋值:
![](https://img-blog.csdnimg.cn/img_convert/03954ff25e80bde82ba8a49463fc45eb.png)
注意:
int a = 0X11223344;
char* pc = & a;
*pc = 1000;//有问题,因为PC解引用只能访问一个字节,最大为255。虽然不会报错,但它得到的值也不是我们想要的
6.野指针:指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
①:没有初始化:
int main()
{
int *p;//p是一个局部变量,因为没有给它初始值,p就会存储一个随机值做地址存储起来。等到用*p时,解开一个数作为地址把值10放进去根本不行,因为找不到对应地址
*p=10;
printf("%d\n",*p);
}
②:越界访问:
int main()
{
int arr[10]={0,1,2,3,4,5,6,7,8,9};
int*p=arr;
int i=0;
for(i=0;i<=sizeof(arr)/sizeof(arr[0]);i++)
{
//当指针指向的范围超出数组arr的范围时,p就是野指针
printf("%d\n",*p);
p++;
}
}
③:指针指向的空间释放:
int * mischief()
{
int a=10;
return &a;
}
int main()
{
printf("%d\n",mischief());
}
如何避免野指针?
1. 指针要初始化
2. 小心指针越界
3. 指针指向空间释放即使置NULL
4. 避免返回局部变量的地址
5. 指针使用之前检查有效性
这里注重讲一下第四点:
看下面的代码,刚接触了指针的知识就编出这样的代码,想着最后打印出来是10,结果真是10吗?
int* test()
{
int a = 10;
int* p1 = &a;
return p1;
}
int main()
{
int* p=test();
printf("%d\n", *p);
return 0;
}
运行结果:
![](https://img-blog.csdnimg.cn/img_convert/83e42e79558601146ec33462a4097360.png)
还真他妈是10!!!
但是:
#include <stdio.h>
int* test()
{
int a = 10;
int* p1 = &a;
return p1;
}
int main()
{
int* p=test();
printf("hehe\n");
printf("%d\n", *p);
return 0;
}
按照上面的代码,只是多了一个提前打印一个呵呵,本质上来讲应该是不会影响最后的结果;但调试后的结果如下:
![](https://img-blog.csdnimg.cn/img_convert/33363b4f73a2802f3a59f0f84bb52aef.png)
结果是5,这里就说明避免返回局部变量的地址简单的将就是空间被覆盖了
具体原因:(请看函数栈帧的创建和销毁)https://blog.csdn.net/sjsjnsjnn/article/details/122811828?spm=1001.2014.3001.5501
如果嫌长,那咱们就不了解全部,只了解这一部分知识,那么看这个:https://blog.csdn.net/iamxiaobai_/article/details/127102945和这个:https://blog.csdn.net/weixin_64308540/article/details/127444611
7.NULL的含义:本质上就是0,它是(void *)0强制转换的结果
8.如果不知道指针变量的初值是多少但又怕不赋产生野指针,就把NULL赋给它。作用:空指针,专门用来初始化指针
eg:int *pa=NULL;
for(pa!=NULL)
{
}
9.指针加减整数
示例一:
#define a 5
int main()
{
float values[a];
float *vp;
for(vp=&values[0];vp<&values[a])
{
*vp++=0;//++的优先级高于*,所以等价于:先*vp=0,再vp=vp+1;
}
}
示例二:
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = arr;
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", *(p + i));//指针p+下标(0~9),通过下标的访问并解引用找到了对应的值
}
return 0;
运行结果:
![](https://img-blog.csdnimg.cn/img_convert/50df2257795589f3fce4877e83a11c5c.png)
10.指针加减指针:两个指针要指向同一块儿空间(前提)
int arr[10]={0};
printf("%d\n",&arr[9]-&arr[0]);//指针-指针得到的是两个指针之间的元素个数(大减小为正,小减大为负)
![](https://img-blog.csdnimg.cn/img_convert/c154e17d8fc21f1b92d2e0b1a982f2fb.png)
11.求字符串长度:
方法一:
#include<stdio.h>
#include <string.h>
int main()
{
char roller[] = "abcdef";
int length = strlen(roller);
printf("%d\n",length);
}
方法二:递归
#include<stdio.h>
int mystrlen(char roller[])
{
int count = 0;
while (*roller != '\0')
{
count++;
roller++;
}
return count;
}
int main()
{
char roller[] = "abcdef";
int length=mystrlen(roller);
printf("%d\n", length);
}
方法三:指针加减指针
#include<stdio.h>
int mystrlen(char roller[])
{
char* start=roller;
while (*roller != '\0')
{
roller++;
}
return roller-start;
}
int main()
{
char roller[] = "abcdef";
int length=mystrlen(roller);
printf("%d\n", length);
}
12.指针的关系运算:
for(vp=&value[5];vp>&value[0])
{
*--vp=0;
}
简化后:
for(vp=&value[4];vp>=&value[0];vp--)
{
*vp=0;
}
注意:虽然简化后的代码可以运行,但我们还是要避免这样写,因为标准规定:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
13.arr[i]=i[arr]=*(arr+i)=*(i+arr)
14.数组名等价于首元素地址
![](https://img-blog.csdnimg.cn/img_convert/5cf25eb6c170230b7d4aaf320ce9ec4c.png)