C语言学习(九)多文件编程 存储类型 结构体

目录

  • 一、多文件编程
      • (一)不写头文件的方方式进行多文件编程
    • (二)通过头文件方式进行多文件编程
      • (1)方法
      • (2)头文件守卫
    • (三) 使用多文件编程实现+ - * / 功能
  • 二、存储类型
    • (一)auto
    • (二)register
    • (三)const
      • 1. const修饰局部变量和全局变量
      • 2. const修饰指针
    • (四)static
      • 1. static修饰的局部变量
      • 2. static修饰的全局变量
      • 3.static修饰函数
    • (五)extern
    • (六)volatile
  • 三、结构体
    • (一)结构体类型定义
    • (二)结构体变量的定义
    • (三)结构体变量赋值
      • 1. 定义结构体变量的同时进行赋值
      • 2. 定义结构体类型的同时定义变量并进行赋值
      • 3. 在定义结构体变量时对指定成员进行赋值
      • 4. 在定义完结构体变量后,通过'.'进行赋值
    • (四)结构体成员访问
    • (五)结构体内部指针的使用
    • (六)结构体指针传参

一、多文件编程

编写一个大型文件时,一般会按照功能生成多个.c文件,

(一)不写头文件的方方式进行多文件编程

extern(存储类型):定义的内容在其他文件中。
类似文件声明,只不过声明的函数在其他文件中。

eg
function1.c 文件

#include <stdio.h>

void function1()
{
	printf("This is fun1 file\n");
}

function2.c 文件

#include <stdio.h>

void function2(int len)
{
	for(int i=0;i<len;i++)
	{
		printf("This is fun2 file\n");
	}
}

test.c 文件

#include <stdio.h>

extern void function1(); //function()为定义在其他文件中的函数
extern int function2(int len);

int main()
{
	function1();
	function2(3);
	return 0;
}

编译方法
gcc test.c function1.c function2.c -o test

输出结果:
在这里插入图片描述

(二)通过头文件方式进行多文件编程

(1)方法

#include "head1"
  • 注:使用引号,是先在自己的路径下找,再去系统的库文件去寻找

编译方法
gcc test.c function1.c function2.c
或者
gcc *.c 意思是编译所有.c文件

(2)头文件守卫

防止重复导入头文件
head1.h文件

#ifndef __HEAD1_H__ 
#define __HEAD1_H__

/***code***/

#endif

(三) 使用多文件编程实现+ - * / 功能

eg
main.c文件

#include "func.h"                                                                                                                                                                 

int main(int argc, const char *argv[])
{
    int x,y;
    char op;

    printf("please input:");
    scanf("%d%c%d",&x,&op,&y);

    switch(op)
    {
    case '+':
        printf("%d%c%d=%d\n",x,op,y,add(x,y));
        break;
    case '-':
        printf("%d%c%d=%d\n",x,op,y,sub(x,y));
        break;
    case '*':
        printf("%d%c%d=%d\n",x,op,y,mul(x,y));
        break;
    case '/':
        printf("%d%c%d=%d\n",x,op,y,div(x,y));
        break;
    }

    return 0;
}

func.h文件

#ifndef __FUN_H__
#define __FUN_H__

#include <stdio.h>

extern int add(int x,int y); 
extern int mul(int x,int y); 
extern int div(int x,int y); 
extern int sub(int x,int y);                                                               

#endif

add.c 文件

int add(int x,int y)
 {
     return x+y;
 } 

sub.c 文件

int sub(int x,int y)
 {
     return x-y;
 } 

mul.c 文件

int mul(int x,int y)
 {
     return x*y;
 } 

div.c 文件

int div(int x,int y)
 {
     return x/y;
 } 

输出结果
在这里插入图片描述

二、存储类型

<存储类型> <数据类型> 标识符 = value;

(一)auto

主要用于修饰自动类型的变量,局部变量就是自动类型。
如果没有赋初值,就是随机值。(因为在栈区)
eg:auto int a = 10; //auto可以省略不写

