❤️爆肝《C语言》函数指针❤️

C语言

5.函数概述与引用

  1. 一个c语言程序由一个或多个程序模块组成,每一个程序模块作为一个源程序文件。对于较大的程序, 一般不希望把所有的内容全放在一个文件中, 而是分别放在若干个源文件中, 由若干个源程序组成一个c程序。

  2. 一个源程序文件由一个或多个函数以及其他有关内容(如指令, 数据声明与定义等)组成。

     一个源程序文件是一个编译单位, 在程序编译时是以源程序文件为单位进行编译,而不是以函数为单位进行编译。
    
  3. c程序的执行是从main函数开始的

  4. 所有函数都是平行的, 也就是说在定义时是分别进行的, 互相独立的。函数间能互相调用,但是不能调用main函数, main函数是由操作系统调用的。

  5. 在定义函数时要指定函数的类型

  6. 使用库函数时应该在本文件开头用#include指令将调用有关库函数时所需要用到的信息”包含“到本文件中来。

  7. 函数的声明和定义只差一个分号;

5.1函数形式

(1).有参数函数
#include <stdio.h>
int max(int x, int y)
{
/* 局部变量声明 */
	if(x > y){
	return (x);
    //z=x>y?x:y;/* 函数返回两个数中较大的那个数 */
	} else{
	return (y);
}
}
int main(){
    int max(int x, int y);//在调用时可以不写形参名,但参数类型必须写
    int a, b, c;
    printf("put in int:");
    scanf("%d, %d, ",&a, &b);
    c = max(a, b);
    printf("max is %d\n", c);
    return 0;

}

(2.1)
#include <stdio.h>
int main(){
    int max4(int , int , int , int );
    int a, b, c,d,max;
    printf("please enter 4 interger numbers");
    scanf("%d%d%d%d", &a,&b,&c,&d);
    max = max4(a, b, c, d);
    printf("max=%d\n", max);
}
int max4(int a, int b, int c, int d){
        int max2(int , int );
        int m;
        m= max2(a, b);
        m = max2(m, c);
        m= max2(m,d);
    return (m);
}
int max2(int a, int b){
    if (a>=b)
        return a;
    else
        return b;
}
(2).无参数函数:
# include <stdio.h>

int main(){
    void print_star();
    void print_message();
    print_star();
    print_message();
    return 0;
}
//定义两个无参数函数
void print_star(){
    printf("**********\n");
}
void print_message(){
    printf("How do you do!\n");
    
}

5.2函数的递归调用

在调用函数的过程中直接或间接地调用该函数本身

函数不需要返回值时,则不需要return语句,此时函数的类型应该为void类型

# include "stdio.h"
int age(int n){
    int c=0;
    if (n==1)
        c =10;
    else
        c = age(n -1)+2;
    return (c);
}
int main(){
    int age(int );   	//对age函数声明
    printf("NO.5,age:%d\n", age(5));
    return 0;
}

(2)求递归n!
# include <stdio.h>
int main(){
    int fac(int n);
    int n;
    int y;
    printf("input an integer number:");
    scanf("%d",&n);
    y = fac(n);
    printf("%d!=%d\n",n,y);
    return 0;
}
int fac(int n ){
    int f;
    if(n<0)
        printf("n<0,data error!");
    else if(n==0||n==1)
        f=1;
    else  f=fac(n-1)*n;
    return (f);
}

(3)汉诺塔
# include "stdio.h"
int main(){
    void hanoi(int n, char one, char two, char three);
    int m;
    printf("input the diskes:");
    scanf("%d",&m);
    printf("the step to move %d diskes\n",m);
    hanoi(m,'A','B','C');
    return 0;
}

void move(char x, char y){
    printf("%c-->%c\n", x, y);
}

void hanoi(int n, char one, char two, char three){
    void move(char x, char y);
    if(n==1)
        move(one, three);
    else
    {
        hanoi(n-1,one,three,two);
        move(one,three);
        hanoi(n-1,two,one,three);
    }
}


5.3数组作为函数参数

  1. 数组元素可以用作函数实参,但是不可用作形参(形参是在被调用时临时分配储存单元的)
  2. 数据传递是从实参到形参,单向传递
  3. 数组名可做实参和形参
