20240325,结构嵌套,联合,全局变量,编译预处理和宏,声明

二,结构 

2.3 结构中的结构
2.3.1 结构数组
#include<stdio.h>//下一秒 
struct time{
	int hour;
	int min;
	int sed;
};
struct time timeupdate(struct time now);
int main(){
	struct time testTime[5]={
		{11,59,59},{12,0,0},{1,29,59},{23,59,59},{19,12,27} 
	};//结构数组
	int i;
	for(i=0;i<5;i++){
		printf("Time is %.2i:%.2i:%.2i\n",
		testTime[i].hour,testTime[i].min,testTime[i].sed);
		testTime[i]=timeupdate(testTime[i]);//函数运算 ,赋值 
		printf("...one second later is %.2i:%.2i:%.2i\n",
		testTime[i].hour,testTime[i].min,testTime[i].sed);
	}
	return 0;
}
struct time timeupdate(struct time now){
	++now.sed;
	if(now.sed==60){
		now.min++;
		now.sed=0;//秒的特殊情况 
		if(now.min==60){
			now.min=0;
			now.hour++;//分的 
		}if(now.hour==24){
			now.hour=0;//小时的 
		}
	}
	return now; //NOW就可以了 
}
2.3.2 结构中的结构【嵌套】
#include<stdio.h>
struct point{
	int x;
	int y;
}; 
struct rectangle{
	struct point pt1;
	struct point pt2;
};
int main(){
	struct rectangle r;
	scanf("%d %d %d %d",&r.pt1.x,&r.pt1.y,&r.pt2.x,&r.pt2.y);
	printf("%d-%d-%d-%d\n",r.pt1.x,r.pt1.y,r.pt2.x,r.pt2.y);
	return 0;
}

注:指针不能嵌套 

#include<stdio.h>
struct point{
	int x;
	int y;
}; 
struct rectangle{
	struct point pt1;
	struct point pt2;
};
int main(){
	struct rectangle *rp;
	struct rectangle r={
		{2,3},{4,5},
	};//初始化
	rp=&r;
	printf("%d-%d-%d-%d\n",r.pt1.x,r.pt1.y,r.pt2.x,r.pt2.y);
	printf("%p\n",&r);
	printf("%p\n",rp);
	printf("%d\n",r.pt1.x);
	printf("%d\n",rp->pt1.x);// 。 先算,指针指向PT1.X
	printf("%d\n",(r.pt1).x);
	printf("%d\n",(rp->pt1).x);
	//meiyou rp->pt1->x,yinwwei (rp->pt1)不是指针 
	return 0;
}
2.3.3 结构中的结构的数组

 地址和SIZE之间的关系,居然!!!!!&da,和da输出的地址不一样,只要加上&都一样

#include<stdio.h>
struct point{
	int x;
	int y;
}; 
struct rectangle{
	struct point pt1;
	struct point pt2;
};
void print(struct rectangle da);
void size(struct rectangle da);
void di(struct rectangle da);
int main(){
	struct rectangle rr[2]={
		{{0,1},{2,3}},{{3,4},{5,6}}
	}; 
	int i;
	for(i=0;i<2;i++){
		print(rr[i]);
		size(rr[i]);
		di(rr[i]);
	}
	return 0;
}
void print(struct rectangle da){
	printf("<%d-%d>-<%d-%d>\n",
	da.pt1.x,da.pt1.y,da.pt2.x,da.pt2.y);
}
void size(struct rectangle da){
	printf("%d\n",sizeof(da));
	printf("%d\n",sizeof(da.pt1));
	printf("%d\n",sizeof(da.pt1.x));
}
void di(struct rectangle da){
	printf("%p\n",da);
	printf("%p\n",&da);
	printf("%p\n",&da.pt1);
	printf("%p\n",&(da.pt1.x));
}

三,联合

3.1 类型定义 TYPEDEF

信的名字是某种类型的 别名,改善了程序的可读性
最后一个单词就是新名字

