当前位置: 首页 > news >正文

C语言如何跨文件调用函数定义中声明的变量

  • 变量的作用域

我们知道,变量根据其作用域有全局变量和局部变量之分。全局变量作用域是整个文件,并且可以使用关键字 extern 达到跨文件调用的目的。但是局部变量值作用于它当前所在的块(即该变量所处最内层中括号之间的区域),当函数执行完并离开当前块后,局部变量及其所处内存空间的值就会销毁。

  • static 关键字

static + 变量声明 表示声明的这个变量是静态变量。静态不是说它的值不会被改变,而是它在内存中的地址静止不动,这也就意味着它的值从一直到函数运行结束之前,都不会被销毁。有趣的是,它声明的的变量只会声明一次,再次调用声明语句时,会自动跳过这条语句。如下面这段代码:

#include <stdio.h>
int main()
{
    int i = 0;
    printf("num1\tnum2\n");
    for(i = 0;i<4;i++)
      { static int num1 = 4;
        int num2 = 4;
        num1 ++;
        num2 ++;
        printf("%d\t%d\n",num1,num2)      
      }
}  

运行结果为:

screenshot
可以看到static初始化的num1变量,虽然我们放在循环中,看起来好像每次都会对变量进行初始化,但是结果却出人意表,num1在循环中没有受到初始化语句的影响,可以正常的进行运算。

  • 指针

指针是一个值为内存地址的变量(或数据对象)。指针本身是不具有内存的,但是它可以通过赋值,指向其他变量的地址进而得到它的内存。因为在计算机中,所有的变量都会有单独一块内存空间,所以理论上,只要使用指针指向变量的地址,就可以在程序的任何位置调用变量。所以,指针是我们实现跨文件跨域调用变量最重要的手段。

  • 使用指针跨文件调用变量

有了上面的基础,我们就可以开始调用变量了。为了表现跨文件的功能,我们定义一个头文件 test.h ,并且在里面放入一个函数声明 void Input(); ,然后我们再创建一个 test.c 文件来作为头文件的实现文件。最后在主文件 main.c 中调用它,函数代码如下:
test.c文件

#include "test.h" 
int *ptr;        //声明一个外部指针用来调用变量
void Input()
{
     //初始化一个静态的数组
     static int nums[10] = {1,2,3,4,5,6,7,8,9,10};
     ptr = nums;  //将外部指针指向数组首地址 
}

main.c文件

#include "test.h"       //引用我们自定义的头文件
#include <stdio.h>
   extern int *ptr;       //调用我们的外部指针
   int main()
  {   
     Input();             //初始化数组并给指针赋值
     //下面打印结果,验证是否成功调用变量
     for(int i = 0;i<10;i++) 
       {
        printf("%d\t",*(ptr + i));
       }
   }

运行结果为
screenshot
可以看到,我们通过一个外部指针,在 Input() 函数内部将指针指向变量的地址,成功的调用了在其他文件的函数内部声明的数组/变量。
事实上,在这里面,static 关键字起到了至关重要的作用。我们尝试将nums[]数组改成普通的自动(auto)变量,看看运行结果:
运行结果为
screenshot
可以看到,循环打印出来的是一片混乱的数值,这意味着指针向内存的数值已经被销毁了

相关文章:

  • 思科网真应用解决方案
  • 使用Spring+MySql实现读写分离(一)关于windows下安装mysql5.6
  • android检测当前网络是否可用
  • 查询mssql的死锁语句
  • PBR基于策略的路由
  • linux光盘镜像更换kernel,定制ks自动安装
  • C# System.Windows.Forms.WebBrowser中判断浏览器内核和版本
  • 3、python自动化运维——定制业务质量报表
  • ***详解账号泄露:全球约1亿用户已泄露
  • 【mysql】mysql 配置
  • 怎样检测内存泄露
  • python之旅九【第九篇】socket
  • 【C#|.NET】利用FastDFS打造分布式文件系统
  • [LeetCode] Binary Tree Preorder Traversal 二叉树的先序遍历
  • 实用算法实现-第 24 篇 高精度整数运算
  • .pyc 想到的一些问题
  • 【译】React性能工程(下) -- 深入研究React性能调试
  • 0x05 Python数据分析,Anaconda八斩刀
  • Less 日常用法
  • MySQL数据库运维之数据恢复
  • nodejs:开发并发布一个nodejs包
  • Nodejs和JavaWeb协助开发
  • nodejs实现webservice问题总结
  • Xmanager 远程桌面 CentOS 7
  • 全栈开发——Linux
  • 入口文件开始,分析Vue源码实现
  • 我与Jetbrains的这些年
  • 智能情侣枕Pillow Talk,倾听彼此的心跳
  • # 执行时间 统计mysql_一文说尽 MySQL 优化原理
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • #我与Java虚拟机的故事#连载10: 如何在阿里、腾讯、百度、及字节跳动等公司面试中脱颖而出...
  • $(selector).each()和$.each()的区别
  • (7)STL算法之交换赋值
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第5节(封闭类和Final方法)
  • (六)Hibernate的二级缓存
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (转)setTimeout 和 setInterval 的区别
  • * 论文笔记 【Wide Deep Learning for Recommender Systems】
  • .h头文件 .lib动态链接库文件 .dll 动态链接库
  • .Net Core缓存组件(MemoryCache)源码解析
  • .NET 设计模式初探
  • .NET 中 GetHashCode 的哈希值有多大概率会相同(哈希碰撞)
  • .net连接MySQL的方法
  • .net通用权限框架B/S (三)--MODEL层(2)
  • .net下的富文本编辑器FCKeditor的配置方法
  • [ vulhub漏洞复现篇 ] Apache Flink目录遍历(CVE-2020-17519)
  • [ vulhub漏洞复现篇 ] JBOSS AS 5.x/6.x反序列化远程代码执行漏洞CVE-2017-12149
  • [Angularjs]asp.net mvc+angularjs+web api单页应用之CRUD操作
  • [ANT] 项目中应用ANT
  • [c#基础]值类型和引用类型的Equals,==的区别
  • [C#小技巧]如何捕捉上升沿和下降沿
  • [c++] C++多态(虚函数和虚继承)
  • [C++] new和delete
  • [C++]unordered系列关联式容器