首页
论坛
课程
招聘
[基础知识] [分享]C语言基础五-指针
2021-5-12 17:55 977

[基础知识] [分享]C语言基础五-指针

2021-5-12 17:55
977

指针的定义

指针的含义包含三个方面:变量、地址、内存宽度:

  • 变量:指针是一个变量,x86占4个字节,x64占8个字节。
  • 地址:指针的值是一个内存地址,指向内存的某一个地方。
  • 内存宽度:指针明确了指向内存的宽度,通过指针的类型确定。

在定义指针的时候,*和类型结合,表示指针的类型; 在使用指针的时候,*和指针结合,表示解引用。

指针的初始化

可以让指针指向某个变量的地址,也可以让指针指向一个分配的内存或者字符串常量,还可以指向NULL。

1
2
3
4
5
6
int nNum = 1;
int* pNumA = &nNum;
int* pNumB = NULL;
pNumB = (int*)malloc(sizeof(int));
char* szTest = "testString";
char* szBuf = szTest;

取地址运算符&

  • 取变量的地址,reference,引用。
  • &和*互为逆运算。

解引用运算符*

  • 取地址对应内存中的内容,dereference,解引用。
  • 解引用运算符后面必须是指针,不能为无效的内存,也不能为NULL,否则程序运行会崩溃。
  • 定义一个指针p,*p表示通过指针指向的内存地址,找到对应的内存和里面存放的数据,进行读取或者修改操作。

指针的数据类型

定义一个指针,指针类型的变量长度为4或者8,即sizeof(p)= 4or8,指针所指类型的长度为sizeof(*p)。
void*类型的指针变量,没有指定内存的宽度,其他类型指针隐式转换成该类型,不能用*p解引用取值,需要先转换成特定类型再取值。对于指针变量void* p:

  • p可以接受任何类型的指针。
  • p赋值给其他类型指针时需要强转。
  • p不能直接进行解引用运算,必须先转换。
  • p不能直接进行加减算术运算,必须先转换。

char*类型的指针变量,既可以指向字符,也可以指向字符串,即字符串首个字符的地址。字符指针初始化时,字符使用单引号,字符串使用双引号。

1
2
3
4
5
6
int nNum = 1;
int* pNum = &nNUM;
void* p = pNum;
printf("%d",*(int*)p);
char* szBufA = 'p';
char* szBufB = "test";

指针的运算

指针支持加减运算,不支持其他算术运算。对于指针p,指针的加法运算p+n,p向后移动的距离不是n个字节,而是n个指针所指类型的单位长度,即nsizeof(p),减法运算与此类似。

数组和指针

数组名是一个常量指针,指向数组的首地址,指针和数组名可以互相通用。

1
2
3
4
5
6
7
int nArray[3] = {1,2,3};
//第i个元素
printf("%d\n",a[i]);
printf("%d\n",*(a+i));
//第i个元素的地址
printf("%p\n",&a[i]);
printf("%p\n",a+i);

常量指针与指针常量

1
2
3
4
5
6
//常量指针,p是一个常量指针,不能修改,指向的内存可以修改
int* const p;
//指针常量,p是一个指针,指向的内存是常量,不能修改,p本身可以修改
const int* p;
//p是一个常量指针,指向的内存也是常量,都不能修改
const int* const p;

指针数组与数组指针

1
2
3
4
//指针数组,存放10个指针的数组
int* a[10];
//数组指针,存放的是地址,指向另一个指针,有10个元素的数组的首地址
int(*a)[10];

函数指针与指针函数

函数指针

  • 函数名,就是函数的地址。
  • 函数的签名,包含函数的返回值类型,参数类型,参数个数。
  • 如果一个指针变量,存放的是函数的地址,那么就把这个指针叫做函数指针,函数指针的类型由对应的函数签名来决定。

指针函数

  • 返回值是指针的函数。
  • 指针函数不能返回局部变量的地址,指针或者引用,因为局部变量的地址会随着函数调用结束被自动释放,指针会成为一个野指针,可以返回堆上的内存地址。

定义函数指针的两种方法

  • 直接用函数的签名定义函数指针。
  • 用typedef关键字定义函数指针的类型,再用指针类型定义函数指针。
  • vs2019中,为函数指针赋值,函数名func等同于&func。

二级指针

如果指针做实参,那么传实参的指针就必须使用二级指针,要在函数中改变指针的值,就必须传指针的指针。

1
2
3
4
5
6
//为指针分配堆内存
char *p = (char*)malloc(128);
if(p==NULL)
{
    return 1;
}

指针的复杂声明

指针在声明的时候必须初始化,如果没有初始化,任何指针变量在被创建的时候,不会自动成为NULL指针,会随机的指向任何一个地址,它的缺省值是随机的,即野指针,访问野指针会造成不可预知的后果。

1
2
3
4
5
6
7
8
//a和*结合,a是一个指针
//a和[]结合,a是一个数组
//a和()结合,a是一个函数
 
int* a[10];//指针数组
int(*a)[10];//数组指针
int* a(int);//指针函数
int(*a)(int);//函数指针

为什么要使用指针

  • 通过内存地址直接操作内存,性能高。
  • 函数传参时,传指针比传值可以减少拷贝,效率高。
  • 复制指针之后,解引用取出数据,无论在时间还是空间上,都比直接复制及访问数据高效。
  • 指针可能跑飞,破坏其他部分的程序数据,造成内存泄露。
  • 传引用比传指针安全。

github:https://github.com/0I00II000I00I0I0

bilibili:https://space.bilibili.com/284022506


第五届安全开发者峰会(SDC 2021)议题征集正式开启!

收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回