#include<stdio.h>
typedef int Lenght;
typedef struct adata{
	int mouth;
	int day;
	int year;
}Data;
int main(){
	Lenght i=8;
	printf("%d\n",i);
	Lenght a[9]={4};
	printf("%d\n",a[8]);
	Data t={10,3,2012};//DATA T==STRUCT ADATA T
	printf("%d\n",t.year);
	struct adata tt={0,0,0};
	printf("%d\n",tt.year);
	return 0;
}
3.2 联合UNION
#include<stdio.h>
typedef union {
	int i;
	char ch[sizeof(int)];//4个字节可以被看作是i,也可以被看作CHAR【4】 
}CHI;
int main(int argc,char const *argv[]){
	CHI chi;
	int i;
	chi,i=1234;//I=1234=04d2 
	for(i=0;i<sizeof(int);i++){
		printf("%02hhX",chi.ch[i]);//很多修饰符
	}//……我的只能输出一串0 
	printf("\n");
	return 0;
}

可以用来得到INT DOUBLE的内部字节,什么低位在前
感觉没懂
存储
所有的成员共享一个空间;同一时间只有一个成员是有效的;union的大小是其最大的成员
初始化
对第一个成员做初始化

程序结构

一,全局变量

1.1 全局变量

定义在函数外面的变量是全局变量
全局变量具有全局的生存期和作用域
它们与任何函数都无关
在任何函数内部都可以使用它们,在任何函数访问都是对全局变量的访问

#include<stdio.h>
int f(void);
int gALL=12;
int main(int argc,char const *argv[]){
	printf("in %s gALL=%d\n",__func__,gALL);
	//__func__表示当前这个函数的名字 
	f();
	printf("agn in %s gALL=%d\n",__func__,gALL);
	return 0;
} 
int f(void){
	printf("in %s gALL=%d\n",__func__,gALL);
	gALL+=2;
	printf("agn in %s gALL=%d\n",__func__,gALL);
	return gALL;
}

没有做初始化的全局变量会得到0值
指针会得到NULL值
只能用编译时刻已知的值来初始化全局变量
它们的初始化发生在main函数之前 

#include<stdio.h>
int f(void);
int gALL;
//X --int gALL=f()
//可以但是不建议
//const int g2=12;
//int gALL=g2; 
int main(int argc,char const *argv[]){
	printf("in %s gALL=%d\n",__func__,gALL);
	//__func__表示当前这个函数的名字 
	f();
	printf("agn in %s gALL=%d\n",__func__,gALL);
	return 0;
} 
int f(void){
	printf("in %s gALL=%d\n",__func__,gALL);
	gALL+=2;
	printf("agn in %s gALL=%d\n",__func__,gALL);
	return gALL;
}

如果函数内部存在与全局变量同名的变量,则全局变量被隐藏

#include<stdio.h>
int f(void);
int gALL;
int main(int argc,char const *argv[]){
	printf("in %s gALL=%d\n",__func__,gALL);
	//__func__表示当前这个函数的名字 
	f();
	printf("agn in %s gALL=%d\n",__func__,gALL);
	return 0;
} 
int f(void){
	int gALL=12;
	printf("in %s gALL=%d\n",__func__,gALL);
	gALL+=2;
	printf("agn in %s gALL=%d\n",__func__,gALL);
	return gALL;
}
1.2 静态本地变量 STATIC

在本地变量定义时加上static修饰符就成为静态本地变量
当函数离开的时候,静态本地变量会继续存在并保持其值
静态本地变量的初始化只会在第一次进入这个函数时做,以后进入函数时会保持上次离开时的值

#include<stdio.h>
int f(void);
int gALL=12;
int main(int argc,char const *argv[]){
	f();
	f();
	f();
	return 0;
} 
int f(void){
	int all=1;
	static int tll=1;
	printf("in %s gALL=%d\n",__func__,gALL);
	printf("in %s all=%d\n",__func__,all);
	printf("in %s tll=%d\n",__func__,tll);
	gALL+=2;
	all+=2;
	tll+=2;
	printf("agn in %s gALL=%d\n",__func__,gALL);
	printf("in %s all=%d\n",__func__,all);
	printf("in %s tll=%d\n",__func__,tll);
	printf("\n");
	return gALL;
}

