C - 函数 域

C语言–备忘



一、函数定义

  1. 函数就是一堆语句的组合,可以实现一些相对独立和通用性的功能;
  2. 任何C语言,包括一对变量(包括数组)和一堆的函数
  3. 解决繁琐代码,重复编写,加大开发量;为解决这个问题,使用函数这个技术,只需编写一遍;
  4. 将公共代码独立化;
    return -1; //一般用来让程序结束,不能继续运行
    return 0; //表示程序运行成功

二、函数声明

  1. 函数声明三步骤
    1.1 函数声明:告诉gcc,将来这个函数可以给别人或者自己用,函数声明不分配内存空间
    1.2 函数声明的语法:
    1.3 如果函数定义在函数调用之前,可以省略函数声明,否则必须声明 ;
extern 返回值数据类型 函数名(形参表)
建议:函数声明加extern ,提高代码可读性;

三、函数定义

函数定义:

  1. 函数定义功能:就是一个函数的具体实现过程,里面包含语句,可被其他调用;
  2. 函数定义语法:
 返回值数据类型 函数名(形参表)
 {
     一堆的函数体语句; 
 }
 int add(int x, int y)
 {
     return x+y; 
 }
 int main(void)
 {
     int sum= add(100,200);
     return 0; 
 }

四、函数调用

  1. 函数调用功能:俗称使用函数,调用函数,访问函数
  2. 调用语法:接收函数返回值的变量 = 函数名(实参表)
  3. 函数调用特点:实参表- 就是给函数形参表赋值的值
sum=add(100,200);//100、200就是实参
// 实参的内存空间和形参的内存空间实独立的,地址不相同,但存储的数据相同

五、函数使用

形式1:无参数无返回值

