嵌入式学习日志16、17:指针函数和函数指针、二级指针、const指针、void*万能指针

接上一节

目录

十一、指针函数和函数指针

11.1  指针函数

11.2  函数指针

十二、二级指针

十三、const指针

十四、void *万能指针


十一、指针函数和函数指针

11.1  指针函数

函数的返回值为指针类型的函数,叫做指针函数

  • 不要返回局部变量的数据(eg: 局部变量、局部数组)
  • 作为另外一个函数的参数

#include<stdio.h>

int *fun()
{
	//函数调用完会释放
	int a=20;  //2000
	return &a;  //return 2000  
	//局部变量当函数调用完会释放,虽然返回了地址,但是变成了野指针
}

char *fun1()
{
	//char str[100]="hello";  //主要是局部变量,函数执行完空间释放
	static char str[100]="hello";//空间开辟在数据区,全局生命周期
	return str;
}

char *fun2()
{
	//char str[100]="hello";//局部变量,不能返回
	char *p="hello";  //字符串常量(数据段:全局生命周期)类型 char* 说明存放的是字符串的地址
	printf("%p\n","hello");
	return p;

}
int main()
{
#if 0
	int *p=fun();
	printf("ret = %d\n",*p);
#endif

	char *p=fun2();
	printf("p %s\n",p);
	return 0;
}
#include<stdio.h>
int main()
{
	char str[100]="hello";
	//char *p="hello";
	char *p=str;

	//str[0]='a';
	//printf("%s\n",str);//aello
	//通过数组可改,存储的地址是栈区,可读可写
	
	//p[0]='a'; 
    //存储的地址是数据段的.rodata段,保存字符串常量,不可改
	*p='a';
	printf("%s\n",p); //aello
	printf("%s\n",str); //aello
}
#include <stdio.h>
char * mystrncpy(char*dst ,char* src,int n)
//返回值为指针类型
{
    char * tmp = dst;
    while((*dst=*src) && --n) 
    {
        dst++;
        src++;
    }
    if(0==n)
    {
        *(dst+1) ='\0';
    }
    return tmp;
}
int main()
{

    char str1[100]="hello";
    char str2[100]={0};
    char* p = mystrncpy(str2,str1,10);
    printf("%s\n",p);
    printf("%s\n",str2);
    return 0;
}

11.2  函数指针

函数指针,本质是一个指针,存储某一个函数的地址<“把操作存入指针”>函数名本质也是一个指针,存储了一个地址,指向代码段中一个对数据操作的代码

函数名对应的地址-->指针

#include<stdio.h>

double add(double a,double b)  // int (*)  (int,int)
{
	return a+b;
}
double sub(double a,double b)
{
	return a-b;
}
double mul(double a,double b)
{
	return a*b;
}
double div(double a,double b)
{
	return a/b;
}
int main()
{
	//add(a,b)
	double (*p)(double,double)=NULL; //函数指针
	double a=10;
	double b=20;
	int choose = 0;
	printf("1  +\n2  -\n3  *\n4  /\n");
	printf("want to do?\n");
	scanf("%d",&choose);
	switch(choose)
	{
	case 1:
		p=add;
		break;
	case 2:
		p=sub;
		break;
	case 3:
		p=mul;
		break;
	case 4:
		p=div;
		break;
	default:
		p=add;
	}
	double ret = p(a,b);//add(a,b)
	printf("p(a,b) ret: %.2lf\n",ret);
	return 0;
}

应用:降低代码耦合度,被称为回调函数-->会被 被动调用的函数

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

int asc(int a,int b)
{
//return a>b;
//return a>b?1:0;
	if(a>b)
	{
		return 1;
	}
	return 0;//无需交换
}
int desc(int a,int b)
{
	if(a<b)
	{
		return 1;
	}
	return 0;//无需交换
}
int asc_abs(int a,int b)
{
	return abs(a)>abs(b);
}
int bub(int *a,int len,int (*fun)(int,int))
{
	int i=0,j=0;
	for(j=len-1;j>0;j--)
	{
		for(i=0;i<j;i++)
		{
			if(fun(a[i],a[i+1]))
			{
				int t=a[i];
				a[i]=a[i+1];
				a[i+1]=t;
			}
		}
	}
	for(i=0;i<10;i++)
	{
		printf("%d  ",a[i]);
	}
	return 0;
}
int main()
{
	int a[10]={0};
	srand(time(NULL));
	int i=0;
	for(i=0;i<10;++i)
	{
		a[i]=rand()%10;
	}
	for(i=0;i<10;i++)
	{
		printf("%d  ",a[i]);
	}
	bub(a,10,asc_abs);//desc/abs
	printf("ret:\n");
	printf("\n");
	return 0;
}

