形参实例化后(形参在接收实参的赋值后)相当于实参的一份临时拷贝。因为函数的形参和实参分别占有不同内存块,所以在传值调用时,我们无法通过改变形参的值来影响实参,比如常见的交换问题,如果我们写一个函数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的值进行作用或者说改变,就像:
图中把a,b的地址传给指针c,d相当于第一幅图中将实参a,b的地址传给形参x,y,则通过解引操作*c=20等将a,b地址里的值更改,赋予新值,最后改变了a,b的结果。
不含形参的函数其实就是不用接收来自主函数的值,独立实现自己的功能,例如可以是在函数实现数值输入等。如:在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;
}
在写函数时可以很好的利用返回值来判断条件,觉得是个不错的构造思路,既使函数有良好的移植性(如果想要实现别的内容,大可以在这基础上修改后运用),然后逻辑清晰,条理简明。如下通过判断返回值来确定三角形的类型。
#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的数字则会取余得到最后一位数。
声明时,括号里可以只写形参类型,如,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);
}
以下是二分查找法代码(下面代码适用的大前提:这组数据是已经按照从小到大排好顺序的),一般来说是要有顺序的序列关于这种查找方法。
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;
}
递归的两个必要条件: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;
}
有些问题不用递归也可以用迭代解决。