(二)register

寄存器是硬件设备中的一小块空间,定义为rigister类型的变量可以使运算速度变快;但是其大小一般是4个字节,且个数有限,价格昂贵,所以尽量不要使用register。

由于register类型的变量是存储在寄存器上,因此无法取得它的地址。

(三)const

const修饰的变量是只读变量。不是常量。

1. const修饰局部变量和全局变量

const修饰的局部变量存储在内存中的栈区,可以通过指针修改(会报警告)
const修饰的全局变量存储在常量区的readonly区,不能通过指针修改

/***此处代码是为了理解***/
#include <stdio.h>

const int number2 = 20;

int main()
{
	const int number = 10;
	printf("number = %d",number);//可读

	number = 20; //对只读常量进行修改会报错
	
	//通过指针修改可以修改,但是会报警告
	int *p = &number;
	*p = 200;
	printf("number = %d\n",number);

	//const修饰的全局变量通过指针也不可修改
	int *p2 = &number2;
	*p2 = 200;
}  

2. const修饰指针

const修饰的指针,const在谁前面谁就不能修改

/***此处代码是为了理解***/
#include <stdio.h>
int main()
{
	int number1 = 10;
	int number2 = 20;
	//*p1不能修改 p1可修改
	const int *p1 = &number1;
	*p1 = 200; //报错
	p = &number2; //可以执行
	
	//p2不能修改 *p2可以修改
	int * const p2 = &number1;
	*p2 = 200; //可执行
	p2 = &number2; //报错

	//*p3和p3都不能修改
	const int * const p3 = &number1;
	*p3 = 200; //报错
	p3 = &number2; //报错
}  

(四)static

static 修饰的未初始化的变量在.bss段;
static 修饰的初始化的变量在.data段;

1. static修饰的局部变量

可以延长局部变量的生命周期,到程序结束的时候才会被释放。
作用域不会发生改变。

#include <stdio.h>

void add1()
{
	static int num = 0;
	printf("num = %d\n",num++);
}
int main()
{
	for(int i=0;i<5;i++)
		add1();
	return 0;
}

输出结果:
图片

2. static修饰的全局变量

static修饰的全局变量的生命周期是整个程序。
作用域:只能在本文件中使用。

3.static修饰函数

作用域:static修饰的函数只能在本文件中进行使用,不能跨文件使用。

(五)extern

外部声明,extern修饰的变量以及函数定义在其他文件中。
只能声明,不能定义。

(六)volatile

每次读值都要从内存中读取,不可以从cache中读取。

应用:
多线程操作时在全局变量前添加volatile
硬件操作时添加volatile
在中断处理函数中访问非自动类型的变量需要加volatile。(ARM接口技术)

三、结构体

结构体是一个构造类型,可以由不同类型的元素的成员组成。

结构体是一个类型,而非变量。
一般定义在全局,如果定义在函数中,只能在函数内部使用

(一)结构体类型定义

struct <结构体名称>
{
	<变量类型1> <变量名1>;
	<变量类型2> <变量名2>;
	...
	<变量类型n> <变量名n>;
}; //分号不能省略

eg: 定义一个结构体

#include <stdio.h>

struct Student{
	char name[128];
	int age;
	float sore;
};
  • 注:
    1. struct 是结构体的关键字,必须书写。
    1. 结构体名称可以省略,一般定义在结构体内部时使用这种方式,定义变量的方式略有不同。
    1. 结构体内部的成员是通过花括号来包括的
    1. 结构体类型的最后必须包括一个’;’
    1. 结构体内部的成员必须是确定大小的,所以结构体内部是不能写函数的。
    1. 结构体内部成员的数据类型可以相等,也可以不等
    1. 注意C语言中不能在定义结构体时在结构体内部进行赋值,即下面的定义是错误的
#include <stdio.h>
/***这种定义方法是错误的***/
struct Student{
	char name[128] = “lily”;
	int age = 10;
	float sore = 100;
};

