c指针详解

1.什么是指针?

指针即地址。指针是个变量是用来存放变量内存地址的变量,不同类型的指针变量所占用的存储单元长度是相同的(32位机器为4个字节64位机器为8个字节),而存放数据的变量因数据的类型不同,所占用的空间长度也不同。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。

我们该如何理解它呢?

#include <stdio.h>
int main()
{
	int a = 10;//在内存中开辟一块空间
	int* p = &a;//取出变量a的地址,使用&操作符。
	//将a的地址存放在p变量中,p就是一个指针变量。
	*p = 0;//对指针进行解引用的操作,对这块内存中的内容进行修改
	return 0;
}

2.指针类型

2.1整型指针

int a = 0;   //p是一个整型指针变量,其存放的是a的地址
int* p = &a;

2.2字符指针

字符指针,即指向一个数组的指针

定义方式:

方式一:

char c = 'a';
char* pc = &c;

方式二:

char c = "hello world";
char* pc = &c;      //这种方式是将字符串c的首元素的地址存放在指针pc中

2.3数组指针

数组指针,即指向一个数组的指针。

定义方式:

int arr[5] = {0};
int (*p)[5] = &arr;  //p是指针,其指向数组arr的地址,指针指向的类型是一个有5个元素的整型数组

指针数组

指针数组,即元素为指针的数组(这里介绍时为了区分数组指针与指针数组)

定义方式:

int a = 0;
int b = 0;
int c = 0;
int* arr[3] = {&a,&b,&c};

2.4函数指针

函数指针,即指针指向一个函数的地址

定义方式:

int  fun(int a)    //定义一个函数
{
     return a;
}    

int (*f)(int a);   //定义一个函数指针
f=&fun;
int ret = f(a);//可通过函数指针去调用该函数
int z = (*f)(a);

需要注意的地方:上述代码在定义函数指针的时候“*f”加了小括号 注意优先级的问题,如果没有加()那么时定义了一个返回值为整型指针的函数

我们来看两段代码来感受一下函数指针

//代码1
(*(void (*)())0)();
//代码2
void (*signal(int , void(*)(int)))(int);

看代码1:

( void( * )( ) ) ,我们先看这部分,这括号内部分不难看出这是一个函数指针类型,接着是( void( * )( ) )0 结合0看是将0强制转换成 这个函数指针类型(这个函数是无返回值,无参数),转换后0是一个函数指针,将0解引用操作后找到这个函数的地址调用这个函数。

看代码2:

signal( int , void(*)(int) ),我们先看这部分,这也不难看出这是一个函数,其参数是int类型,和函数指针类型(这个指针所指向的这个函数无返回值,参数是int类型),接下来看外面的部分

void(*)(int);

外面的部分很明显是一个函数指针类型(这个指针所指向的这个函数无返回值,参数是int类型),这个就是函数signal( int , void(*)(int) )返回值类型,也就是说这个代码是一个函数的声明,它的返回值是一个函数指针参数是int类型,和函数指针类型

这里呢,可能有一些朋友会对返回值类型这里有些不能理解,那么我们来另一种理解方式:

typedef void(*pf)(int);
pf signal(int, pf);

这里我们使用typedef将这个函数指针类型进行了重新命名,那么这个指针pf就是上述的函数指针

pf signal(int,pf);

这个是转换后的代码,这个代码更容易让大家理解。

2.4.1函数指针数组

函数指针数组,即数组的元素类型为函数指针。

定义方式:

int (*pf[5])();

我们该如何理解它呢?

首先,pf先与[]结合说明pf是一个数组,再看int (*)();这个是一个函数指针类型,数组内存放的类型是函数指针类型。

2.4.2指向函数指针数组的指针

这是一个指针,指向的一个数组,这个数组内存放的类型是函数指针类型。

定义方式:

void test(const char* str)
{
printf("%s\n", str);
}
int main()
{
//函数指针pf
void (*pf)(const char*) = test;
//函数指针数组pfArr
void (*pfArr[5])(const char* str);
pfArr[0] = test;
//指向函数指针数组pfArr的指针ppfArr
void (*(*ppfArr)[10])(const char*) = &pfArr;
return 0;
}

如何理解呢?

先看 (*ppfArr) * 先和ppfArr结合,说明这是个指针,接着是[10],说明这个指针指向的是一个数组,再看最后外面的这一部分,

void(*)( const char *)这是个函数指针类型,即这个数组中存放的类型就是这个函数指针类型。

3.野指针

野指针,即指针所指向的位置是不确定的,是随机的,程序是不能控制的。

产生的原因:

1.局部指针变量没有初始化。

2.在用指针访问数组时,越界访问。

3.动态内存分配,指针在释放后没有置空。

规避野指针的方法:

在定义局部指针变量时,如果你不知道开始要指向谁,一定要让其指向一个空指针。

动态内存分配中在释放一个指针后,要将其置空。

4.指针运算

4.1指针的算术运算

来看一段代码:

int main()
{
	int a = 0;
	char b = 0;
	int* p1 = &a;
	char* p2 = &b;
	printf("p1=%p,p2=%p\n", p1, p2);
	p1++;
	p2++;
	printf("p1=%p,p2=%p", p1, p2);
	return 0;
}

在这里插入图片描述

一个指针加减整数后,其类型决定了它移动多少个字节

4.2指针的关系运算

for(p = &arr[5]; p > &arr[0];)
{
*--p = 0;
}

在这里插入图片描述

上述代码通过指针的关系运算来进行的,指针也可以进行比较大小,使用指针将一个数组的前5个元素都赋值为0。

5.指针与数组的关系

数组名,即数组首元素的地址,我们可以用一个指针变量来接受这个地址,通过指针来访问数组成员。

int main()
{
	int arr[5] = { 1,2,3,4,5 };
	int* p = arr;
	printf("p=%p   &arr[0]=%p\n", p, &arr[0]);
	for (int i = 0; i < 5; i++)
	{
		printf("%d\n", *(p++));
	}
	return 0;
}

在这里插入图片描述

这次的指针讲解就是以上这些,后续会更新更多的内容,如果有哪里写的有问题,希望大家可以指正。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值