C语言学习笔记(七): 指针的使用
函数的定义
形参和实参
在定义函数时函数名后面括号中的变量名称为“形式参数”(简称“形参”)或“虚拟参数”。
在主调函数中调用一个函数时,函数名后面括号中的参数称为“实际参数”(简称“实参”)。
当函数被调用时,系统为形参分配内存空间。无论形参与实参的名称是否相同,它们都各自占用自己的存储空间。
函数的声明
函数声明是在程序中声明函数的名称、参数列表和返回类型的语句。它不包括函数的主体,也就是实际的代码。它的目的是向编译器说明接下来将定义的函数的类型,以便编译器知道如何处理函数调用
在函数声明中的形参名可以省略,只写形参的类型。
float add(float x, float y);
float add(float, float); //不写参数名,只写参数类型
float add(float a, float b); //参数名不用x,y,而用a,b。合法
函数的递归调用
在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。
程序中不应出现无终止的递归调用,而只应出现有限次数的、有终止的递归调用,这可以用if语句来控制,只有在某一条件成立时才继续执行递归调用;否则就不再继续。
例如这个例子,有5个学生坐在一起,问第5个学生多少岁,他说比第4个学生大2岁。问第4个学生岁数,他说比第3个学生大2岁。问第3个学生,又说比第2个学生大2岁。问第2个学生,说比第1个学生大2岁。最后问第1个学生,他说是10岁。请问第5个学生多大1.
include <stdio.h>
int main()
{ int age(int n); //对age函数的声明
printf("NO.5,age:%d\n",age(5)); //输出第5个学生的年龄
return 0;
}
int age(int n) //定义递归函数
{ int c; //c用作存放函数的返回值的变量
if(n==1) //如果n等于1
c=10; //年龄为10
else //如果n不等于1
c=age(n-1)+2; //年龄是前一个学生的年龄加2(如第4个学生年龄是第3个学生年龄加2)
return(c); //返回年龄
}
数组作为函数参数
数组元素可以用作函数实参,但是不能用作形参。
因为形参是在函数被调用时临时分配存储单元的,不可能为一个数组元素单独分配存储单元(数组是一个整体,在内存中占连续的一段存储单元)。
在用数组元素作函数实参时,把实参的值传给形参,是“值传递”方式。数据传递的方向是从实参传到形参,单向传递。
数组可以作为函数实参,通过"地址传递"的方式将值传递给形参
int test(int *p) {
int i = p[0];
return i;
}
int main()
{
int a[] = { 1,2,3,4,5 };
printf("%d", test(a)); //数组作为实参
}
一维数组作函数参数
例如下述例子,有一个一维数组score,内放10个学生成绩,求其平均成绩。函数的实参是一个数组名,其本质上属于值传递
include <stdio.h>
int main()
{ float average(float array[],int n);
float score[10]={67.5,89.5,99,69.5,77,89.5,76.5,54,60,99.5};//定义长度为10的数组
printf("The average of class B is %6.2f\n",average(score,10)); //用数组名score和10作实参
return 0;
}
float average(float array[],int n) //定义average函数,未指定形参数组长度
{ int i;
float aver,sum=array[0];
for(i=1;i<n;i++)
sum=sum+array[i]; //累加n个学生成绩
aver=sum/n;
return(aver);
}
二维数组作函数参数
如下例子所示, 有一个3×4的矩阵,求所有元素中的最大值。可以发现函数的参数是一个二维数组
include <stdio.h>
int main()
{ int max_value(int array[][4]); //函数声明
int a[3][4]={{1,3,5,7},{2,4,6,8},{15,17,34,12}}; //对数组元素赋初值
printf("Max value is %d\n",max_value(a));
//max_value(a)为函数调用
return 0;
}
int max_value(int array[][4]) //函数定义
{ int i,j,max;
max=array[0][0];
for(i=0;i<3;i++)
for(j=0;j<4;j++)
if(array[i][j]>max) max=array[i][j]; //把大者放在max中
return(max);
}
局部变量和全局变量
局部变量
在一个函数内部,可以在复合语句中定义变量,这些变量只在本复合语句中有效,这种复合语句也称为“分程序”或“程序块”。
形式参数也是局部变量。只在定义它的函数中有效。其他函数中不能直接引用形参。
全局变量
函数之外定义的变量称为外部变量,外部变量是全局变量(也称全程变量)。全局变量可以为本文件中其他函数所共用。它的有效范围为从定义变量的位置开始到本源文件结束。
若函数内的局部变量和全局变量同名,则局部变量会覆盖全局变量。
变量的生存期
从变量值存在的时间(即生存期)来观察,有的变量在程序运行的整个过程都是存在的,而有的变量则是在调用其所在的函数时才临时分配存储单元,而在函数调用结束后该存储单元就马上释放了,变量不存在了。
变量的存储方式
静态存储方式
静态存储的变量通常在程序整个生命周期中存在,不能在运行期间被删除,空间分配静态,因此使用静态存储的变量是程序中最常见的存储方式。静态存储的变量可以用关键字 "static" 声明
动态存储方式
动态存储是在程序运行时动态分配空间的存储方式。动态存储的变量可以在运行期间删除,不需要预先分配空间,因此可以根据需要调整内存分配。动态存储的变量用关键字 "malloc" 声明,使用 "free" 释放
变量的存储类别
自动变量
若局部变量不专门声明为static(静态)存储类别,都是动态地分配存储空间的,数据存储在动态存储区中。函数中的形参和在函数中定义的局部变量(包括在复合语句中定义的局部变量),都属于此类。在调用该函数时,系统会给这些变量分配存储空间,在函数调用结束时就自动释放这些存储空间。因此这类局部变量称为自动变量。自动变量用关键字auto作存储类别的声明
int f(int a) //定义f函数,a为形参
{
auto int b,c=3; //定义b,c为自动变量,新版本auto不能加在数据类型前面了
}
静态局部变量
若希望变量调用完后值还留着,即其占用的存储单元不释放,在下一次再调用该函数时,该变量的值就是上次用的值。这时就应该指定该局部变量为静态局部变量,用关键字static进行声明。
静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个运行期间都不释放。而自动变量(即动态局部变量)属于动态存储类别,分配在动态存储区空间而不在静态存储区空间,函数调用结束后即释放。
寄存器变量
为提高执行效率,允许将局部变量的值放在CPU中的寄存器中,需要用时直接从寄存器取出参加运算,不必再到内存中去存取。这种变量叫做寄存器变量,用关键字register作声明,如register int f;
外部变量
外部变量是在函数的外部定义的全局变量,它的作用域是从变量的定义处开始,到本程序文件的末尾
如下代码所示,在文件内扩展外部变量的作用域
include <stdio.h>
int main()
{ int max();
extern int A,B,C; //把外部变量A,B,C的作用域扩展到从此处开始
printf("Please enter three integer numbers:");
scanf("%d %d %d",&A,&B,&C); //输入3个整数给A,B,C
printf("max is %d\n",max());
return 0;
}
int A,B,C; //定义外部变量A,B,C
int max()
{ int m;
m=A>B?A:B; //把A和B中的大者放在m中
if(C>m) m=C; //将A,B,C三者中的大者放在m中
return(m); //返回m的值
}
如下代码所示,将外部变量的作用域扩展到其他文件
include <stdio.h>
int A; //定义外部变量
int main()
{ int power(int); //函数声明
int b=3,c,d,m;
printf("enter the number a and its power m:\n");
scanf("%d,%d",&A,&m);
c=A*b;
printf("%d*%d=%d\n",A,b,c);
d=power(m);
printf("%d**%d=%d\n",A,m,d);
return 0;
}
extern A;
//把file1中定义的外部变量的作用域扩展到本文件
int power(int n)
{ int i,y=1;
for(i=1;i<=n;i++)
y*=A;
return(y);
}
若不希望本文件的变量被外部文件引用,可以使用关键字static
声明变量
变量的声明
- 定义性声明:像
int a
这种需要建立存储空间的,称为定义性声明 - 引用性声明:像extern int a这种不需要建立存储空间的,称为引用性声明