嵌入式学习之路 10(C语言基础学习——函数)

        函数的思想:从上到下,逐步求解问题的过程。将一个大的问题拆开成一个个小问题,每一个小问题都有与之对应的解决方案,这个解决方案就是“函数”。

函数的定义:(表示把功能实现出来)

1.main函数之前:

2.main函数之后:需要在调用函数之前声明该函数,函数头+分号 就是函数声明

表示形式:

类型标识符 函数名(形式参数)
{
    函数体代码;
 }

类型标识符:表示函数要带出的结果的类型,既返回值的数据类型。

注意:

1、数组类型也是数据类型,但这里不能用数组类型来表示返回值的类型。

2、如果函数不需要带出什么结果,此时返回结果的类型说明符一般设计为void。如果类型为void,一般不写return。

3、如果返回结果的类型与类型说明符不一致,以类型说明符为准,最终结果的类型都会转为类型说明符表示的类型。

4、类型说明符如果不写,默认是int型。

函数名:函数的入口地址,命名规则符合标识符的命名规则。(由字母、数字、下划线组成组成,不能以数字开头)

形式参数:表示该函数要用到的数据,表明将来使用时需要用到的实际参数该怎么写。

注意:

1、每一个形参变量都必须明确指定类型,不能写成(int a,b)。

2、实参和形参对应的关系:类型匹配,个数相同,顺序一一对应。

3、函数传参,传递的是实际参数的数值(值传递)。

4、如果不需要接收实际参数,形参一般设计为void(表示空类型)。

函数体代码:这是用来实现函数具体功能的代码。

eg:写一个函数,实现两数求和。

1.先确定函数名

2.考虑函数需要用到哪些数据 ---- 形参

  形参的写法:
  (数据类型 形参变量名1,数据类型 形参变量名2 ...)

3.处理数据---- 函数体的具体实现 

4.考虑需不要带出结果 --- (返回值对应)类型说明符

#include <stdio.h>

//函数的定义
int add(int num1,int num2)
{
	int sum;
	sum = num1 + num2;

	return sum;
}

int main()
{
	int ret;
	
	//函数的调用
	ret = add(1,2);
	printf("ret = %d\n",ret);

	return 0;
}

函数的调用

1、函数语句

把函数调用作为一个语句。如"printstar(); "这时不要求函数带回值, 只要求函数完成一定的操作。

2、函数表达式

        函数出现在一个表达式中,这种表达式称为函数表达式。这时要求函数带回一个确定的值以参加表达式的运算。例如: c=2*max(a,b);函数 max 是表达式的一部分,它的值乘2再赋给c。

3、函数参数

函数调用作为一个函数的实参。

例如: m=max(a,max(b,c));

其中 max(b, c) 是一次函数调用,它的值作为 max 另一次调用的实参。 m的值是a,b,c三者中的最大者。

又如: printf ("%d\n", max (a,b));

也是把 max(a, b) 作为 printf 函数的一个参数。

函数调用作为函数的参数,实质上也是函数表达式形式调用的一种,因为函数的参数本来就要求是表达式形式。

在函数里又调用另一个函数,叫做函数的嵌套调用。

注意:函数不支持嵌套定义(在定义的函数里又定义新的函数),但是可以嵌套调用。

函数调用的关系:

调用者与被调用者 

int main(void) 
{
   printf("%d\n",getMonthDays()); 
   return 0;
}

这个个示例的代码里面:
main 为调用者  ---main函数是整个程序的入口,只能作为调用者 
getMonthDays --- 在此处是被调用者

函数调用的本质

实现函数调用的本质,实际上是利用了栈的结构,先入后出,保证了函数可以层层调用。

栈:实际上是一种数据结构,数据结构表示数据的一种组织形式。栈的特点是:先进后出(first in last out)FILO。

从c语言角度的栈,本质上是一块内存空间,只是按照栈这种数据结构来处理和使用的。