//输入十个数,输出最大的数及其位置
# include <stdio.h>
int main(){
    int max(int x,int y);
    int a[10],m,n,i;
    printf("enter 10 integer number:");
    for(i=0;i<10;i++)  //输入十个数给a[0]~a[9]
        scanf("%d", &a[i]);
        printf("\n");//不知有何意义???

    for(i=1,m=a[0],n=0;i<10;i++)
    {
        if(max(m,a[i]>m)){
            m= max(m,a[i]);
            n=i;
        }
    }
    printf("The largest number is%d\nit is the %dth number.\n",m,n+1);
    return 0;
}
int max(int x,int y){
    return (x>y? x:y);
}



(2)一维数组score内放十个数据,求平均值

#include "stdio.h"
int main(){
    float average(float array[10]);
    float score[10],aver;
    int i;
    printf("input 10 scores:\n");
    for(i=0;i<10;i++)
        scanf("%f",&score[i]);
    printf("\n");
    aver = average(score);
    printf("average score is %5.2f\n",aver);
    return 0;
}

float average(float array[10])//array为形参数组名
{
    int i;
    float aver,sum=array[0];
    for(i=1;i<10;i++)
        sum = sum+array[i];
    aver=sum/10;
    return (aver);
}

(3)3x4矩阵,求所有元素中的最大值

#include "stdio.h"
int main(){
    int max_value(int  array[][4]);
    int a[3][4]={{1,3,4,5},{4,8,11,6},{13,53,3,15}};
    printf("max value is %d\n", 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];
    return max;
}

5.4变量储存方式和生存期

从变量的作用域来看:变量可分为全局变量和局部变量

从另一个角度来看,变量值存在的时间来观察——生存期

1.储存空间分为:
(1)程序区
(2)静态存储区:

在程序开始执行时给全局变量分配储存区,程序执行完毕就释放,

对于局部变量来说:它使变量由动态储存方式改变为静态储存方式

对于全局变量来说:使得变量局部化(仅限于本文件中)。

(3)动态储存区:

以下这些数据,在函数的调用时,分配动态储存空间,即函数结束时释放这些空间。

  1. 函数形式参数,在调用函数时给形参分配储存空间
  2. 函数中定义的没有用关键字static声明的变量,即自动变量
  3. 函数调用时的现场保护和返回地址
每个函数中的局部变量的生存期并不等于整个程序的执行周期,他只是程序执行周期的一个部分
2.数据类型和储存类型
(1)局部变量的储存类别
  1. 自动变量(auto变量):函数中不专门声明为static储存类别,都是动态地分配储存空间
  2. 静态局部变量(static):局部变量的值在调用结束后不消失二继续保持原值,即其占用的储存单元不释放。多次调用,相当于会覆盖掉自身局部变量的值。
eg:
#include "stdio.h"
int main(){
    int f(int );
    int a=2,i;
    for(i=0;i<3;i++){
        printf("%d\n",f(a));
        printf("%d\n",f(a));
        printf("%d\n",f(a));
        //调用结束后,每一次调用c的值没消失,而是保存到程序的结束
        return 0;
    }
}
int f(int a){
    auto int b=0;
    static int c=3;
    b=b+1;
    c=c+1;
    return a+b+c;
}
求阶乘
#include "stdio.h"
int main() {
    int fac(int n);
    int i;
    for(i=1;i<=5;i++){
        printf("%d!=%d\n",i,fac(i));
    }
    return 0;
}
int fac(int n){
    static int f=1;
    f=f*n;
    return f;
}

3.寄存器变量(register变量)

使用频繁的变量将放在寄存器中,读取寄存器的速度要大于内存

但优化的编译系统能够识别使用频繁的变量,从而自动将这些变量放在寄存器中。
(2)全局变量的存储类别:

存放在静态存储中,生存期是固定的,存在与程序的整个运行过程,,但作用域是从什么位置到那个位置。有以下几种情况:

1.在一个文件内扩展外部变量的作用域

