指针的定义
-
概念
指针就是内存地址,指针变量是保存地址的变量。
-
变量定义
//整型指针: int *i_pointer = &i;//*i_pointer拿到4字节(整型) //字符指针: char *c_pointer = &c;//*c_pointer拿到1字节(字符型)
间接访问
-
&是取地址运算符,它返回变量的地址。*是解引用运算符,它用于指针,返回指针所指向地址的值。 -
int *i_pointer = &i;//i_pointer保存的是变量i的起始地址 *i_pointer=10;//间接修改i的值
指针变量的大小
-
系统差异
- 64位系统:指针变量占8个字节(sizeof(i_pointer))
- 32位系统:指针变量占4个字节(sizeof(i_pointer))
-
取值大小(注意与上面区分)
- sizeof(*_pointer)(等于sizeof(i))(4字节)
- sizeof(*_pointer)(等于sizeof©)(1字节)
-
重要特性
- 指针变量大小固定,与被指向变量大小无关
- 指针只存储变量的起始地址
指针的传递使用场景
这样子不会改变主函数a的值
- 值传递机制:它调用的是值传递,实参a的值复制给b
- 内存隔离:主函数main和change函数都有独立的栈空间,互不影响
#include <stdio.h>
void change(int b)
{
b = 10;//只会影响变量b的值,对a没影响
}
int main()
{
int a = 100;
printf("before change\n");
change(a);//传的是a的值
printf("after change\n");
printf("%d", a);//输出100
}
使用指针间接访问
-
地址传递:传递的是变量a的地址,而不是值
-
间接修改:通过*j=5访问变量i的内存空间
#include <stdio.h> void change(int *b) { *b = 10;//直接修改a在内存地址的值 } int main() { int a = 100; printf("before change\n"); change(&a);//传的是a的内存地址 printf("after change\n"); printf("%d", a);//输出10 }
指针的偏移
指针偏移是指针的加减运算,通过指针变量进行加或减操作实现内存地址的移动。
指针加减1时,实际偏移的长度是其基类型的大小(如int型指针偏移sizeof(int)字节)
#include <stdio.h>
void change(int *b)
{
b[1] = 10; // 下标直接修改
*(b + 2) = 99; // 指针偏移
}
int main()
{
int a[4] = {1, 3, 4, 6};
int *p;
p = a;
change(p);
for (int i = 0; i < 4; i++)
{
printf("%3d", *(p + i)); //*(p+i)相当于a[i]
}
//输出1 10 99 6
}
栈空间和堆空间
-
栈空间:存放main函数的局部变量
-
堆空间:通过malloc动态申请内存区域
-
管理方式:栈由系统自动管理,堆需要手动申请(malloc)和释放(free)
-
大小确定性:栈空间大小在编译时确定不可变,堆空间可以动态改变
-
生命周期:
-
堆:
函数内定义的局部变量存储在栈空间,函数执行结束后,栈空间自动释放
(例:char c[100] = “I am print_stack func”; 存储在栈空间)
-
堆
通过函数
malloc手动申请内存空间需要手动释放,否则会一直存在
(例:char *p = (char)malloc(100); 申请100字节堆空间)
-
指针与malloc动态内存申请
-
动态内存申请
-
malloc函数
- 头文件:#include <stdlib.h>
- 原型:void* malloc(size_t size)
- 参数:整型变量,申请字节数
- 返回值:无类型指针(void*),要强行转换成具体类型
-
案例
需要注意必须将void转换为具体指针类型
若存储字符串需包含结束符’\0’的空间
free时必须使用malloc返回的原始指针值,忘记free会导致内存泄漏
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int size; // 记录申请空间大小 scanf("%d", &size); char *p; p = (char *)malloc(size); strcpy(p, "malloc success"); // 使用分配的空间 puts(p); free(p); // 释放时必须使用原始地址 return 0; }(考研重点:链表、树等数据结构都需要使用堆空间)
-
注意事项
-
推荐使用int *a,而不是用int* a
(例:int* a,b,c 很多人会很自然的以为三个都是整型指针,但其实只有a是整型指针,其他两个只是普通的整型变量) -
禁止跨类型指针赋值
float a; int *p; p = &a;//毫无意义且会报错 -
“&” 和 "*"的优先级一样,计算*&a,要按自右向左方向结合,但一般不会结合去使用
-
先计算
&a,得到变量a的地址。 -
然后对
&a的结果(即地址)使用*运算符,即解引用该地址,得到该地址存储的值,也就是a的值。
因此*&a等于a
-
-
内存释放
- free时必须传入malloc返回的原始地址,不能是偏移后的地址
- free参数位void*,任何指针可以自动转换,直接传入
- 若free时地址不匹配,会导致进程崩溃

被折叠的 条评论
为什么被折叠?