栈还可以放局部变量,变量的空间自动申请,自动释放。

c语言程序把内存划分了五个区域,栈只是其中的一个区域,栈(主要用来存放自动变量或函数调用的数据),堆(空间大,堆上的空间使用需要手动申请,手动释放),字符串常量区(只读),静态区,也叫全局区(用来存放全局变量和静态变量),代码区(只读)。

在 Linux 系统中,默认情况下栈的大小通常为 8MB,这是一个常见的默认设置。 然而,这个默认值是可以修改的。修改栈大小的方式可能因不同的情况和需求而有所不同。 一种常见的方法是通过编译器的选项来设置。例如,在使用 GCC 编译器时,可以使用 `-Wl,--stack=<size>` 选项来指定栈的大小,其中 `<size>` 是以字节为单位的栈大小值。 另外,在一些特定的环境或应用场景中,可能还可以通过系统配置文件或相关的内核参数来进行修改。 需要注意的是,修改栈大小应该谨慎进行。如果将栈大小设置得过小,可能会导致程序在运行时出现栈溢出的错误。相反,如果设置得过大,可能会浪费系统资源。 例如,如果一个程序需要处理大量的递归操作,可能需要适当增加栈的大小以避免栈溢出。但如果是一个简单的小型程序,过大的栈大小可能是不必要的。

特殊嵌套调用——递归

        递归就是函数自己调用自己,递归有两种形式,一是直接递归,二是间接递归。递归类似于循环——递归是一种特殊的循环。

下面是递归的几个简单的示例:

#include <stdio.h>

int pbnq(int n)    //求斐波那契数列的第n项
{
	if(n==1 || n==2)
	{
		return 1;
	}
	else
	{
		return pbnq(n-1)+pbnq(n-2);
	}
}

int sum(int n)   //求1-n的累加求和
{
	if (n==1)
	{
		return 1;
	}
	else
	{
		return sum(n-1)+n;
	}
}

int jieCheng(int n)    //求n的阶乘
{
	if (n==1)
	{
		return 1;
	}
	else
	{
		return jieCheng(n-1)*n;
	}
}

int main()
{
	int n;
	scanf("%d",&n);
	//printf("%d\n",sum(100));
	//printf("%d\n",jieCheng(n));
	printf("%d\n",pbnq(n));
	
	return 0;
}

经典的汉诺塔问题:

汉诺塔(Tower of Hanoi)是一个经典的数学问题和递归算法的示例。

 

问题描述:
有三根柱子 A、B、C ,在 A 柱上有 n 个圆盘,圆盘大小不等,大的在下,小的在上。要把这 n 个圆盘从 A 柱移动到 C 柱,在移动过程中始终保持大盘在下,小盘在上。每次只能移动一个圆盘,并且只能在三根柱子之间移动。

 

解决思路:
通过递归的方式来解决。
当只有一个圆盘时,直接将其从 A 柱移动到 C 柱。
当有多个圆盘时,把上面 n - 1 个圆盘看成一个整体,先将这 n - 1 个圆盘从 A 柱借助 C 柱移动到 B 柱,然后把最大的圆盘从 A 柱移动到 C 柱,最后再把 B 柱上的 n - 1 个圆盘借助 A 柱移动到 C 柱。

#include <stdio.h>

void move(int befor, int after)
{
	printf("%c ---> %c \n",befor,after);
}

int hannuo(int n, int begin, int mid, int end)
{
	if(n == 1)
	{
		move(begin,end);
	}
	else
	{
		hannuo(n-1,begin,end,mid);
		move(begin,end);
		hannuo(n-1,mid,begin,end);
	}
}

int main()
{
	int n;
	scanf("%d",&n);
	hannuo(n,'A','B','C');

	return 0;
}

数组作为函数参数

        普通变量可以作为函数参数,数组也可以作为函数参数。 

        数组作为函数参数, 传递的是数组首元素的地址。---数组名可以做形参,也可以做实参。

