嵌入式C语言学习笔记(2)

1.数组指针

数组指针本质上就是一个指针,它里面存放的是数组的首地址。

#include

void show(int (*p)[4],int n)
{
    for(int i=0;i

2.指针数组

指针数组的本质就是数组,不过所有存储元素都是指针。当你想一次性定义出多个相同数据类型的指针时,可以使用指针数组

int* a[3] ;
char* names[4]={"ikun","ctrl","music","susan"};
sizeof(names);//--->4*4=16;

3.命令行传递参数,main函数的标准格式

int main(int argc,const char * argv[])
{

return 0;
}

//argc:参数的个数 包括./a.out
//argv:参数的值列表 argv[0]="./a.out" argv[1] ="第一个参数"

注意:1.命令上传递过来的所有参数都是字符串
    2.只要用到命令行传递的参数必须加容错判断
    if(argc ==1)//./a.out ==1
    {
        printf("err\n");
        return -1;
    }
1.argc和argv 变量名可以改变
2.argv的数据类型是:char *[]

示例:

//判断终端输入的是否是质数
#include

int myatoi(char *p)
{
    int num = 0;
    int i = 0;
    while(p[i])
    {
        num = mun*10 +p[i]-48;
        i++;
    }
    return num;
}

int isPrime(int num)
{
    for(int i=2;i

终端命令:

./a.out 123


#123是传递给a.out文件的参数

4.递归

简单来说就是:一个函数直接或者间接调用自己。递归函数运用比较少,因为它要在栈内开辟空间,如果递归没有写好出口,就会造成栈溢出。

//递归实现计算阶乘
#include
int fun(int n)
{
    if(n==1)//递归结束条件
    {
        return 1;//递归出口,如果递归函数不写出口会导致无限递归,最后消耗完栈空间后,栈溢出报错。
    }
    return n*fun(n-1);
}

int main ()
{
    int n=0;
    scanf("%d",&n)
    int res =fun(n);
    printf("%d! is%d\n",n,res);
    return 0;
}

5.二级指针

本质还是个指针,就是指向指针的指针。存放的是一级指针的地址

int *p;		//一级指针---》保存普通变量的首地址
int **p;	//二级指针---》保存一级指针的首地址
int ***p;	//三级指针---》保存二级指针的首地址
int ****p;	//四级指针---》保存三级指针的首地址

二级指针的定义:

int a=10086;
int *p=&a;
int **q=&p;
通过二级指针修改变量:
    **q=10;
//对一级指针取地址,就变成了二级指针
#include
int main()
{
    int a=10;
    int *p=&a;	//一级指针
    int **q=&p;	//二级指针
    //打印a的值
    printf("%d %d %d",a,*p,**q);
    //打印a的地址
    printf("%p %p %p",&a,p,*q);
    //打印p的地址
    printf("%p %p",&p,q);
	return 0;
}
	q 	//int **
    *q	//int *
    **q	//int 
    &q	//int ***
        *降级
        &升级
#include
#include

void get_mermory(int *q)
{
	q=malloc(10*sizeof(int ));//申请40字节空间,首地址赋值给q
}

int main(int argc, const char *argv[])

{
	int i=0;
	int *p=NULL;
	get_mermory(p);//值传递
	for(i=0;i<10;i++)
	{
		p[i]=i;//赋值
	}
		
	for(i=0;i<10;i++)
	{
		printf("%d\n",p[i]);//打印
	}
	free(p);//释放手动申请的空间
	return 0;
}
//运行结果:段错误。函数结束后函数内的临时变量被清空。无法改变p指针是空指针的事实,对空指针指向的地址赋值,段错误。
//修改代码:(1)
#include
#include

void get_mermory(int **q)//变成了二级指针
{
	*q=malloc(10*sizeof(int ));//修改指针指向
}

int main(int argc, const char *argv[])

{
	int i=0;
	int *p=NULL;
	get_mermory(&p);//地址传递
	for(i=0;i<10;i++)
	{
		p[i]=i;
	}
		
	for(i=0;i<10;i++)
	{
		printf("%d\n",p[i]);
	}
	free(p);
	return 0;
}
//修改代码:(2)通过函数返回值实现修改p的指向
#include
#include

int * get_mermory()
{
	int*p= malloc(10*sizeof(int ));
    if(p==NULL)//非空校验
    {
        printf("空间开辟失败\n");
        return -1;
    }
    return p;
}

int main(int argc, const char *argv[])

{
	int i=0;
	int *p=NULL;
	p=get_mermory();
	for(i=0;i<10;i++)
	{
		p[i]=i;
	}
		
	for(i=0;i<10;i++)
	{
		printf("%d\n",p[i]);
	}
	free(p);
	return 0;
}

5.1二级指针的用途

1.修改一级指针保存的内容
#include

void change_ptr(int **p,int *q)
{
    *p=q;	//*p ---p1
}

int main()
{
    int a=10,b=20;
    int *p1=&a;
    printf("修改前p的指向是:%d\n",*p1);	//10
    change_ptr(&p1,&b);
    printf("修改后p的指向是:%d\n",*p1);	//20
    return 0;
}
//二级指针常用来修改一级指针保存的内容
2.传递指针数组
#include
//void show(char *p[5],int n) 	---转成二级指针
void show(char **p,int n)
{
    for(int i=0;i

6.指针函数

本质还是函数,只不过他的返回值是指针类型。

作用:调用完函数能获得一个地址

6.1常用的指针函数

void* malloc(int size);		//void* 返回值是无类型的指针
char* strcpy(char *dest,const char *src)
char* strcat(char *dest,const char *src)

7.函数指针

本质是指针,是指向函数的指针。存放的是一个函数的地址//定义一个指针
数据类型* 指针名 =地址---》函数名
    函数的数据类型是什么???

7.1函数的类型

指针特点---》*
数组特点---》[]
函数特点---》()保留()才知道这是函数

void fun(void);		//无参无返回值<--->void fun();
//类型 (void)	除掉不重要的函数名和形参变量名(形参名可以不去)就是函数的类型
int getmax(int a,int b)
//类型 int(int ,int)
char *strcpy(char *a,char* b)
//类型 char*(char*,char*)

7.2定义一个函数指针

void fun();
void (void)*p=fun;	//由于()的优先级高,这样等号左边会被视为一个函数的声明---》
//加()---》
void (void)(*p)=fun;
//但依旧是从左往右识别,这样写还是不合适---》
//(*p)前移----》
void (*p)(void)=fun;

再来两个例子:
char *strcpy(char *a,char* b);
char *isWithin(char *s,char ch);

char*(*p)(char *,char *)=strcpy;
//给指针名删了---》指针类型:char*(*)(char *,char *)	
//给(*p)一起删了---》指针指向的类型:char* (char *,char *)	

char*(*q)(char *,char)=isWithin;

//直接复制函数声明,把函数名的位置换成(*p),然后把形参名删了,加上等号以及等号右边的函数名
//切记,*p的括号不能省掉,不屑括号就变成了,指针函数了。--》void *p(void);

7.3用函数指针调用函数

函数指针的作用:
    1.能用函数名一样使用
    调用函数时可以通过函数名或者通过函数指针来调用
    2.能将一个函数当作另一个函数的参数进行传递

#include


int getSum(int a,int b)
{
	return a+b;
}

int getSub(int a,int b)
{
	return a-b;
}

int getMul(int a,int b)
{
	return a*b;
}
int getDev(int a,int b)
{

	return a/b;
}


int main()
{
	//定义指针指向getSum()
	int (*p)(int ,int )=getSum;
	int res=0; 			//用于保存计算结果
	res =getSum(10,5);	//通过函数名调用函数
	printf("res is %d\n",res);

	res =p(10,5);		//通过函数指针调用,函数指针能函数名一样使用
	printf("res is %d\n",res);

	p=getSub;	//修改p指针的指向,指向了getSub函数
	res =p(10,5);		
	printf("res is %d\n",res);

	p=getMul;	//修改p指针的指向,指向了getMul函数
	res =p(10,5);		
	printf("res is %d\n",res);
	
	p=getDev;	//修改p指针的指向,指向了getDev函数
	res =p(10,5);	
	printf("res is %d\n",res);

	res=callFun(getSum,10,5);	//传函数名实现函数调用函数	
	printf("res is %d\n",res);


	return 0;
}


//通过修改指针指向来实现调用不同函数,这样写很麻烦。可以通过函数指针优化程序,使得程序更加简单。
#include

int getSum(int a,int b)
{
	return a+b;
}

int getSub(int a,int b)
{
	return a-b;
}

int getMul(int a,int b)
{
	return a*b;
}
int getDev(int a,int b)
{
	return a/b;
}

int callFun(int (*p)(int ,int ),int a,int b)
{
	return p(a,b);
}

int main()
{
	int res=0; 			//用于保存计算结果
	res=callFun(getSum,10,5);	//传函数名实现函数调用函数,不用在主函数中来回修改指针指向。
	printf("res is %d\n",res);
     
    res=callFun(getSub,10,5);
    printf("res is %d\n",res);
    
    res=callFun(getMul,10,5);
    printf("res is %d\n",res);
    
    res=callFun(getDev,10,5);
    printf("res is %d\n",res);
    
	return 0;
}


    //实现并不知道调用的是什么函数,再调用的时候传递函数名实现具体调用。提高了函数的功能性,可拓展性。
   	//回调函数:只要参数列表中有一个参数类型是函数指针的函数就是回调函数。在函数的内部一定会用指针调用指向的函数,所以称为回调函数。callFUn就是一个回调函数。
}

8.函数指针数组

本质是数组,但是数组中的每一个元素都是一个函数指针。

作用:能一次性定义多个相同数据类型对的函数指针。

上面定义了四个函数:getSum,getSub,getMul,geyDev
    如果要分别定义一个指针指向他们就得写重复的代码
int(*p)(int ,int )=getSum;
int(*q)(int ,int )=getSub;
int(*r)(int ,int )=getMul;
int(*s)(int ,int )=getDev;
//定义函数指针数组存放他们
数据类型 数据名[];
--->
    int(*)(int,int)a[]
()优先级最高,[]优先级高于*
--->
int (*a[4])(int ,int)={getSum,getSub,getMul,getDev};
    元数个数:[]里的写几个就是几个
    元素类型:除掉数组名和[]---》int(*)(int ,int)
    函数指针指向的类型:在元素类型基础上给(*)删了---》int(int ,int)
        
其中:	
    a[0]=getSum;
	a[1]=getSub;
    a[2]=getMul;
    a[3]=getDev;

9.const关键字

const :常量化
    被修饰的变量不能被修改,被常量化了。
    const int a=10;<--->int const a=10;
//无法修改a的值,尝试修改会报错。

9.1常量指针与指针常量

const int * ptr;	//常量指针
int const *ptr;		//指针常量
#include

int main()
{
	int a=10;
	int b=20;
	int const*p=&a;		//const修饰*p,无法修改*p里面保存的内容,但是可以通过指针修改它指向的内容 常量指针
    a=30;
	printf("a is %d\n",a);
	int * const q=&a;	//const修饰p,无法修改p里面保存的内容,无法通过指针修改它指向的内容,但是可以指向别的地方 指针常量
	*p=30;//报错 *p只读
    printf("a is %d\n",a);
    q=&b;//报错	q只读
    printf("a is %d\n",a);
	return 0;
}	
 
    

你可能感兴趣的:(c语言,学习,笔记)