指针
目录
1. 指针是什么?
指针理解的2个要点:
1. 指针是内存中一个最小单元的编号,也就是地址
1.怎么理解指针是内存中一个最小单元的编号,也就是地址
我们的买的电脑一般都是8G或者16G的内存
那这些内存空间是如何管理的呢?
计算机是把这些内存空间切割成内存单元 ——1个内存单元的大小为1byte
2.如何理解:平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量
我们创建一个整形变量a,a在内存中如图所示占4个字节的内存空间,里面存放了10。现在我们用pa这个指针变量来存放a的地址。
下面是通过监视来证明pa里面存放的是a的地址。
总结:指针变量里面存放的是地址,通过这个地址,就可以找到一个内存单元。
3.计算机是如何编址的?
这里顺便说一下计算机是如何编址的(蛮重要的)
2.指针和指针类型
1.指针类型
我们都知道,变量有不同的类型,整形,浮点型等。那指针有没有类型呢?
有的,比如:
int a=0;
int* pa=&a;
这里的指针pa的类型是int* 它的意思是,pa这个指针存放的是int类型的变量的地址。
同样
double b=0;
double* pb=0;
那么pb这个指针它的类型就是double*,意思是pb存放的是double类型的变量的地址。
2.指针的解引用
pa存放的是a的地址,在pa前面加上*号,就可以对pa进行解引用,通过解引用我们就可以通过pa里面存放的a的地址来找到a,并对a进行操作。所以*pa=0等价于a=0
我们创建了一个整形变量a初始化为0x11223344,然后把a的地址给pa,最后对pa进行解引用,把0赋给a。
首先通过调试我们可以看到到当程序走完int a =0x11223344时,a的地址存放的是44 33 22 11我们可以把它倒过来读,也就是我们的11 22 33 44
可以看到当程序走完*pa=0时,a的值就变成了0,里面存放的都是0。
我们现在把 pb的指针类型改成char*类型,然后和上面进行同样的操作,通过解引用把0赋值给a
可以看到,虽然char*类型也能存放a的地址(因为指针存放的是地址,在32位平台上,大小都为4个字节) 。但是我们对pb进行解引用时,它只访问了一个字节。只是把44改成了0,所以它输出的结果不是0
补充一下:一个16进制数比如0x11223344占4个字节,一个十六进制数字比如这里面的最后一个数字4,它翻译成4个2进制位,也就是4个bit位。那么2个16进制数字就是1个字节。所以16进制数字占4个字节。
为了方便大家理解,这里给大家翻译一下0x11223344
0x11223344
0001 0001 0010 0010 0011 0011 0100 0100
结论
指针类型决定了指针在被解引用时,访问几个字节
例:如果是int*类型的指针,解引用访问4个字节
如果是char*类型的指针,解引用访问1个字节
3.指针+-整数
可以看到pa,和pb存放的都是a的地址,但是当它们+1时,它们的地址不相同。
pa+1,它的地址跳过了4个字节。pb+1,它的地址跳过了1个字节。
结论
指针的类型决定了,指针+-1操作时,跳过几个字节。
通俗点说:指针的类型决定了,指针的步长。
3.野指针
1.指针未初始化
我们这里没有给指针变量p初始化(就是没有给它一个明确的地址),在C语言中,如果不给指针初始化的话,它里面存放的是随机值。当我们对p进行解引用时,它是把生成的随机值当作地址,然后访问这个地址。这样做是非法的,这里的p就是野指针。
2.指针越界访问
我们这里的p也是野指针,因为a是一个局部变量,当a出代码块{}时,a就已经销毁了,我们用p存放a的地址(&a),p里面存放的a的地址已经不能使用了。
4.如何避免野指针
4.指针运算
1.指针+-整数
现在有一个初始化为0的数组arr[10]=0,我们如何把它里面的每一个元素赋值为1?
没学数组之前大家应该都是这样写的
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
//sizeof(arr)计算的是整个数组的大小
//sizeof(arr[0])计算的是数组首元素所占空间的大小
//sz得到的就是数组有多少个元素
for (i = 0; i < sz; i++)
{
arr[i] = 1;
}
return 0;
}
辣么学完指针后,我们还可以怎么写呢?
int main()
{
int arr[10] = { 0 };
int* p = arr;
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < sz; i++)
{
*p = 1;//对p进行解引用,把p所指向的对象赋值为1
p++;//这里的p++相当于p=p+1=arr+1
}
return 0;
}
还可以这样写:
int main()
{
int arr[10] = { 0 };
int* p = arr;
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < sz; i++)
{
*(p + i) = 1;//这里其实就相当于把上个程序的*p=1和p++给合并了
//意思是先给p里面存储的地址+i,然后对它解引用。
}
return 0;
}
为了便于大家理解,给大家说下:当i=0时,*(p+i)相当于arr[0],当i=1时,*(p+i)相当于arr[1],当i=2时,*(p+i)相当于arr[2],以此类推……
2.指针-指针
总结:指针-指针得到的是指针和指针之间的元素个数。
不是所有指针都能相减,指向同一块空间的2个指针才能相减。
指针-指针有什么作用呢?
这里给大家举个例子:
我们在求字符串长度时,会用到strlen这个库函数,它可以帮我们求出字符串的长度。那我们可不可以自己设计一个函数来求字符串的长度呢?
学完指针-指针,我们还可以怎么写呢?
5.指针和数组
指针变量:是一个变量,里面存放的是地址
数组:一组相同元素的集合
那么它们之间有什么联系呢?
可以看到,p+i等价于&arr[i],*(p+i)等价于arr[i]、
我们可以用指针来访问数组:
#include <stdio.h>
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int *p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i<sz; i++)
{
printf("%d ", *(p + i));
}
return 0;
}
6. 二级指针
二级指针变量是用来存放一级指针变量的地址的
这里大家想到了什么?对,没错,就是它——洛必达法则,无限套娃【dog】
7.指针数组
指针数组:存放指针的数组
我们也可以打印数组里面的内容
用指针数组模拟一个二维数组:
我们先写一个二维数组:
我们现在再用指针来模拟一个二维数组
好啦,初阶指针的内容就给大家讲到这里啦,家人们如果觉得有帮助,还请来个一键三连【dog】