如果外部变量不在文件的开头定义,则其有效的作用范围只限定于定义处到文件结束。在定义点之前的函数不能引用该2外部变量。如果要用,则在引用之前用关键字extern对改变量作“外部变量声明”

#include "stdio.h"
int main() {
    int max();
    extern int A,B,C;
    printf("input  number:");
    scanf("%d%d%d",&A,&B,&C);
    printf("max is %d\n",max());
    return 0;
}
//全局变量	A,B,C使用static后对main函数不起作用
int A,B,C;
int max(){
    int m;
    m=A>B?A:B;
    if(C>m)m=C;
    return m;
}

提倡将外部变量的定义放在引用它的函数之前。

2.将外部变量的作用域扩展到其他文件

一个c程序可以由一个或多个源程序文件组成。当两个或以上的文件都要用到同一个外部变量时,不能分别在两个文件中各自定义一个变量,这时需要使用extern对其做外部声明。

//file1.c
#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;
}

//file2.c
#include "stdio.h"
extern A;
int power(int n){
    int i,y=1;
    for(i=1;i<=n;i++){
        y*=A;
    }
    return y;
}

3.将外部变量的作用域限制在文本中

使用static则可以将外部变量的作用域限制在本文件内。

这种只能用于本文件的外部变量称为静态外部变量。

小结:

1.声明变量时是在定义变量的基础上加上关键字,而不是单独使用。

2.对于一个数据的定义,需要指定两种属性:数据类型和存储类型

3.对于变量大的属性可以从两个方面:一是变量的作用域,二是变量存在时间的长短。前者从空间的角度,后者从时间的角度。

5.5关于变量的声明和定义

将建立储存空间的声明称为定义

把不需要建立储存空间的声明称为声明

函数中除了用extern声明的以外都是定义

5.6外部函数和内部函数

1.内部函数:

如果一个函数只能被本文件中其他函数所调用,它称为内部函数

static 类型名 函数名(形参表)

2.外部函数:

如果在定义函数时,在函数首部的最左端加关键字extern,则此函数是外部函数,可供其他函数调用。

但是c语言规定,如果在定义函数是省略extern,则默认为外部函数

//main
#include "stdio.h"
int main(){
    extern void enter(char str[]);
    extern void delete(char str[],char ch);
    extern void print(char str[]);
    char c,str[50];
    enter(str);
    scanf("%c",&c);
    delete(str,c);
    print(str);
    return 0;
}
//f1.c
#include "stdio.h"
void enter(char str[50]){
    gets(str);
}
//f2.c
#include "stdio.h"
void delete(char str[],char ch){
    int i,j;
    for(i=j=0;str[i]!='\0';i++)
        if(str[i]!=ch)
            str[j++]=str[i];
    str[j]='\0';
}
//f3.c
#include "stdio.h"
void print(char str[]){
    printf("%s\n",str);
}

6.指针

6.1数据如何储存,读取

存取一个数据,除了需要位置信息外,还需要该数据的类型信息。

即C语言中的地址包括位置信息和它所指向的数据的类型,或者说带:类型的地址。如:&a:“整形变量啊的地址”

  1. 直接访问:直接按变量名进行访问的方法
  2. 间接访问:将变量i的地址存放在另一个变量中,然后通过该变量来找到变量i的地址。

6.2指针变量

存放地址的是指针变量

*如何定义指针变量:类型名 指针变量名

*表示该变量是指针变量。

在赋值时,值是给指针变量名的,而不是,*指针变量名

例:

int a,b;

int *point_1 = &a,*point_2 = &b;
//a的地址给了point_1而不是*point_1
int a,b;

int *point_1,*point_2;
point_1 = &a;
point_2 = &b;
//a的地址给了point_1而不是*point_1

指针变量中只能存放地址

6.2.1引用指针变量
  1. 引用指针变量的值:printf(“%o”,p);

  2. 引用指针变量指向的变量:如果已经执行“p=&a;”,即变量指针p指向了整型变量a

    & 取地址运算符。

    *指针运算符,星号p代表指针变量p指向的对象;

    //
    // Created by 20248 on 2021/7/25.
    //
    
    #include <stdio.h>
    int main()
    {
        int *p1,*p2,*p,a,b;
        printf("input 2 number:");
        scanf("%d%d",&a,&b);
        p1 =&a;
        p2=&b;
        if(a<b)
            {p=p1;p1=p2;p2=p;}
        printf("a=%d,b=%d\n",a,b);
        printf("max=%d,min=%d\n",*p1,*p2);
        return 0;
    }
    
