【C语言指针】函数指针及回调函数、动态空间分配以及释放、二级指针的应用

int* p;*p=8;//非法,p此时为野指针,不能直接赋值
while(*p++)//不是死循环
restrict关键字

概括的说,关键字restrict只用于限定指针;该关键字用于告知编译器,所有修改该指针所指向内容的操作全部都是基于(base on)该指针的,
即不存在其它进行修改操作的途径;这样的后果是帮助编译器进行更好的代码优化,生成更有效率的汇编代码.
注:两个由restrict关键字修饰的指针不会执行重叠内存空间
例子:void *restrict ptr;

void指针(无类型指针)

任何类型的指针都可以赋给void指针,但是void指针不能直接赋值给其他类型的指针,需要强制类型转换

void* p1;
int* p2;
p2=(int*)p1;

如果函数参数可以是任意类型指针,应该将参数声明为void指针
如:void memcpy (void s1, const void* s2, size_t n);

一、函数指针

声明函数指针:
1、(类型*)(类名::*指针名)(参数列表)=类名::函数名;

int add(int n1,int n2)
{return n1+n2;}
int (*p)(int ,int )=add;//执行add函数的指针,加不加&都一样
void main()
{
	printf("add(1,2)=%d\n",(*p)(1,2));//*p一定要用括号包围,或者直接p(1,2)
}

2、typedef 类型 (*指针名)(参数列表);

//创建了一个函数指针类型ptr
typedef int (*ptr)(int ,int)
int sub(int n1,int n2)
{return n1-n2;}
void main()
{	
	//定义
	ptr p1=sub;
	printf("sub(2,1)=%d\n",(*p1)(2,1));//p(2,1)
}
函数指针应用:回调函数

例:

typedef int(*p)(int,int);

int callback_add(int x,int y,p func)//也可以不用typedef,直接在参数里写int(*p)(int,int)
{
	return func(x,y);
}
int add(int x,int y)
{
	return x+y;
} 
void main()
{
	int x=3,y=4;
	int z=callback_add(x,y,add);//z=7;
} 

一个用于排序的回调函数,通过调用不同的函数指针实现对不同类型数据的排序

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//void*,因为排列函数也是void*,不然会出警报
int cmp_int(const void* n1,const void* n2)
{
        return (*(int*)n1-*(int*)n2);
}
int cmp_double(const void* n1,const void* n2)
{
        if(*(double*)n1-*(double*)n2>0)
                return 1;
        else
                return 0;
}
//排序
void sort(void* data,const int n,const int size,int(*ptr)(const void*,const void*))
{
        int i,j;
        void* temp=malloc(size);
        void* arr1,*arr2;
        for(i=0;i<n-1;i++)
        {
                arr1=data+i*size;
                for(j=i+1;j<n;j++)
                {
                        arr2=data+j*size;
                        if(ptr(arr1,arr2)>0)
						{
                                memcpy(temp,arr1,size);
                                memcpy(arr1,arr2,size);
                                memcpy(arr2,temp,size);
                        }
                }
        }
        free(temp);//free-----
}
int main()
{
	int i;
	int group_ints[10] = {4,5,3,2,3,4,6,8,9,10};
	double group_doubles[10] = {12.3,4,5,3.4,1,8.12,45,23,3.14,78};
	printf("ints test-----------------\n");
	sort(group_ints, 10, sizeof(int),cmp_int);
	for(i=0; i<10; i++)
	printf("%d ", group_ints[i]);
	printf("\n");
	printf("dobs test-----------------\n");
	sort(group_doubles, 10, sizeof(double),cmp_double);
	for(i=0; i<10; i++)
	printf("%.2f ", group_doubles[i]);
	printf("\n");
	return 0;
}

二、malloc和free

注意:若指针为全局指针,无法在全局声明就直接动态分配空间(即无法在函数体外分配空间)
1、void* malloc(size_t size) ///参数是字节数
注意:malloc出来的空间,想改变其内的值不能简单使用=(应该使用memset、memcpy、memmove),=是浅拷贝,只是改变了指向,这样做的后果是内存泄漏,而且最后free这个指针的时候,由于指向改变,也会报错
例:创建一个4个int大小的数组空间

int* arr=(int *)malloc(4*sizeof(int));//(int *)为强制类型转换

2、void free(void* ptr)//与malloc配套使用:

free(arr);

3、free使用注意事项

free的指针必须是指向malloc函数开辟出的空间的首地址
(即指针在释放前应该变回首地址,或采用另一个指针存储首地址)

4、malloc创建二维数组
1)使用数组指针形式创建

//为数组指针,int*a[]为指针数组,[]的优先级大于*;
int (*a)[2]=(int(*)[2])malloc(sizeof(int)*3*2);
//创建一个数组指针,数组存放了2个int数据。
//若多出数据两个数据则按每行2个int排列(即变成多维数组)
free(a);//释放内存

2)使用二级指针创建

int** a;int rows=2;int cols=3;
//需要malloc两次
a=(int**)malloc(sizeof(int*)*rows);
for(int i=0;i<rows;i++)
	a[i]=(int*)malloc(sizeof(int)*cols);
//free,需要free两次
for(int i=0;i<rows;i++)
	free(a[i]);
free(a);

5、calloc

void* calloc(int num,int size);//num为个数,size为每个的字节大小

和malloc的区别:会初始化为0,比较耗时
6、realloc

void* realloc(void* address,int newsize);//重新分配空间

三、二级指针(慎用,能不用则不用)
使用原因:由于C语言没有引用类型,如果要在函数内改变指针指向,只能使用二级指针

以下函数改变不了指针:

void changePtr(int* p)
{
	p = (int*)malloc(4 * sizeof(int));
	if (p)
	{
		for (int i = 0; i < 4; i++)
		{
			p[i] = i;
		}
	}
}
void main()
{
int* a = NULL;
	changePtr(&a);
	if (a)
	{
		for (int i = 0; i < 4; i++)
		{
			cout << "a[" << i << "]=" << a[i] << endl;
		}
		free(a);
		a = NULL;
	}
}

结果:空
原因:函数参数传入指针,只能改变指针指向地址存储的值,无法改变指针指向

改变指向的两种方法

1、使用指针类型返回值

int* changePtr()
{
	int *p = (int*)malloc(4 * sizeof(int));
	if (p)
	{
		for (int i = 0; i < 4; i++)
		{
			p[i] = i;
		}
	}
	return p;
}

2、使用二级指针

int changePtr(int** p)
{
	*p = (int*)malloc(4 * sizeof(int));
	if(*p)
	{
		for (int i = 0; i < 4; i++)
		{
			(*p)[i] = i;//*p要加括号
		}
	}
}

结论:函数内改变指针指向要使用指针类型返回或者使用二级指针。不过使用指针返回值的方法中,局部指针变量开辟的动态空间存放在堆区,即使函数结束也不会自动释放,又因为要返回指针(返回前不能释放) 故,使用指针返回值的方法会造成内存的泄露,还是使用二级指针妥当。

链接

用malloc动态申请一个二维数组的三种方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值