静态本地变量实际上是特殊的全局变量
它们位于相同的内存区域
静态本地变量具有全局的生存期,函数内的局部作用域
static在这里的意思是局部作用域(本地可访问) 

#include<stdio.h>
int f(void);
int gALL=12;
int main(int argc,char const *argv[]){
	f();
	return 0;
} 
int f(void){
	int all=1;
	static int tll=1;
	printf("&gALL=%xp\n",&gALL);
	printf("&tll=%xp\n",&tll);
	printf("&all=%xp\n",&all);
	return gALL;
}
1.3 返回指针的函数

返回本地变量的地址是危险的
返回全局变量或静态本地变量的地址是安全的
返回在函数内malloc的内存是安全的,但是容易造成问题
最好的做法是返回传入的指针

#include<stdio.h>
int* f(void);
void g(void);
int main(int argc,char const *argv[]){
	int *p=f();
	printf("*p=%d\n",*p);
	g();
	printf("*p=%d\n",*p);
	return 0;
} 
int* f(void){
	int i=12;
	printf("&i=%p\n",&i);
	return &i;
}//woring address of variable"i" returned
void g(void){
	int k=24;
	printf("k=%d\n",k);
	printf("&k=%p\n",&k);
}

I的地址,在出了函数F之后,进入函数G,又分配给了G使用

不要使用全局变量来在函数间传递参数和结果尽量避免使用全局变量
丰田汽车的案子
使用全局变量和静态本地变量的函数是线程不安全的 

二,编译预处理和宏

2.1 宏定义

#开头的是编译预处理指令
它们不是C语言的成分,但是C语言程序离不开它们
#define用来定义一个宏

#include<stdio.h>
const double PI=3.14159;
#define PI1 3.14159//没有等号,没有分号 
int main(int argc,char const *argv[]){
	printf("%f\n",2*PI*3.0);
	printf("%f\n",2*PI1*3.0);
	return 0;
} 

--save--temps【GCC】
.C源文件——》.I中间结果文件——》.S汇编代码文件——》.O目标代码文件——》.OUT

#include<stdio.h>
const double PI=3.14159;
#define PI1 3.14159//没有等号,没有分号 
#define FORMAT "%f\n"
int main(int argc,char const *argv[]){
	printf("%f\n",2*PI*3.0);
	printf("%f\n",2*PI1*3.0);
	printf(FORMAT,2*PI1*3.0);
	printf("FORMAT\n",2*PI1*3.0);
	return 0;
} 

·#define<名字><值>
注意没有结尾的分号,因为不是C的语句名字必须是一个单词,值可以是各种东西
在C语言的编译器开始编译之前,编译预处理程序(cpp)会把程序中的名字换成值
·完全的文本替换 

#include<stdio.h>
#define PI 3.14159
#define PI2 2*PI//不能带空格,纯文本替换 
#define PI3 printf("%f\n",PI);\
			printf("%f\n",PI2)
			
int main(int argc,char const *argv[]){
	printf("%f\n",2*PI*3.0);
	printf("%f\n",2*PI2*3.0);
	PI3;
	return 0;
} 
2.1.1 没有值的宏 

#define DEBUG
这类宏是用于条件编译的,后面有其他的编译预处理指令来检查这个宏是否已经被定义过了

2.1.2 预定义的宏
//__LINE__当前源代码文件的行号
//__FILE__源代码文件的文件名
//__DATE__,__TIME__当前源代码创建日期,时间
//__STDC__ ,当编译器以 ANSI 标准编译时,则定义为 1;判断该文件是不是标准 C 程序。
#include<stdio.h>
int main(int argc,char const *argv[]){
	
	printf("文件名%s:行号%d\n",__FILE__,__LINE__);
	printf("日期%s,时间%s\n",__DATE__,__TIME__); 
	return 0;
} 
2.2 带参数的宏