void 函数名(void{
    函数语句;
}

形式2:无参数有返回值

int 函数名(void{
    函数语句;
}

形式3:有参数无返回值

void 函数名(int x) 
{
    函数语句;
}

形式4:有参数无返回值

 建议小于4个,影响运行效率
void 函数名(int x,int y,int m,int n) 
{
    函数语句;
}

形式5:有参数有返回值

 建议小于4个,影响运行效率
int 函数名(int x,int y,int m,int n) 
{
    函数语句;
}

形式6:return关键字和exit函数

  1. return:实现函数返回
  2. exit: 让程序强制结束,为使用次函数需添加 #include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
void print(void)
{
    printf("1.\n");
    exit(0);//程序到此结束
    //return;//程序返回至main函数,继续执行
    printf("2.\n");
}
int main(void)
{
    print();
    printf("3.\n");
    return 0;//让程序正常结束,0表示正常
}

要点说明:

#include <stdio.h>
 extern void print(int a,int b,int c, int d);
 extern int read(void);
 // 自定义 print 函数
 void print(int a,int b, int c, int d)
 {
     printf("a、b、c、d的四个变量的地址为%p,%p,%p,%p",&a,&b,&c,&d); 
     //abcd的值与main函数相同,但是地址不同
     return;//只要CPU碰到return,此函数立马返回//
 }
 
 int read(void)
 {
     int a=250;
     a++;
     a+=250
     return a;//有返回值,但是若不添加return,将返回一个随机数
 }
 
 int main(void)
 {
     int a=1,b=1,c=1,d=1;
     //查看main函数中的地址和函数中的地址是否相同,
    printf("abcd的地址为%p,%p,%p,%p\n"&a,&b,&c,&d);
    
    // 打印,形参和实参内存情况如下图
    print(a,b,c,d);
    printf("read的返回值为:%d\n",read());
      
    return 0; 
 }

注意:形参就是实参的一份拷贝,实参传递至形参时,拷贝一份。
Alt

六、函数和数组

说明:数组和参数最重要的区别在于传递地址;

/*定义访问数组的函数*/
void 函数名(数组的首地址,数组的长度)
{
    可以查看数组元素;
    可以修改数组元素;
}  

案例1: 说明数组与函数关系

#include <stdio.h>
void print_array(int a[],int length)//a[]为数组首地址
{
    for(int i=0;i<length;i++){
        printf("%d\n",a[i]);    //数组元素可直接使用
    }
    printf("%d\n");
    return;
}
void change_array(int a[],int length) //同理
{
    for(int i=0;i<length;i++){
        a[i] *=10;    
    }
    return; 		   
}
int main(void)
{
    int array[5]={1,2,3,4,5};
    /*调用print_array 函数打印数组元素值*/ 
    //二维数组的sizeof(array)表示空间大小
 	print_array(array,sizeof(array)/sizeof(array[0]));   
    change_array(array,sizeof(array)/sizeof(array[0]));   
   
   return 0;
}

案例2: 实现数组元素内容交换

  1. 定义两个元素的数组,利用函数将这两个元素互换
  2. 利用函数将数组中某个元素的第n位清零
  3. 利用函数将数组中某个人元素的第n位置零
#include <sdtio.h>
extern void swap(int a[],int length);

/*定义交换数组的数据,可定义任意两个元素的交换*/
 void swap(int a[],int length)
 {
     int c=a[0];
     a[0]=a[1];
     a[1]=c; 
     return;
 } 
 /*将数组的某一个元素的位清零*/
 void clear_array_bit(int a[],int index, int n)
 {
     a[index] &=~(1<<n);//与非清零 //a[index] |=(1<<n);
     return;      
 }
 
int main(void)
{
    int a[2]={1,2};
    
    printf("打印%d%d",a[0],a[1]);
    swap(a,sizeof(a)/sizeof(a[0]));
    printf("打印%d%d",a[0],a[1]);
    
    clear_array_bit(a,3,1);//将数组的第三个元素的,第 1 位清零
    return 0;
}

七、作用域与可见性

说明:按照作用域【范围】可见性【生命周期】来分:

  1. 局部非静态变量
  2. 局部静态变量
  3. 全局非静态变量
  4. 全局静态变量

局部与全局

定义: 定义在函数内部

void A(void)
{
    int a=250;//此为局部变量
}

定义: 定义为函数之外的变量

int g_b=520//全局变量
void A(void)
{
    int a=250;//此为局部变量
}
int g_c=521;//全局变量

形式一:局部非静态变量

1. 定义:static关键字:如果定义变量前面加static关键字修饰,表明为静态变量;
2. 变量使用范围:从定义的地方开始,从定义的地方开始一次向下直到最近的花括号结束;
3. 内存生命周期:从定义的地方,操作系统会给变量分配内存,直到最近的花括号,操作系统会立马收回变量的内存;
4. 函数形参:void A(int a); //a在整个函数体都可以用,出了函数就不能用,以下代码说明:

形式1void A1(int c)
{ 
    printf("a=%d\n",a);//不可以,报错,gcc编译时报没有定义的错误
    int a=250;//定义 局部非静态变量
    printf("a=%d\n",a)//可以
    print("c=%d\n",c);//c变量只能在函数内部使用,不允许在main函数使用
}

形式2void A2(void)
{
    if(1){
        int a=250; //此变量的作用域为最靠近的花括号{}之内,出了范围就消亡
        printf("a=%d\n",a);//可以    
    }
    printf("a=%d\n",a);//不可以,报错,gcc编译时报没有定义的错
}
int main()
{
    A1(23);
    A2();
    return 0;
}

形式二:局部 静态变量 (钉子户)

1. 变量使用范围:从定义的地方开始,从定义的地方开始一次向下直到最近的花括号结束;
2. 内存生命周期:定义的地方开始分配内存直到程序结束;一次分配,程序不结束下一次不会分配内存,接着上一次的用;/重要程序不结束,下一次就不会重新分配内存;

void A1()
{
    static int a=250;//定义 局部静态变量
    printf("a=%d\n",a)//可以
    a= 10;
}
int main(void)
{
    A1();//输出a=250
    A1();//不会再给 static int a 分配内存,相当于语句不执行,接着上次使用,a=10;
    return 0;
}

形式三:全局 非静态变量

1. 在同一源文件

1. 变量使用范围:全局非静态变量的定义和使用访问都是在同一个文件
2. 内存生命周期:定义的地方开始分配内存直到程序结束;

void B(void)
{
    printf("g_a=%d\n",g_a);//不可以,gcc报没有定义的错误
}
 int  g_a=10;//定义初始化为全局非静态变量,只从定义的地方开始,到程序结束;
 
 void A(void) 
 {
     printf("g_a=%d\n",g_a);//可以,函数内部访问全局非静态变量 
 }

2. 在不同源文件

1. 明确:如果一个源文件定了一个全局非静态变量,另外一个文件想要直接访问这个全局非静态,只需要extern 声明这个全局非静态即可
2. 语法:声明全局非静态变量的语法:extern 数据类型 全局非静态变量名;
3. 结论:一旦声明,就可以访问别的文件定义好的全局非静态变量。
4. 切记:变量使用范围分两种情况:

  1. 如果本文件访问,范围为定义的地方开始向下可以访问,前面的不可以;
  2. 如果是不同文件(跨文件)之间访问,范围是声明的地方依次向下所有的函数都可以访问;
  3. 此变量生命周期:从启动运行程序时,操作系统就会分配内存;知道程序结束,操作系统回收。
  4. 切记:全局非静态变量实际开发时少用,慎用,避免出现乱序,一定记得互斥访问保护,但是降低执行效率。
//*全局非静态变量:同一个文件*//* vim func1.c *//
#include <stdio.h>
/*定义全局非静态变量*/
int g_a=250;
void A(void)
{
    printf("A函数:g_a=%d\n",g_a);
}
void B(void)
{
    g_a++;
}

*vim func2.c*
#include <stdio.h>
extern void A(void);
extern void B(void);//由于跨文件访问函数,故调用前需要声明才行
extern int g_a;//由于跨文件访问变量,故调用前需要声明才行
int main(void)
{
    A();//打印250
    B();//变量自加1
    A();//打印251
    printf("g_a=%d",g_a);
    return 0;
}
/最后执行 gcc -o func1 func1.c func2.c

形式四:全局 静态变量

  1. 全局 静态变量的定义和使用访问都是在同一个文件
  2. 全局静态变量只能用于本文件,其他源文件不可访问;
  3. 能降低乱序的可能性;
  4. 只能用于定义变量的文件中,而且从定义的地方开始。
  5. 生命周期:启动程序开始,分配内存,直到结束再将内存收回。
  6. 少用、慎用,迫不得已,互斥访问,但是比全局非静态发生乱序的现象要小;
 // vim var.c
#include <stdio.h>
 void B(void)
 {
     printf("g_a=%d\n",g_a);//不可以,gcc报没有定义的错误
 }
 static int  g_a=10;//定义初始化为全局静态变量,只从定义的地方开始,到程序结束;
 void A(void) 
 {
     printf("g_a=%d\n",g_a);//可以,函数内部访问全局非静态变量 
 }
 static void C(void)//vim var1.c无法访问此函数
 {
     g_a--; 
 }
 
 /vim var1.c
 #include <stdio.h>
 extern void B(void);//声明函数A
 extern void A(void) ;//声明函数B
 extern g_a; //声明全局变量g_a,报错
 int main(void)
 {
      B();
      A();
      C();//报错
      return 0;
 }
  gcc -o var var.c var1.c

总结

  1. static修饰的全局变量只能用于本文件,其余文件不允许。
  2. static 修饰的函数只能用于本文件,其他文件不能访问。
  3. static 的变量和函数用起来 相对安全,间接保护,降低乱序发生概率
  4. 抢夺CPU能力:A程序<B程序,互斥抢夺运算,造成全局变量混乱
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值