(二)结构体变量的定义

结构体变量定义:
struct <结构体名称> 标识符;

结构体指针变量:
struct <结构体名称> *标识符;

(三)结构体变量赋值

1. 定义结构体变量的同时进行赋值

struct Student s2 ={"xiao,18,99.9"};
//访问
printf("name:%s\n",s2.name);

2. 定义结构体类型的同时定义变量并进行赋值

struct Student{
	char name[128];
	int age;
	float sore;
}s1={"lily",17,99}; 

3. 在定义结构体变量时对指定成员进行赋值

struct Student{
	char name[128];
	int age;
	float sore;
}s1={.name="Lily"};
  • 注:不能写成下面的形式
/***错误的写法***/
struct Student{
	char name[128];
	int age;
	float sore;
}s1={s1.name="Lily"};//这种是错误的写法

4. 在定义完结构体变量后,通过’.'进行赋值

struct Student{
	char name[128];
	int age;
	float sore;
};

int main()
{
	struct Student s1;
	
	strcpy(s1.name,"Lily");
	s1.age = 18;
	s1.sore = 99;
} 

(四)结构体成员访问

结构体变量:
通过 <结构体变量>.<成员> 来访问

结构体指针:
*p . <成员>
p -> <成员>

eg :使用指针访问结构体的值,实现两个虚数相加。

#include <stdio.h>

struct vir 
{
    int x;
    int y;
}s1={12,3},s2={65,32},s3; 
//此时s1,s2,s3均为全局变量
//他们的成员也都是全局变量,存储在常量区的.bss段和.data段

int main(int argc, const char *argv[])
{
    
    struct vir *p1 = &s1;
    struct vir *p2 = &s2;
    struct vir *p3 = &s3;

    p3->x=(p1->x)+(p2->x);
    p3->y=(p1->y)+(p2->y);
    printf("s1+s2=%d+%d*i\n",p3->x,p3->y);

    p3->x=(p1->x)-(p2->x);
    p3->y=(p1->y)-(p2->y);
    printf("s1-s2=%d+%d*i\n",p3->x,p3->y);                                                                                                                     
    
    return 0;
}

(五)结构体内部指针的使用

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
struct Place
{
	int *arr;
	int size;
	int capacity;
};
int main()
{
	struct Place t;

	t.arr=(int *)malloc(4*50);//申请50个int型数据的空间大小
	t.size = 0;//相当于下标
	t.capacity = 50;//可以容纳的数据的个数
}

(六)结构体指针传参

eg:在堆区申请一段地址连续的空间
create函数,申请一块空间
write函数,向申请的空间内写值

#include <stdio.h>
#include <stdlib.h>

//定义结构体类型
typedef struct Place{
    int* arr;
    int size;
    int capacity;
}Place_t;

//创建空间
int create(Place_t *s,int size)
{
	if(!p)
	{
		printf("struct is empty!\n");
		return -1;
	}
    s->arr = (int *)malloc(4*size);
    if(!(s->arr))
    {
        printf("create fail!\n");
        return -1;
    }
    s->size=0;
    s->capacity=size;

    printf("create %d please success!\n",size);

    return 0;
}
//向空间中写值
int write(Place_t *s,int num)
{
	if(!p)
	{
		printf("struct is empty!\n");
		return -1;
	}
    if((s->size)<=(s->capacity))
    {   
    	*((s->arr)+(s->size)) = num;
    	(s->size)++;
    }else
    {   
        printf("capacity is full!\n");
        return -1;                                                                                                                                                                                                   
    }   
    return 0;
}

int main(int argc, const char *argv[])
{
    Place_t a;
    int size;
    int num;

    printf("请输入需要多少空间:");
    scanf("%d",&size);  
    create(&a,size);

    for(int i=0;i<size;i++)
    {   
        printf("please input %d number:",i);
        scanf("%d",&num);
        if(write(&a,num))
        {
            printf("write fail!\n");
        }
    }

    for(int i=0;i<size;i++)
    {
        printf("%d\n",*(a.arr+i));
    }
    
    //释放内存
    free(a.arr);
    a.arr=NULL;
    
    return 0;
}  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/618060.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

