C Primer Plus(第六版)第九章重点解析。

标题:函数

函数是完成特定任务的独立程序代码单元。若你编写好一个函数,例如输出几个数之中的最大值或从小到大排序一堆数。可以保存好,有需要时拿出来使用。
即使只是使用函数一次,也值得编写函数,函数可以让代码简洁易懂。
ps:把可移植的部分留在函数之中,不可移植的部分留在住函数之中。
单独设计和测试每个函数。

函数声
void starbar(void);
1.第一个void可以换成int float double等数据类型。表示该函数的返回值。
2.第二个void可以用一些形式参数代替,例如int x,double y等。
3.形式参数只在调用函数时分配内存,函数调用结束后内存空间自然释放。
4.函数声明告诉编译器在别处查找函数的定义。注意指明函数的返回类型和参数类型。
5.函数声明是一个语句。末尾要加 ; ,函数定义后不用加分号。
6.函数声明告知编译器函数的类型,而函数定义则提供实际的代码。
ps(我们平时所用的printf和scanf函数其实已经有了声明,因此我们不必声明就可以使用,stdio.h头文件包含了标准I/O库函数的声明,math.h头文件包含了各种数学函数的声明)。
7.若把函数定义放在调用函数的语句之前,就不用对函数进行声明。

定义带形式参数的函数
1.和定义在主函数中的变量一样,形式参数也是局部变量,属该函数私有。在其他函数中使用同名变量不会引起冲突,但最好不要这样做,降低代码可读性。但是也可以

#define N 6

或者

int A;
int main(void)

`
A、N由主函数和被调函数共同使用。尤其是当利用函数直接修改实参时,要修改两个以上的值,可是函数只能return一个值,这个时候可以使用全局变量。
例如:

#include <stdio.h>
int MAX;
int MIN;
int main(void)
{
void choose(int str1[],int n);//函数声明
int str1[8]={1,2,3,4,5,6,7,8};//此处形参与实参同名,但本质上是不同的
choose(str1,8);
printf("MAX=%d,MIN=%d",MAX,MIN);//MAS和MIN在函数中被赋值,在主函数和被调函数中是同一个值
return 0;
}
void choose(int str1[],int n)
{ 
MIN=str1[0];
MAX=str1[0];
int i;
for(i=1;i<n;i++)
{
if(str1[i]>MAX)
MAX=str1[i];
if(str1[i]<MIN)
MIN=str1[i];
}
}

2.主调函数把它的参数储存在称为栈的临时存储区,被调函数从栈中读取这些参数。
若函数定义应读取2个参数,可只传递了一个实参,那么函数会从栈中读取一个未知值。`

#include <stdio.h>
int main(void)
{
 int function(int, int);
 int a, b;
 printf("输入两个整数:");
 scanf_s("%d,%d", &a, &b);
 function(a);
 printf("%d", function(a));//此处会打印一个未知值
 return 0;
}
int function(int x, int y)
{
 printf("你输入的两个整数分别是: %d,%d.", x, y);//此处的y也应该为未知值
 return y;
}

(如果按照书中的说法,函数会从栈中读取一个未知值,打印的y应该为未知数。但我使用的是Microsoft Visual Stdio2019,比较高级了,它识别你只传递了一个实参,报错,程序根本无法运行。

3.另外,函数根据定义中的形参类型读取实参的数据。假如函数读取两个int类型的值,即要读取栈中的64位,假如你传递了两个double类型的值,即128位,那么函数只会读取前64位。
但是:

#include <stdio.h>
int main(void)
{
 int function(int);
 function(12.4444);
 printf("%d", function(5659.555584));
 return 0;
}
int function(int x)
{
 printf("你输入的整数是: %d.", x);
 return x;
}

该函数的输出为12和5659,即发生了对小数的截断,并没有如书中所说读取只64位产生一个神奇值。

函数的返回值
1.函数实际的返回值相当于把函数中指定的返回值赋给与函数类型相同的变量所得到的值。
例如

int function(void)
{
return 4.5;
}

函数返回的值为4,而不是4.5.
2.函数中遇到return即终止函数的进行,退出函数,不再理会函数的剩下部分。
例如

void function(void)
{
printf("第一句话");
return;
printf("第二句话");//这句printf语句永远也不会执行。

}

关于递归
1.每级递归的变量都归本级递归所有,因此每进行一层递归,都会创建属于本机递归的变量。在对效率要求比较高的程序之中,递归函数可能不太行。
2.递归函数必须包含能让递归调用停止的语句。通常,递归函数都使用if或其他等价的测试条件在函数形参等于某特定值时终止递归。
下面是斐波拉契函数的递归调用:

int Fibonacci(int n)
{
if(n>1)
 return Fibonacci(n-1)+Fibonacci(n-2);
 else if(n==1)
 return 1;
 else(n==0)
 return 0;
}

在附上用循环做的斐波那契函数:

#include <stdio.h>
int main(void)
{
 void Fibonacci(int);
 int length;
 printf("请输入一个整数表示你想了解的斐波那契数列长度:");
 scanf_s("%d", &length);
 Fibonacci(length); 
 return 0;
}
void Fibonacci(int n)
{
 int x, y, i,temp;
 x = 1; y = 1; i = 2;
 if (n == 1)
  printf("1");
 else
  printf("1 ");
 while (i <= n)
 {
  printf("%d ", y);
  if (i % 8 == 0)
   printf("\n");
  temp = y;//把y的值先存起来
  y = x + y;
  x = temp;
  i++;
 }
}

3.递归在处理倒序时非常方便。

编译多源代码文件的程序
在Microsoft Visual Stdio2019上平时敲代码都是要建立一个项目先,然后可以创建一些源文件和头文件,它们自然就连接在一起。
但若是使用VisuaC++这种比较落后的东西就需要进行连接的相关复杂操作。可以参考C程序设计学习辅导谭浩强版。

中间遇到的一个问题
对于

scanf_s("%*s");

一开始愣是搞不明白,它为什么可以过滤掉你输入的垃圾数据跳到下一个空白处。后来在本书P96页找到答案。
scanf()中的*用法:把 *放在%和转换字符之间,会使得scanf跳过相应的输出项。本例中跳过一个字符串,因为字符串以空白结尾,所以说跳到下一个空白处。

指针
指针书中说的很基础也很详细,就不多说。有几点:
1.对于int *a;
a是指针变量名,a的类型是int *,虽然说 *和a靠得比较近,但 *是与int 结合的。(在声明变量时)
2.指针是新类型,转换说明是%p,
3.普通变量把值作为基本量,把地址作为通过&运算符获得的派生量,而指针变量把地址作为基本量,把值作为通过 *间接得到的派生量。

end

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值