学习C语言的小收获2(关于函数)

1、函数传参(传值和传址)

形参实例化后(形参在接收实参的赋值后)相当于实参的一份临时拷贝。因为函数的形参和实参分别占有不同内存块,所以在传值调用时,我们无法通过改变形参的值来影响实参,比如常见的交换问题,如果我们写一个函数Swap1函数对所接受的实参的值进行大小比较并进行数值交换后,我们改变的只是函数创建出来的x,y但却不是最后要呈现的a,b。他们的联系只是建立了一次传值而已,就是x,y被a,b的值初始化了一下。

#include

void Swap1(int x,int y)//创建相同数据类型的形参接收实参传值
{
	int temp;
	temp = x;
	x = x > y ? x : y;
	y = temp > y ? y : temp;
}

void Swap(int* x, int* y)//创建指针类型的形参接收
{
	int temp;
	temp = *x;
	*x = *x > *y ? *x : *y;
	*y= temp> *y ? *y: temp;

}                           //Swap1为传值调用,Swap为传址调用
int main()                  //想要表达的作用相同,但输出结果不同。
{
	int a, b;
	scanf("%d %d", &a, &b);
	//比较a,b大小,若a

 不同于Swap函数,如图中是传址调用,则可以通过解引操作符*对实参a,b的值进行作用或者说改变,就像:学习C语言的小收获2(关于函数)_第1张图片

 图中把a,b的地址传给指针c,d相当于第一幅图中将实参a,b的地址传给形参x,y,则通过解引操作*c=20等将a,b地址里的值更改,赋予新值,最后改变了a,b的结果。

2、不含形参的函数

不含形参的函数其实就是不用接收来自主函数的值,独立实现自己的功能,例如可以是在函数实现数值输入等。如:在value函数中,不需要接收实参,所以()里没有设置形参去接收。

#include
int value()//不设置形参
{
	int temp;
	do {
		puts("请输入一个正整数:");
		scanf("%d", &temp);
		 if (temp <=0)
			puts("请重新输入:");
	} while (temp <= 0);
	return temp;
}
void reverse(int a)
{
	int c=0;
	while (a != 0)
	{
		c = a % 10;
		a= a/10;
		printf("%d", c);
	}
}
int main()
{
	int a = value();//括号里为空,不赋予实参
	printf("初值:%d\n", a);
	printf("翻转后:");
	reverse(a);//调用函数后无需接收,函数没有返回值,所以为void
	return 0;
}

3、函数返回值

在写函数时可以很好的利用返回值来判断条件,觉得是个不错的构造思路,既使函数有良好的移植性(如果想要实现别的内容,大可以在这基础上修改后运用),然后逻辑清晰,条理简明。如下通过判断返回值来确定三角形的类型。

#include
#include
int org(int x, int y, int z)
{
	if (abs(x-y)z)
	{
		if (x == y&&y == z)
			return 0;
		else
		{
			if (x == y || x == z || y == z)
				return 1;
			else
				return 2;
		}
	}
	else
		return -1;
}
int main()
{
	int a, b, c,i;
	for (i = 0; i < 2; i++)
	{
		scanf("%d %d %d", &a, &b, &c);
		if (org(a,b,c) == 0)
			printf("Equilateral triangle!\n");
		else if (org(a,b,c) == 1)
			printf("Isosceles triangle!\n");
		else if (org(a,b,c) == 2)
			printf("Ordinary triangle!\n");
		else if (org(a,b,c) == -1)
			printf("Not a triangle!\n");
	}
		
	return 0;
}

关于返回值要注意的是,当我们构建函数时,若设计的是int型则返回整数,若是void型则不需要返回值。 如图可见没有返回值的函数:

void end(int a)//函数类型为void,没有返回值
{ 
	int i = 0;
	int r=1;
	while (r <= a)
	{
		for(i=0;i 10);
		end(a);//因为没有返回值,也不用创建变量去接收
		return 0;
}

 函数运行结果如下图,若输入大于10的数字则会取余得到最后一位数。学习C语言的小收获2(关于函数)_第2张图片

4、函数的声明

 声明时,括号里可以只写形参类型,如,int

#include
void print(int);//声明函数,因为函数的定义在后面
                //主函数在定义之前对函数进行调用则需要在前声明一下
int main()
{
	int num = 1997;
	print(num);
	return 0;
}

void print(int num)
{
	if (num > 9)
	{
	    print(num / 10);
	}
	printf("%d ", num%10);
}

 或者创建两个文件,把函数放进一个文件,主函数在另一个文件,想要调用函数则要用extern声明一下:

在test.c中:
#include
extern void print(int);//用extern声明外部定义的函数,才可以调用
int main()
{
	int num = 1997;
	print(num);
	return 0;
}

在test1.c中:
#include
void print(int num)
{
	if (num > 9)
	{
		print(num / 10);
	}
	printf("%d ", num % 10);
}

5、用函数查找数字的方法

以下是二分查找法代码(下面代码适用的大前提:这组数据是已经按照从小到大排好顺序的),一般来说是要有顺序的序列关于这种查找方法。

int find(int shu[], int a,int c)
{
	int left = 0;
	int right = a-1;//数组的下标从0开始计数,所以最右边元素的下标最大为a-1
	while(left<=right)//只有当左边的数在左边查找,右边的数在右边继续查找时
	{                  //才有可能说这个数有被找到的可能,当交叉后,说明数字已被查完
		int mid = (left + right) / 2;//特别容易把mid的表达式写到循环外,
		if (shu[mid] < c)            //注意每次比较完mid都要重新求值,所以要在循环里面
		{
			left = mid + 1;
		}
		else if (shu[mid] > c)
		{
			right = mid - 1;
		}
		else
		{
			return mid;//这里的mid,left,right全都为数组下标
		}
	}
	return -1;
}
int main()
{
	int shu[] = {1,2,3,4,5,6,44,55,77};
	int a = sizeof(shu) / sizeof(shu[0]);
	int c;
	puts("请输入要查找的数:");
	scanf("%d", &c);
	int b = find(shu, a,c);
	if (b == -1)
		printf("找不到!");
	else
		printf("找到了!该数下标为%d", b);
	return 0;

}

6、函数的递归

递归的两个必要条件:1、存在限制条件,当满足这个限制条件的时候,递归便不再继续。2、每次递归调用之后越来越接近这个限制条件

如下代码:不创建变量,求字符串的长度:

#include
int word(char *p)
{
	if (*p != '\0')  
		return 1+word(p+1);//调用word函数
	else
		return 0;
}
int main()
{
	int b;
	char a[] = "what are you doing?";
	b = word(a);
	printf("%d", b);
	return 0;
}

在函数里再利用该函数,形成调用自身函数的效果,我们可以发现当第一个字符或者说数组元素是w不是结束符'\0 '则return1+word(p+1),想要得到准确的返回值则再调用word函数求出下一个数组元素对应的word函数的返回值,所以会一直调用求解直到下一个元素为结束符'\0',则调用结束,计算出最后结果:1+1+1+······+word函数返回值0(最后满足限制条件'\0',所以返回值为0)

int main()
{
	int n = 0;
	scanf("%d", &n);

	int i = 0;
	int ret = 1;
	//迭代
	for (i = 1; i <= n; i++)
	{
		ret = ret * i;
	}
	printf("%d\n", ret);

	return 0;
}
递归方法:如下
#include
int ret(int n)
{ 
	if (n>0)
		return n * ret(n-1);
	else
		return 1;
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int a=ret(n);
	printf("%d\n", a);
	return 0;

}

有些问题不用递归也可以用迭代解决。

 

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