系统设计中的泛化调用

背景 目前在学习一些中间件&#xff0c;里面看到了一个词是叫泛化调用&#xff0c; 其实这个场景在JAVA中比较常见。我们常用的有反射&#xff0c;反射就是我知道类名称、类方法和参数&#xff0c;调用一个Object的类&#xff0c;但是在HTTP或者RPC远程调用过程中&#xff0c;…

服务异步通讯MQ

同步调用存在的问题: 异步调用方案: RabbitMQ安装: 第一种:在线拉取 docker pull rabbitmq:3-management 第二种:将已有的安装包放入再用load加载 我这里放到tmp包里边 然后:cd /tmp docker load -i mq.tar 加载进去 然后运行mq容器 docker run \-e RABBITMQ_DEFAULT_USER…

【一步一步了解Java系列】:了解Java与C语言的运算符的“大同小异”

看到这句话的时候证明&#xff1a;此刻你我都在努力~ 加油陌生人~ 个人主页&#xff1a; Gu Gu Study ​​ 专栏&#xff1a;一步一步了解Java 喜欢的一句话&#xff1a; 常常会回顾努力的自己&#xff0c;所以要为自己的努…

下水道井盖多分类检测定位

下水道井盖识别&#xff0c;多分类&#xff0c;使用yolov5训练&#xff0c;采用一部分开源数据集和自建数据集。python pytorch opencv 深度学习#人工智能#深度学习#目标检测

在STM32中用寄存器方式点亮流水灯

文章目录 实验资料一、对寄存器的理解1.通俗认识寄存器2.深入了解寄存器&#xff08;1&#xff09;端口配置低寄存器&#xff08;配置0到7引脚的寄存器&#xff09;&#xff08;2&#xff09;端口配置高寄存器&#xff08;配置8到15引脚&#xff09; 3.GPIO口的功能描述 二、配…

Git Bash和Git GUI设置中文的方法

0 前言 Git是一个分布式版本控制系统&#xff0c;可以有效、高速地处理从很小到非常大的项目版本管理。一般默认语言为英文&#xff0c;本文介绍修改Git Bash和Git GUI语言为中文的方法。 1 Git Bash设置中文方法 &#xff08;1&#xff09;鼠标右键&#xff0c;单击“Git B…

时间复杂度的简单讲解

小伙伴们大家好&#xff0c;我们又见面了&#xff0c;这次我们直接进入正题 时间复杂度的概念 时间复杂度的定义&#xff1a;在计算机科学中&#xff0c; 算法的时间复杂度是一个函数 &#xff0c;它定量描述了该算法的运行时间。一 个算法执行所耗费的时间&#xff0c;从理论…

公有云Linux模拟TCP三次挥手与四次握手(Wireshark抓包验证版)

目录 写在前面环境准备实验步骤1. 安装nc工具2. 使用nc打开一个连接2.1 公有云-安全组放行对应端口&#xff08;可选&#xff09; 3. 打开Wireshark抓包工具4. 新开终端&#xff0c;进行连接5. 查看抓包文件&#xff0c;验证TCP三次握手与四次挥手TCP三次握手数据传输TCP四次挥…

【C++杂货铺铺】AVL树

目录 &#x1f308;前言&#x1f308; &#x1f4c1; 概念 &#x1f4c1; 节点的定义 &#x1f4c1; 插入 &#x1f4c1; 旋转 1 . 新节点插入较高左子树的左侧---左左&#xff1a;右单旋 2. 新节点插入较高右子树的右侧---右右&#xff1a;左单旋 3. 新节点插入较高左…

57 读取/写出/读取 文件的过程的调试