6.2.2指针变量作为函数参数
//
// Created by 20248 on 2021/7/25.
//

#include <stdio.h>
int main(){
    void swap(int *p1,int *p2);
    int a,b;
    int *point1,*point2;
    printf("input a and b:");
    scanf("%d%d",&a,&b);
    point1=&a;
    point2=&b;
    printf("%o\n%o\n",point1,point2);
    if(a<b)
        swap(point1,point2);
    printf("%d%d",a,b);
    printf("%o\n%o\n",point1,point2);
    printf("max=%d,min=%d\n",a,b);
    return 0;
}

void swap(int *p1,int *p2){
    int temp;
    temp=*p1;
    *p1=*p2
    *p2=temp;/*完成交换后,p1和p2的地址是不变的,但是			地址包含的值已变化
    		上一个例子,地址变化*/
}

/*
int *p;
p=p1;
p1=p2;
p2=p;
不能通过改变指针形参的值而使指针实参的值改变*/

6.3通过指针引用数组

数组中每个元素都需要在内存中战用储存单元。

所谓数组元素的指针就是数组元素的地址。

int c[10]={10个值}int *p;
p=&a[0];//用一个指针指向一个数组元素。
//等价于:p=a;数组名代表数组中首元素的地址
//等价于:int *p=a;将a数组首元素的地址赋值给指针变量p
6.3.1指针的运算

在指针已指向一个数组元素时,可以做以下运算

加一个整数,(用+或者+=),如p+1;

减一个整数,(-或-=),如p-1;

自加运算,p++,++p;

自减运算,p–,--p;

两个指针相减,如p1-p2(只有都指向同一数组时才有意义)

通过数组名计算数组元素的地址:

#include "stdio.h"
int main(){
    int a[10];
    int i;
    printf("input 10 int number:\n");
    for(i=0;i<10;i++)
        scanf("%d",&a[i]);
    
    for(i=0;i<10;i++)
        printf("%d",*(a+i));//a中序号为i的元素;
    printf("\n");
    return 0;
}

用指针变量指向数组元素

#include "stdio.h"
int main(){
    int a[10];
    int *p,i;
    printf("input 10 int number:\n");
    for(i=0;i<10;i++)
        scanf("%d",&a[i]);
    //for(p=a;p<(a+10);p++):a+10等价于&a[10]
    //   scanf("%d",p);用指针变量表示元素的地址
    for(p=a;p<(a+10);p++)
        printf("%d",*p);
    //无法用数组名a变化的方法,因为数组名a代表数组首元素的地址,它是一个指针型常量,它的值在运行期间固定不变
    printf("\n");
    return 0;
}

错例子:

#include "stdio.h"
int main(){
    int i,*p,a[5];
    p=a;
    printf("input 5 number:");
    for(i=0;i<5;i++)
        scanf("%d",p++);//此时p的指针指向的是5以后的地址,i此时也等于5!!!
    //p=a;重新指向a[0]
    for (i = 0; i <5;i++,p++)
            printf("%d",*p);
        printf("\n");
        return 0;
}
6.3.2数组名作函数参数:
#include "stdio.h"
int main()
{
    void inv(int *,int n);
    int i,a[10]={1,3,4,5,1,5,7,8,4,2};
    printf("the original array:\n");
    for(i=0;i<10;i++)
        printf("%d",a[i]);
    printf("\n");
    inv(a,10);
    printf("the array has been:\n");
    for(i=0;i<10;i++){
        printf("%d",a[i]);
    }
        printf("\n");
        return 0;
}

void inv (int *x,int n){
    int *p,temp,*i,*j,m=(n-1)/2;
    i=x;
    j=x+n-1;
    p=x+m;
    for(;i<=p;i++,j--)
    {
        temp=*i;*i=*j;*j=temp;
    }
    return;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

弈鸣coding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值