原则:一切都要括号
整个值要括号
参数出现的每个地方都要括号

#include<stdio.h>
#define cube(x) ((x)*(x)*(x)) 
#define dada(x) (x)*50.343
#define dada2(x) x*50.343
int main(int argc,char const *argv[]){
	int i;
	scanf("%d",&i);
	printf("%d\n",cube(i));
	printf("%d\n",cube(i+2));
	printf("%f\n",dada(i+2)); 
	printf("%f\n",dada2(i+2));
	
	printf("%f\n",180/dada(2+1));// 180/(2+1)*50.343
	printf("%f\n",dada2(5+2));// 5+2*50.343
	return 0;
} 

带多个参数,也可以组合(嵌套)其他宏

#include<stdio.h>
#define MIN(a,b) ((a)>(b)?(b):(a)) 
int main(int argc,char const *argv[]){
	int a=5,b=10;
	printf("%d\n",MIN(a,b));//a>b?b:a不懂 
	return 0;
} 
//表达式1 ? 表达式2 :表达式3
如果 1 为真,则2,否则3
三目运算符?

千万不要加分号哦!#不是C?啥,用空间换取效率
在大型程序的代码中使用非常普遍 ,可以非常复杂,如“产生”函数--在#和##这两个运算符的帮助下,存在中西方文化差异
什么涉及到多个参数类型没人检查?
部分宏会被inline函数替代 

其他编译预处理指令,条件编译,REEOR……看不懂,先放着,丢

三,大数据结构

3.1 多个源代码文件

 单个.C文件拆成多个.C文件……建项目,CEV C++允许不建项目只建一个文件
一个.c文件是一个编译单元
编译器每次编译只处理一个编译单元

#include<stdio.h>
int max(int a,int b) ;
int main(){
	int a=7;
	int b=8;
	printf("%d\n",max(a,b));
	return 0;
} 
int max(int a,int b){
	return a>b?a:b;
}
3.2 头文件
#include<stdio.h>
int main(){
	int a=7;
	int b=8;
	printf("%d\n",max(a,b));
	return 0;
} 
double max(double a,double b){
	return a>b?a:b;
}

出错,假笑

把函数原型放到一个头文件(以.h结尾)中,在需要调用这个函数的源代码文件(.c文件)中#include这个头文件,就能让编译器在编译的时候知道函数的原型

#include<stdio.h>
#include "max.h" //要和文件名一样哦 
int main(){
	int a=7;
	int b=8;
	printf("%f\n",max(a,b));
	return 0;
} 
#include "max.h" 
double max(double a,double b){
	return a>b?a:b;
}
double max(double a,double b);

 #include是一个编译预处理指令,和宏一样,在编译之前就处理了
它把那个文件的全部文本内容原封不动地插入到它所在的地方
所以也不是一定要在.c文件的最前面#include

#include有两种形式来指出要插入的文件
“”要求编译器首先在当前目录(.c文件所在的目录)寻找这个文件,如果没有,到编译器指定的目录去找
<>让编译器只在指定的目录去找
编译器自己知道自己的标准库的头文件在哪里环境变量和编译器命令行参数也可以指定寻找头文件的目录

#include不是用来引入库的
stdio.h里只有printf的原型,printf的代码在另外的地方,某个.lib(Windows)或.a(Unix)中
现在的C语言编译器默认会引入所有的标准库
#include <stdio.h>只是为了让编译器知道printf函数的原型,保证你调用时给出的参数值是正确的类型

声明——在使用和定义这个函数的地方都应该#include这个头文件
一般的做法就是任何.c都有对应的同名的.h,把所有对外公开的函数的原型和全局变量的声明都放进去

不对外公开的函数——在函数前面加上static就使得它成为只能在所在的编译单元中被使用的函数
在全局变量前面加上static就使得它成为只能在所在的编译单元中被使用的全局变量