1、数组元素作为函数参数

        由于实参可以是表达式,而数组元素可以是表达式的组成部分,因此数组元素当然可作为函数的实参,与用变量作实参一样,是单向传递,即“值传送”方式。

2、数组本身作为函数参数

总结:一维整形数组做函数的参数

做形参:写成数组形式,还需要传数组长度

做实参:传数组名,数组长度

     eg:
       printArrray(int a[],int len) //函数头,数组作为形参 
	   //printArrray (int *a,int len) ---编译器最终理解的形式 
       
       printArray(a,len);  //调用函数

练习: 

#include <stdio.h>

void printfArray(int a[],int len)
{
	int i;
	for ( i=0; i<len; i++ )
	{
		printf("a[%d] = %d\n",i,a[i]);
	}
}

void nixu(int a[], int len)
{
	int i=0;
	int j=len-1;
	int temp;

	while(i<j)
	{
		temp = a[i];
		a[i] = a[j];
		a[j] = temp;
		i++;
		j--;
	}
	return ;
}

void crpaixu(int a[], int len)
{
	int i=0, j=0;
	int temp;

	for( i=1; i<len; i++ )
	{
		temp = a[i];
		j = i;
		while(j>0 && temp<a[i-1])
		{
			a[i] = a[i-1];
			j--;
		}
		a[j] = temp;
	}
	return ;
}

int chazhao(int a[], int len, int n)
{
	int begin, mid, end;
	begin = 0;
	end = len - 1;

	while ( begin <= end )
	{
		mid = (begin+end)/2;

		if( n < a[mid] )
		{
			end = mid - 1;
		}
		else if ( a[mid] < n )
		{
			begin = mid + 1;
		}
		else
		{
			break;
		}
	}

	if (begin <= end)
	{
		return mid;
	}
	else
	{
		return -1;
	}

}

int main()
{
	int a[] = {1,2,3,4,5,6,7,8,9};
	int len = sizeof(a)/sizeof(a[0]);

	/*printfArray(a,len);
	printf("-------------------\n");

	nixu(a,len);
	printfArray(a,len);
	printf("-------------------\n");

	crpaixu(a,len);
	printfArray(a,len);
	printf("-------------------\n");
*/
	int n;
	printf("input n : ");
	scanf("%d",&n);
	chazhao(a,len,n);

	if(chazhao(a,len,n)>=0)
		printf("found!\n");
	else
		printf("no found!\n");

	return 0;
}

  • 22
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
sscanf函数C语言中一个非常常用的函数,它可以将一个字符串按照指定的格式转换成相应的数据类型。在嵌入式开发中,sscanf函数也是非常常见的,因为很多时候需要从串口或者其他外部设备中读取数据,并将其转换成相应的数据类型进行处理。下面是一些sscanf函数的使用技巧: 1. 使用sscanf函数时一定要注意格式字符串的正确性。格式字符串中的占位符必须与待转换的数据类型相对应,否则会发生未知错误。 2. 如果待转换的字符串中包含多个数据,可以使用多个占位符进行转换。例如,如果待转换的字符串为"1,2,3",可以使用" %d,%d,%d"的格式字符串进行转换。 3. 可以使用sscanf函数的返回值来判断转换是否成功。如果返回值等于待转换字符串的长度,则说明转换成功,否则转换失败。 4. 如果待转换的字符串中包含浮点数,可以使用"%f"或者"%lf"的格式字符串进行转换。 5. 如果待转换的字符串中包含十六进制数,可以使用"%x"的格式字符串进行转换。 6. 如果待转换的字符串中包含字符或字符串,可以使用"%c"或者"%s"的格式字符串进行转换。 7. 如果待转换的字符串中包含指针类型的数据,可以使用"%p"的格式字符串进行转换。 总之,在使用sscanf函数时一定要注意格式字符串的正确性,否则很容易出现转换错误的情况。同时,还应该注意sscanf函数返回值的判断,以确保转换的正确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值