第6周:函数
函数是一块代码,接受零个或者多个参数,做一些事情,并返回零个或者多个参数。
函数定义
void sum(int begin, int end)
// 其中 void 为没有返回值的返回类型,sum为函数名,begin 和 end 为参数
// void sum(int begin, int end) 被称为函数头
{
...
//函数体
}
调用函数采取函数名(参数值)
的形式
函数返回
return停止函数的执行,并送回一个值
- return;
- return 表达式
一个函数可以出现多个return
而函数的返回值可以赋值给变量,可以再次传递给函数,甚至丢弃。
void sum(int a)
//void无返回值,不能用return。
int sum(int a )
//int必须用return返回一个值。
函数的先后关系:先定义函数后使用函数
但可以将函数原型先定义,告诉编译器这个函数的名称,参数,返回类型。
double max(double a double b);
// 函数原型
int main()
{
int a=1, b=2, c=3;
c=max(10,12);
return 0;
}
double max(double a double b)
//真正的函数头
{
...
}
函数的传递
- 字面量
- 变量
- 函数的返回值
- 计算的结果
调用函数时候的给的值与参数的类型不匹配,编译器会进行类型转换,但很有可能是不想要的结果。而C++与JAVA对这方面很严格
值的传递
每个函数有自己的变量空间,而这个函数的参数也位于这个独立空间中与其他函数没有任何关系。
double max(double a double b);
//这里的a和b为参数
int main()
{
int a=1, b=2, c=3;
c=max(a,b);
//这里的a和b为值
return 0;
}
double max(double a double b)
//这里的a和b为参数
{
...
}
本地变量
函数的每次运作,就产生了一个独立的变量空间,在这个空间的变量,是函数的这次运行所独有的,称做本地变量。
定义在函数内部的变量就是本地变量,参数也是本地变量。
对于本地变量,它们的生存期和作用期都在大括号内。
本地变量的规则
- 在块外面定义的变量在块内任然有效。
- 若块外与块内有同名变量,块内的变量将掩盖块外的。
- 不能再块内定义同名的多个变量。
- 本地变量不会被默认初始化。
- 参数在进入函数的时候被默认初始化。
Tips
- 调用函数时候的逗号是标点符号不是运算符f(a,b)
- C语言不允许函数的嵌套
- 没有参数输入时候的函数 void f(void), 但是main函数例外,void main()
第6周练习
#include <stdio.h>
void swap(int a, int b);
int main()
{
int a = 5;
int b = 6;
swap(a,b);
printf("%d-%d\n", a, b);
return 0;
}
void swap(int a, int b)
{
int t = a;
a = b;
b = t;
}
//因为交换这个行为只在函数内部生效,所以输出为 5-6
分解质因数
#include<stdio.h>
int isprime(int a)
{
int flag=0,i;
for(i=2;i<a;i++)
{ if(a%i==0)
{
flag=1;
}
}
return flag;
}
int smallfactor(int a)
{
int i;
for(i=2;i<a;i++)
{
if(a%i==0)
{ return i;
}
}
}
int main()
{
int n,s;
scanf("%d",&n);
if(isprime(n)==0)
printf("%d=%d",n,n);
else
{ printf("%d=",n);
do
{ s=smallfactor(n);
if(isprime(n/s)==0)
{printf("%d",s);}
else
{printf("%d*",s);}
n=n/s;
}while(isprime(n)!=0);
printf("*%d",n);
}
}
第7周:数组
int num[100];
scanf("%d",&num[i]);
- 数组其中所有的元素具有相同的数据类型,一旦创建,不能改变 大小。
- 使用数组中放在括弧中的数字被称为下标,下标从0开始计数。
- 编译器不会检查数组下标是否越界。
长度为0的数组。
数组的集成初始化
int a[]={1,2,3,4,5};
//不给出数组的大小,编译器会自己数数;
int b[10]={2};
//如果给出了数组的大小,但后面的初始值数量不够,则其后面的元素由0代替。
若已有数组a, sizeof(a)/sizeof(a[0])
可以得到数组的单元个数。
数组本身不能赋值给另一个赋值,要用for循环遍历数组将数组的中每个值依次赋值
- 常见错误,出了for循环后,仍直接用i来代替下标
- 数组作为函数参数的时候,不能再[]中给出数组的大小,要另外输入一个值作为数组的大小
二维数组
int a[3][5]
可以将a理解为3行5列的矩阵
二维数组的初始化
int a[][5]={
{0,1,2,3,4},
{1,2,3,4,5},
};
//列数必须给出,行数可以由编译器来数
//每行一个{},逗号来分隔,最后一行的逗号可以存在
//如果省略表示补零
第8周:指针与字符串
scanf("%d", &a)
// & 为获得变量的地址,其操作数a必须是变量。&不能对没有地址的东西取地址,例如 &(a+b),&(a++).
如果能够将取得的变量的地址传递给一个函数,那么能否通过这个地址在函数内访问该变量?
则需要一个参数能保存别的变量的地址。
int i;
int *p=&i;
// 普通变量的值是具有实际值的变量的地址,而指针变量的值是具有实际值的变量的地址。
void f(int *p)
在被调用的时候得到了某个变量的地址int i=0; f(&i)
在函数里面可以通过这个指针访问外面的这个iint k=*p; *p=k+1
*是一个单目运算符 用来访问指针的值所表示的地址上的变量
指针的运算符&*
- *&aa —> *(&aa) —>*(aa的地址) —>得到那个地址的变量—>aa
- &*aa—> &(*aa) —>&(b) —>得到b的地址,也就是aa—>aa
int i; scanf("%d",i)
// 传入一个地址
交换两个变量的值
void swap(int *pa, int *pb)
{
int t=*pa;
*pa=*pb;
*pb=t;
}
常见错误: 定义了指针变量,还没有指向任何变量就开始使用指针
指针与数组
函数参数表中的数组实际上是指针,以下几种函数原型是等价的
int sum(int *ar, int n);
int sum(int *, int);
int sum(int ar[], int n);
int sum(int [], int);
数组变量是特殊的指针
int a[10]; int *p=a;
无需用&取地址, 但是数组的单元表达式变量,需要用&取地址。
指针与const
指针是const
- int * const q=&i
一旦得到了某个变量的地址,不能再指向其他变量。
- *q=26
是可以的。
- q++
是错误的。
所指向的是const
- const int *p=&i
表示不能通过这个指针取修改那个变量。
- *p=26
是错误的,(*p)是const
- i=26
是可以的。
- p=&j
是可以的。
判断哪个被const了的标志是const在*的前面还是后面
const数组
- const int a[]={1,2,3,4,};
表示数组的每个单元都是const int,所以必须通过初始化赋值。
- 因为把数组传入函数时候传递的是地址,所以那个函数内部可以修改数组的值,要保护数组不变,可设置参数为constint sum(const int a[]);