3.3 声明
#include<stdio.h>
#include "max.h" //要和文件名一样哦 
int main(){
	int a=7;
	printf("%d\n",max(a,g));
	return 0;
} 

#include "max.h" 
int g=12; //定义 
int max(int a,int b){
	return a>b?a:b;
}

int max(int a,int b);
extern int g; //声明,不能初始化 

声明是不产生代码的东西;函数原型,变量声明,结构声明,宏声明,枚举声明,类型声明,inline函数
定义是产生代码的东西;函数,全局变量

只有声明可以被放在头文件中
是规则不是法律
否则会造成一个项目中多个编译单元里有重名的实体*某些编译器允许几个编译单元中存在同名的函数,或者用weak修饰符来强调这种存在

同一个编译单元里,同名的结构不能被重复声明
如果你的头文件里有结构的声明,很难这个头文件不会在一个编译单元里被#include多次
所以需要标准头文件结构

#ifndef _MAX_H_
#define _MAX_H_
//如果没有定义过
//那么定义 

int max(int a,int b);
extern int g; 

#endif

暴躁这个头文件在一个编译单元中只会#INCLUDE一次
#pragmaonce也能起到相同的作用,但是不是所有的编译器都支持

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

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

相关文章

数据结构 之 队列习题 力扣oj(附加思路版)

优先级队列 #include<queue> --队列 和 优先级队列的头文件 优先级队列&#xff1a; 堆结构 最大堆 和 最小堆 相关函数&#xff1a; front() 获取第一个元素 back() 获取最后一个元素 push() 放入元素 pop() 弹出第一个元素 size() 计算队列中元素…

Maven学习记录

一、简介 1. Maven&#xff1a; 基于 Java 平台的项目管理和整合工具&#xff0c;将项目的开发和管理过程抽象成一个项目对象模型&#xff08;POM&#xff09;。开发人员只需要做一些简单的配置&#xff0c;Maven 就可以自动完成项目的编译、测试、打包、发布以及部署等工作。…

把学浪视频保存到电脑方法

为了可以更好的学习很多用户都会想要将学浪的视频下载下来,但是学浪视频官方却没有提供下载方法,为了将学浪视频下载下来我研究了一段时间,总算有突破,找到了下载方法 文章中所用到的工具就在下面,有需要的自己取一下 链接&#xff1a;https://pan.baidu.com/s/1y7vcqILToULr…

go的for循环应该这么用

目录 目录 一&#xff1a;介绍 1: for流程控制 2&#xff1a;for-range流程控制 二&#xff1a;实例展示 1&#xff1a;//按照一定次数循环 2&#xff1a;//无限循环 3: //循环遍历整数、各种容器和通道 4&#xff1a;遍历通道 5&#xff1a;//指针数组循环 6&…

git笔记之撤销、回退、reset方面的笔记

git笔记之撤销、回退、reset方面的笔记 code review! 文章目录 git笔记之撤销、回退、reset方面的笔记1.git 已经commit了&#xff0c;还没push&#xff0c;如何撤销到初始状态git reset --soft HEAD~1git reset HEAD~1&#xff08;等同于 git reset --mixed HEAD~1&#xff0…

机器学习OpenNLP

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl OpenNLP概述 OpenNLP是一个基于机器学习的自然语言处理开发工具包&#xff0c;它是Apache软件基金会的一个开源项目。OpenNLP支持多种自然语言处理任务&#xff0c;如分词、…

计算机网络:现代通信的基石

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

如何忽略Chrome最小字号的限制

通过控制台调整字体大小时&#xff0c;可以发现即便设置了小于12px的字号&#xff0c;也并不会变小&#xff0c;这是因为Chrome默认最小字号为12px。 在Chrome设置中的外观选项卡中可以发现&#xff0c;默认字体是16px。将最小字号改为0&#xff0c;就能随意设置小于12px的字号…

面向对象【枚举类】