前言 问题来自于文章 请教文件读写问题 请教文件读写问题 - 内核源码-Chinaunix vim 编辑文件, 实际上删除了原有的文件建立了一个新的文件? Ls –ail . 查看 inode 编号不一样了 这里主要是 调试一下 这一系列流程 测试用例 就是一个程序, 读取 1.txt 两次, 两次之间间隔…

49. UE5 RPG 使用Execution Calculations处理对目标造成的最终伤害

Execution Calculations是Unreal Engine中Gameplay Effects系统的一部分&#xff0c;用于在Gameplay Effect执行期间进行自定义的计算和逻辑操作。它允许开发者根据特定的游戏需求&#xff0c;灵活地处理和修改游戏中的属性&#xff08;Attributes&#xff09;。 功能强大且灵…

国内智能搜索工具实战教程

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

C++新特性-线程

主要内容 thread、condition、mutexatomicfunction、bind使用新特性实现线程池&#xff08;支持可变参数列表&#xff09;异常协程其他 1 C11多线程thread 重点&#xff1a; join和detach的使用场景thread构造函数参数绑定c函数绑定类函数线程封装基础类互斥锁mutexconditi…

网络基础-Telnet协议

Telnet&#xff08;Telecommunication Network&#xff09;是一种基于文本的远程终端协议&#xff0c;允许用户通过网络连接到远程计算机&#xff0c;并在远程计算机上执行命令&#xff1b;它使用TCP作为传输层协议&#xff0c;并依赖于网络连接在客户端和服务器之间进行通信&a…

FPGA SDRAM读写控制器

感谢邓堪文大佬 &#xff01; SDRAM 同步动态随机存取内存&#xff08;synchronousdynamic randon-access menory&#xff0c;简称SDRAM&#xff09;是有一个同步接口的动态随机存取内存&#xff08;DRAM&#xff09;。通常DRAM是有一个异步接口的&#xff0c;这样它可以随时响…

计算机毕业设计 | vue+springboot调查问卷管理系统(附源码)

1&#xff0c;研究目的 在进入21世纪以后&#xff0c;互联网得到了蓬勃的发展&#xff0c;电子问卷调查也开始逐渐流行起来。传统纸质问卷和电子问卷相比较后&#xff0c;传统问卷还存在很多弊端&#xff1a; 问卷分发起来比较困难&#xff0c;并且分发试卷耗费大量的金钱和时…

基于STC12C5A60S2系列1T 8051单片机实现一主单片机给多个从单片机发送数据的串口通信功能

基于STC12C5A60S2系列1T 8051单片机实现一主单片机给多个从单片机发送数据的串口通信功能 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机串口通信介绍STC12C5A60S2系列1T 8051单片机串口通信的结构基于STC12C5A60S2系列1T 8051单片机串口通信的特殊功能寄…

基于深度学习神经网络的AI图像PSD去雾系统源码

第一步&#xff1a;PSD介绍 以往的研究主要集中在具有合成模糊图像的训练模型上&#xff0c;当模型用于真实世界的模糊图像时&#xff0c;会导致性能下降。 为了解决上述问题&#xff0c;提高去雾的泛化性能&#xff0c;作者提出了一种Principled Synthetic-to-real Dehazing (…

STC8增强型单片机开发【LED呼吸灯(PWM)⭐⭐】

目录 一、引言 二、硬件准备 三、PWM技术概述 四、电路设计 五、代码编写 EAXSFR&#xff1a; 六、编译与下载 七、测试与调试 八、总结 一、引言 在嵌入式系统开发中&#xff0c;LED呼吸灯是一种常见的示例项目&#xff0c;它不仅能够展示PWM&#xff08;脉冲宽度调制…

2024 cleanmymac有没有必要买呢,全反面分析

在使用mac时&#xff0c;小编遇到了运行内存不足、硬盘空间不足的情况。遇到这种情况&#xff0c;我们可以借助经典的电脑深度清理软件——CleanMyMac X&#xff0c;清理不常用的软件和系统垃圾&#xff0c;非常好用&#xff01;不过&#xff0c;有许多网友发现CleanMyMac X有免…