08 C语言指针
1、取地址运算
- 取地址运算符 & 是一元运算符,用于返回一个变量或对象在内存中的地址。例如,如果有一个名为x的变量,那么&x将返回x在内存中的地址。除了对变量进行取地址运算,还可以对指针变量进行取地址运算,得到指针变量本身的地址。例如,如果有一个名为p的指向int类型变量的指针变量,那么&p将返回p在内存中的地址。
- 取地址运算符 & 只能对具有内存地址的变量进行操作,因为只有变量才会在内存中占用一定的空间,才能有地址。因此,不能对常量、表达式、函数名等进行取地址运算。
- 取出来的地址大小取决于编译器和处理器的架构。在32位系统中,地址通常是4字节长,而在64位系统中,地址通常是8字节长。在一些嵌入式系统中,地址可能只有2字节或更少。
- 为了打印地址,可以使用 %p 格式化字符,例如:printf(“The address of x is %p”, (void*)&x); 在使用%p格式化字符打印地址时,需要将地址强制转换为void指针类型,这是因为%p只接受void指针类型的参数。
- 在内存中,变量地址是按照从低地址到高地址的顺序分布的,自底向上分布。数组名是数组首个元素的地址,而相邻的数组元素的地址之间相差一个数据类型的大小。例如,如果一个整数数组的第一个元素的地址为0x1000,那么第二个元素的地址为0x1004(如果是32位系统),第三个元素的地址为0x1008,以此类推。指针变量也是如此,指针变量在内存中的地址也是按照从低地址到高地址的顺序分布的,自底向上分布。
2、指针变量
int *p
的含义是 p
是一个指向 int
类型变量的指针变量,而不是指针存放的地址是 int
类型。- 指针变量存储的值是一个内存地址,它指向一个具有有效值的普通变量。
- 当一个指针被解引用时,使用指针所指向的地址读取或写入该地址中存储的值。
*
作为一元运算符,可以用于访问一个指针变量所指向地址中存储的值。作为左值进行赋值时,可以修改指针变量所指向地址中存储的值。&
运算符可以取出一个变量的内存地址,而 *
运算符可以通过一个指针变量访问该地址中存储的值。它们是相互关联的操作,但并不是相互反作用的。
3、指针的应用场景
1、交换两个变量。
2、函数返回值不止一个;传入的参数就是需要保存带回来的结果。
2、函数返回运算状态,结果用指针返回。
指针必须指向一个变量,否则直接访问会对不明确的地址进行访问,会有严重错误。
4、指针与数组
1、在函数的参数列表里面,数组int a[] == int * == int *a,但是可以通过[]进行数组运算。
2、数组变量是const指针,所以无法把一个数组直接赋值给另一个数组,因为数组变量存放的地址是数组首个变量的地址,为常量不可以修改。
3、[]和*符号可以对数组进行操作,可以对指针进行操作。
5、指针与const
1、指针本身可以是const,变量本身也可以是const
2、* const 表示的是指针是const,*const p = q说明,p当中只能是q的地址,不可被修改。类似于数组a[10]当中,a[]和a表达的是 * const ,指针常量不可修改
3、const *表示不可以通过指针去改变变量,但指针所指的变量不会变成const
4、传参数的时候可以使用const*避免变量被修改。
5、const int a[10],表面数组的每个变量都是const,所以必须初始化才能赋值。
6、在传参数的时候防止数组被破坏,可以将数组参数设置为const。
6、指针计算
*p++
这个表达式会先取出指针 p
指向的地址上的值,然后将指针 p
加上它指向的数据类型的大小,指向下一个地址。例如,如果 p
是一个 int
类型的指针,那么 *p++
将会先取出 p
所指向地址上的 int
值,然后将 p
加上 sizeof(int)
,指向下一个 int
类型的地址。- 两个指针相减得到的是它们之间相差的地址数量,也就是它们之间隔了多少个数据类型大小的空间。例如,如果
p1
和 p2
都是 int
类型的指针,那么 p2 - p1
的结果将是两个指针之间隔了多少个 int
类型的大小。这个值通常被称为指针之间的偏移量。 *p++
表达式的执行过程是先取出 p
所指向地址上的值,然后将 p
加上它指向的数据类型的大小,指向下一个地址。因此,*p++
的结果是取出 p
所指向地址上的值。这个表达式实际上等价于 *(p++)
。- 不同类型的指针之间不能相互赋值,这是因为不同类型的指针所指向的内存结构是不同的。即使它们的地址大小相同,它们指向的数据类型也可能不同,因此在使用指针的时候需要格外小心,避免出现类型不匹配的问题。
7、动态内存分配
- 数组动态申请内存int *p =(int *)malloc(sizeof(int) * n) 这行代码的意思是,申请一个长度为n的int类型数组,p指向这段内存的首地址。由于malloc返回的是void类型指针,需要进行强制类型转换。
- 动态申请的内存是字节为单位的。 malloc函数申请的内存是以字节为单位的,因此需要通过sizeof运算符计算需要申请的字节数。
- 如果申请失败了,返回的是0 如果内存申请失败,malloc函数会返回一个NULL指针。因此,我们需要在申请内存后检查返回值是否为NULL,以确定是否申请成功。
- 申请完地址,需要free,malloc和free参数需要一致。 在动态内存分配中,申请到的内存空间需要手动释放。使用free函数可以释放已申请的内存。需要注意的是,释放内存时需要确保指针参数与申请内存时返回的指针参数一致,否则会出现不可预料的问题,甚至导致程序崩溃。