文章目录 枚举类定义枚举类enum 方式定义的要求和特点 enum 中常用方法实现接口的枚举类 枚举类 枚举类是一种特殊的类&#xff0c;它用于定义一组固定数量的常量。枚举类在实际开发中非常有用&#xff0c;因为它们可以增加代码的可读性和可维护性。本文将介绍Java枚举类的定义…

[网鼎杯2018]Unfinish 两种方法 -----不会编程的崽

网鼎杯太喜欢搞二次注入了吧。上次是无列名盲注&#xff0c;这次又是二次注入盲注。。。不知道方法还是挺难的。哎&#xff0c;网鼎嘛&#xff0c;能理解透彻就很强了。能自己做出来那可太nb了。 又是熟悉的登录框。不知道这是第几次看见网鼎杯的登录框了。后台扫描一下&#x…

基于深度学习的海洋鱼类识别算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ............................................................ % 对测试集进行分类预测 [Pr…

西安石油大学校赛培训(1)数学模型简介 初等模型

数学建模竞赛 什么是数学建模竞赛?数学竞赛给人的印象是高深莫测的数学难题,和一个人、一支笔、一张纸&#xff0c;关在屋子里的冥思苦想&#xff0c;它训练严密的逻辑推理和准确的计算能力&#xff0c;而数学建模竞赛从内容到形式与此都有明显的不同。 数学建模竞赛的题目由日…

高防服务器、高防IP、高防CDN的工作原理是什么

高防IP高防CDN我们先科普一下是什么是高防。“高防”&#xff0c;顾名思义&#xff0c;就犹如网络上加了类似像盾牌一样很高的防御&#xff0c;主要是指IDC领域的IDC机房或者线路有防御DDOS能力。 高防服务器主要是比普通服务器多了防御服务&#xff0c;一般都是在机房出口架设…

学点儿Java_Day10_集合框架(List、Set、HashMap)

1 简介 ArrayList: 有序(放进去顺序和拿出来顺序一致)&#xff0c;可重复 HashSet: 无序(放进去顺序和拿出来顺序不一定一致)&#xff0c;不可重复 Testpublic void test1() {String[] array new String[3];//List: 有序 可重复//有序: 放入顺序 与 拿出顺序一致&#xff0c;…

Github多账号共存

在开发阶段&#xff0c;如果同时拥有多个开源代码托管平台的账户&#xff0c;在代码的管理上非常麻烦。那么&#xff0c;如果同一台机器上需要配置多个账户&#xff0c;怎样才能确保不冲突&#xff0c;不同账户独立下载独立提交呢&#xff1f; 我们以两个github账号进行演示 …

基于STM32的最小系统电路设计(手把手零基础教学)

文章目录 前言一、复位电路二、晶振电路三、电源转换电路四、SWD下载电路五、LED测试电路六、芯片外扩引脚七、STM32微控制电路总结 前言 在上篇介绍完《STM32的核心板制作流程》后&#xff0c;本篇我们将开始学习STM32最小系统电路的设计。具体包括复位电路、晶振电路、电源转…

快速入门go语言

环境搭建 编译器安装 1、编译器下载地址 2、打开命令行模式&#xff0c;输入go version ide安装 ide下载地址 依赖管理 goproxy 1、goproxy代理地址 // 阿里云 https://mirrors.aliyun.com/goproxy // 微软 https://goproxy.io // 七牛 https://goproxy.cn 2、ide配置g…

io的学习4

打印流 分类&#xff1a;打印流一般是指&#xff1a;PrintStream、PrintWriter两个类 特点&#xff1a; 1.打印流只操作文件目的地&#xff0c;不操作数据源 2.特有的写出方法可以实现&#xff0c;数据原样写出 3.特有的写出方法&#xff0c;可以实现自动刷新&#xff0c;…

openGauss + Datakit搭建openGauss运维平台

系统架构OS 硬件需求&#xff1a;2c4g [rootlocalhost ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) [rootlocalhost ~]# uname -m x86_64 [rootlocalhost ~]# hostname -I 192.168.92.32 下载地址&#xff1a;https://opengauss.org/zh/download/ 下载…

软考高级架构师:MVP 架构概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…