C语言从文件中读取不同类型的变量,C语言之从内存角度理解不同类型的变量

我们都知道在C语言中不同类型的变量在内存中的存放位置不同的,从内存角度上讲,不同内存块中存放的代码或者变量其属性(主要是作用域、生命周期、链接属性)是不同的。

首先我们介绍一下作用域、生命周期已经链接属性的概念

1:作用域

作用域也就是指变量其作用的范围

(1)局部变量为代码块作用域(也就是说局部变量的作用范围是{  })

(2)函数和全局变量是文件作用域,进一步讲其作用范围就是函数和全局变量定义或者声明后的部分。

2:生命周期

生命周期也就是变量的产生时间和消亡时间

(1)栈变量的生命周期:局部变量是被分配到栈上面的(栈变量),其生命周期是临时的,临时的意思是按需要去创建、使用、消亡。比如在一个子函数里面定义了一个局部变量int a;那么当这个子函数被调用执行的时候,局部变量int a;会被创建在栈上面(符号a和栈上面的某个内存相绑定),当这个子函数被调用结束时,局部变量int a就消亡了(取消符号a和栈上面的某个内存的绑定),很现实的一个例子就是,当我们写个程序去读取局部变量的地址时,每次读取的地址值是不一样的。

(2)堆变量的生命周期

首先需要明白一点,堆内存空间是客观存在的,它是由系统维护的一段内存空间,程序员只是向系统申请堆内存,然后释放,所以堆变量也是有生命周期的,其生命周期就是mallloc(返回申请堆内存的首地址)申请到free释放,

(3)数据段、bss段的生命周期

全局变量的生命周期是永久的,永久的意思是从被定义开始,一直到程序结束。

(4)代码段、只读段的生命周期

代码段存放的是程序执行的代码(也就是函数),它的生命周期是永久的,但是一般不去研究代码的生命周期,需要注意的是放在代码段的还有const修饰的常量和字符常量(const类型的常量、字符串常量有时候放在rodata段,有时候放在代码段,取决于平台)

3:链接属性

链接属性是指代码在链接时的属性,包括外连接、内链接、无链接三种

(1)外连接:意思是外部链接属性,也就是说可以在整个程序范围(可以跨文件)内进行链接

(2)内链接:意思是内部链接属性,也就是说可以在当前c文件范围内进行链接

(3)无链接:意思是这个符号本身不参与链接,所有的局部变量(auto的,static的)都是无链接的

注意这里还涉及一个同名变量屏蔽规则的问题

(1)问题:编程时,不可避免会出现同名变量。变量同名后不一定会出错。

(2)首先,如果两个同名变量作用域不同且没有交叠,这种情况下同名没有任何影响。比如两个子函数里面都定义了局部变量int a;

(3)其次,如果两个同名变量作用域有交叠,C语言规定在作用域交叠范围内,

作用域小的一个变量会掩蔽掉作用域大的那个(就小范围原则)。比如定义了一个全局变量int a;又在子函数定义了局部变量int a;那么在这个子函数里面起作用的就是局部变量int a;

接下来从变量的类型角度出发,分析代码这三打要素具体到不同变量中的意义

1:普通局部变量

作用域为代码块作用域,生命周期为临时性生命周期,链接属性为无链接

普通局部变量被分配到栈上面,是按需创建、使用、消亡的,栈每次分配给变量是的地址是不确定的(随机分配)这就决定了其链接属性是无链接。

2:静态局部变量(static修饰的局部变量)

静态局部变量被分配到了数据段或者bss段(显示初始化为非0则被分配到数据段,未显式初始化或者显式初始化为0则被分配到bss段),作用域为代码块作用域,生命周期为永久性生命周期,链接属性为无链接(因为它的作用域是代码块作用域)。因为静态局部变量被分配到了数据段或者bss段,所以它的生命周期是永久的,所分配的地址和静态局部变量的符号的绑定是不变的,直到程序结束,所以在一个程序中多次使用同一个静态局部变量时其实操作的是同一段内存,因为有这一特性,所以静态局部变量常用来统计子函数被调用的次数。

3:全局变量和普通函数

作用域为文件作用域,生命周期为永久,链接属性为外连接

需要注意的是全局变量和函数不要在头文件中定义,原因是一个程序多处调用这个头文件(头文件中的内容在被预处理的时候是在文件中原地展开的)时就会出现重复定义(当然使用inline修饰的函数是可以放在有文件中的,并且不会城乡重复定义)。全局变量的外连接属性就决定了其必须是文件作用域以及永久的生命周期。

0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果要从文件结尾向前读取不知道大小的结构体变量,我们可以按照以下步骤进行: 1. 打开二进制文件: 使用C语言的`fopen`函数打开文件,并以二进制模式打开(`rb`)。 2. 定位到文件末尾: 使用`fseek`函数将文件指针定位到文件末尾。 3. 逐步向前读取数据: 从文件末尾开始,使用`fread`函数逐步读取数据,并将其存储到一个缓冲区。 4. 解析结构体变量: 通过解析缓冲区的数据来获取结构体变量。这需要根据结构体的定义和存储方式进行解析操作。 以下是一个示例代码,演示了如何实现上述步骤: ```c #include <stdio.h> #include <stdlib.h> typedef struct { // 定义结构体成员 int variable; } MyStruct; int main() { FILE *file = fopen("binary_file.bin", "rb"); // 打开二进制文件 if (file == NULL) { printf("无法打开文件\n"); return 1; } fseek(file, 0, SEEK_END); // 将文件指针定位到文件末尾 long fileSize = ftell(file); // 获取文件大小 long structSize = sizeof(MyStruct); // 获取结构体的大小 long numStructs = fileSize / structSize; // 计算结构体的数量 // 创建一个缓冲区,用于存储读取的数据 char *buffer = (char *)malloc(structSize * numStructs); if (buffer == NULL) { printf("内存分配失败\n"); return 1; } fseek(file, -structSize * numStructs, SEEK_END); // 将文件指针定位到最后一个结构体的位置 fread(buffer, structSize, numStructs, file); // 读取数据到缓冲区 // 解析结构体变量 for (int i = 0; i < numStructs; i++) { MyStruct *structPtr = (MyStruct *)(buffer + structSize * i); printf("第 %d 个结构体变量值为: %d\n", i + 1, structPtr->variable); } free(buffer); // 释放缓冲区内存 fclose(file); // 关闭文件 return 0; } ``` 请注意,以上示例代码仅为演示目的,实际使用时应进行错误处理和适当的调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值