作为函数的设计者,希望显示数据的时候,可以更加多种规则显示,所以需要主调者规则调入函数因此需要使用函数指针进行解耦合

其中的fun()函数就是回调函数,这个函数就是被动调用

十二、二级指针

定义:指向指针变量的指针就是二级指针

应用:

  • 函数调用的地址传递中,需要通过改变指针变量本身(使用二级指针,能改变指针的指向)
  • 区分一级指针:如果需要改变指针指向的内容,使用一级指针
  • 函数传参过程中, char **,char*[]-->指针数组,是兼容类型

十三、const指针

Const  常量

int a=10;

const int b=10;//只读变量

b=20;  //错误,因为只读变量不能赋值

const int c;//写法是错误的、因为是只读变量,所以需要在定义的时候就初始化

c=20;//否则后面都是赋值会报错

#include<stdio.h>
int main()
{
	const int *p;  //表示指针指向的内容不能被修改,常量指针
	int const *p1;  //const在前在后无所谓,这两个一样
	int *const p;  //表示指针的指向(指针本身)不能变化,(整形的)指针常量-->类似数组名
	const int*const p;  //指针本身不能变,指针指向的内容也不能变-->指向常量的常量指针

	char str[100]="hello";
	char str2[100]="world";

	//最常用
	const char *p=str;
//	p[0]='a';//错误的,不能通过P去修改str的内容
	str[0]='a'; //对的,只说了P是只读的,没说str是只读的
    p=str2;  //对的,表达的内容不能变,没有说指针本身不能变
	
	char *const p2=str;  //定义的时候就要初始化
	p2[0]='a'; // 对的,指针本身不能变,指向的内容可以修改
//	p2=str2;  //错误的,本身不能变化

	const char*const p3=str;  //指向常量的常量指针,指针本身不能变,指向的内容也不能变
//	p3[0]='a';  //错误
//	p3=str2;  //错误
}

十四、void *万能指针

void a;//  错误的,编译器不知道给a要开辟多大的空间

void   函数的返回值

void *  函数的返回值,函数的参数

void *  作为函数的参数的时候,可以接受任意类型的指针

  • void*保存内存的地址
  • 其他任意类型的指针给void*赋值或参数传递,不需要额外操作,直接赋值或参数传递就可以了
  • 当需要把void*转换为其他类型的指针时,需要强制类型转换后才可以使用
  • void*中只保存了地址,不知如何对数据进行访问,如果没有转换,*p,p+1都会失败,没有void类型的变量
  • void*用于函数的返回值、函数的参数(mycpy.c最能体现这一点)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

void show_char(void *p)
{
	printf("%c",*(char *)p);
}
void show_int(void *p)
{
	printf("%d  ",*(int *)p);
}
void show_double(void *p)
{
	printf("%lf  ",*(double *)p);
}

void show(void *a,int len,int size,void (*show_change)(void*))
{
	int i=0;
	for(i=0;i<len;i++)
	{
		show_change(((char*)a+i*size));
	}
	printf("\n");
}
int main()
{
	char str[5]="hello";
	int a[5]={1,2,3,4,5};
	double b[5]={1.1,2.2,3.3,4.4,5.5};
	show(str,strlen(str),sizeof(str[0]),show_char);
	show(a,5,sizeof(a[0]),show_int);
	show(b,5,sizeof(b[0]),show_double);
	return 0;
}

mycpy.c


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void* mymemcpy(void* dst,void* src,int size)
{
    char * pdst = (char*)dst;
    char* psrc= (char*)src;
    
    int i = 0 ;
    for(i=0;i<size;i++)
    {
        *pdst=*psrc;
        pdst++;
        psrc++;
    }
    return dst;

}
int main()
{
    double d1[5]={1.11,2.22,3.33,4.44,5.55};
    double d2[5]={0};

    mymemcpy(d2,d1,sizeof(d1)); // 8*5  =40 

    int i = 0 ;
    for(i=0;i<5;i++)
    {
        printf("%lf\n",d2[i]);
    }


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值