2024-09-17 - 笔记 - 13
作者(Author):仟濹(网名)
指针
1. 指针是什么?
-
指针是内存中一个最小单元的编号,也就是地址
-
平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量。
指针就是地址
指针变量其就是存放地址的变量
2. 内存空间如何管理?
1 byte = 8 bit
总结
-
一个小的单元到底是多大? 1个字节
-
如何编地址?
一个字节给一个对应的地址是比较合适的。
就跟如下一样,每一个格子都是一个内存单元,一个内存单元为一个字节。
0 | byte |
---|---|
1 | |
2 | |
… | |
3. 32 位机器和64 位机器
32位机器
如果是32位机器的,有32根地址线(那么一个地址的大小 == 32 bit == 4 * 8 bit == 4 byte(字节),所以在32位的机器中,一个地址要用4个字节来存储,所以一个指针变量的大小4个字节 )
00000000 00000000 00000000 00000000 32个bit,四个byte
这样就有2 ^ 32 个地址 = 2 ^ 32 byte = 2 ^ 32 / 1024 KB = 2 ^ 32 / 1024 / 1024MB == 2 ^ 32 / 1024 / 1024 / 1024GB = 4 GB 所以 2 ^ 32(32个2相乘)个地址可以管理4GB的内存空间
所以,在32位的机器中,一个地址的大小位32位,也就是4byte
64位机器
64位机器有64个地址线
一个地址 == 64 bit == 8 * 8 bit = 8 byte(字节) == 一个指针变量的大小
所以,在64位的机器中,一个地址的大小位64位,也就是8byte
总结:
-
指针变量是用来存放地址的变量,地址是唯一表示一块地址空间的。
-
指针的大小在32位平台是4个字节,在64位平台是8个字节
-
其实机器是64位的将环境改成32位的,地址变量大小也会改变
4. 指针 和 指针类型
类型不同,大写一致
虽然指针类型不同,但是他们的大小(占的空间)是相同的。
int main()
{
char* pc = NULL;
short*ps = NULL;
int* pi = NULL;
double* pd = NULL;
//sizeof 返回的值的类型是无符号整型unsigned int
printf("%zu\n",sizeof(pc));
printf("%zu\n",sizeof(ps));
printf("%zu\n",sizeof(pi));
printf("%zu\n",sizeof(pd));
return 0;
}
32位结果为:4 4 4 4 64位结果为:8 8 8 8
5. 指针定义
int* = a;
略
指针类型的意义是什么???
char* 类型的指针是为了存放char的地址 int* 类型的地址是为了存放int的地址 ……
像一维数组int arr[5]
中,arr代表的是首元素的地址,类型就为int*
6. 野指针 / 空指针
概念:就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针怎么形成的
-
没有初始化(一个局部变量不初始化,放的是随机值)
int* p; p = 105;
-
指针的越界访问
int main() { int a[5] = {1, 2, 3, 4, 5}; for(int* p = a; p <= a + 5; p ++) { printf("%d", *p);//当进行最后一次循环的时候,指向的是a[5],越界访问 } }
-
指针变量指向的空间释放。返回局部变量的地址。
int* fun() { int a = 10; return &a; } int main() { int* p = fun();//错误,返回的地址空间被释放 return 0; }
如何避免空指针(***重要,新知识点)
#include <assert.h>
int main()
{
int *p;
assert(*p != NULL);//这样子就会在运行以后,自动弹窗报错
return 0;
}
7. 指针运算
-
指针
+-
整数eg:
int main() { int a[5] = {1, 2, 3, 4, 5}; for(int* p = a; p < a + 5; p ++) printf("%d", *p); }
*p++
And(*p)++
第一个是地址++,第二个是值++ -
指针 - 指针 (指针 + 指针没有实际意义,但不报错)
指针 - 指针 后的绝对值得到的是指针和指针之间元素的个数。
注:指向同一块空间的两个指针才能相减。
eg:连续数组 两个元素地址的相减int main() { int arr[5] = { 0 }; printf("%d", &arr[4] - &arr[0]);//结果为: 4 printf("%d", arr + 5 - arr);//5 return 0; }
&arr[0] &arr[1] &arr[2] &arr[3] &arr[4] ^ ^ ^ ^ ^
arr arr + 1 arr + 2 arr + 3 arr + 4
注:越界访问只能往后越界,不可往前越界
8. 指针和数组
指针和数组经常结合在一起使用
略
int main()
{
int a[5] = {1, 2, 3, 4, 5};
for(int* p = a; p < a + 5; p ++)
printf("%d", *p);
} int main()
{
int a[5] = {1, 2, 3, 4, 5};
for(int* p = a; p < a + 5; p ++)
printf("%d", *p);
}
9. 二级指针变量 - 存放【指针变量】的地址的变量(***)重要
-
这种叫一级指针
int a = 10; int* p = &a;
-
这种叫二级指针
82. 【C语言初阶】指针指针收尾哔哩哔哩_bilibili
int a = 10; int *p = &a; int** pp = &p; //Or: int* *pp = &p;Or: int **pp = &p;
两个*代表什么意思???
第 2 个*说明的是 pp 是指针,第 1 个int*说明 pp 指向的i对象是int* 类型的
我不能仅仅知道
int**
代表的二级指针,更要知道每个*
代表的意义。
指针数组(***)重要
定义: 存放指针( 地址 )的数组就是指针数组。
int a, b;
a = 2;
b = 3;
int* parr[10] = { &a, &b };
10. const + 指针 (***重要,新知识点)
const如果写在定义变量的前面,就相当于变成了具有常量性质的一种变量。
const 的作用其实就是为了保护数据。
-
+
-
const int num = 20; const int num = 10; num = 20;//修改不了
-
但是如果用指针去访问这个变量,就是可以修改的,间接破坏了
const
的作用const int num = 10; num = 20;//修改不了 int *p = # *p = 20;//这种情况之下就可修改,这就破坏了const不可修改的作用
怎么办呢???可以用下面的方法
-
const int* p = #
此时const修饰的是*p
意思是p指向的对象不能通过*p来改变,但是p变量本身存储的地址是可以改变的。
const int num = 10; num = 20;//修改不了 int *p = # *p = 20;//这种情况之下就可修改,这就破坏了const不可修改的作用 const int* p = #//这样就可以保证即使是p指向变量,然后通过*p修改也修改不了p指向的变量的值 *p = 20;//此时就不可修改了
p可以改变指向的对象吗???
当然可以,因为p变量本身的存储的地址是可以改变的
虽然不可改变*p,但是仍然可以改变p指向的对象。
下方位例
const int num = 10; num = 20;//修改不了 int *p = # *p = 20;//这种情况之下就可修改,这就破坏了const不可修改的作用 const int* p = #//这样就可以保证即使是p指向变量,然后通过*p修改也修改不了p指向的变量的值 *p = 20;//此时就不可修改了 int n = 100; p = &n;//这种是可以修改的,可以改变p指向的对象
那更改了p指向的对象以后,已经改变了在const在刚开始定义的时候指向的变量,那这种情况可以更改二次指向的变量的值吗???
不可以,因为一旦有了
const int* p;
就意味着p指向的对象不能通过*p来改变,无论p指向的是否是什么对象。
并不是只有在这种在
const int* p = #
指向第一次使用const修饰定义*p的时候指向的num才不会改变。int main() { char a[10] = "abcdef"; const int num = 10; const int* p = # int n = 100; p = &n; *p = 300;//报错,改变了指向的对象,依然不可以改 }
-
int* const p = #
p指向的对象是可以改变的,但是不能修改p指针所指向的对象。
*p = 300;int main() { char a[10] = "abcdef"; const int num = 10; int* const p = # *p = 20;//可以改变p指向的对象的数值 p = &n;//报错,但是不可以改变p指针变量中存储的地址,意思就是不可改变指向的对象。 // 在第一次指向的时候就已经固定只能指向刚开始定义时就指向的对象了。 }