C语言中的.c和.h及生成exe文件

新人的第一篇水文

目前只会一点点C,所以水的话也只能水水自己的一些经历和在学习的过程中个人觉得很重要的点吧,很多知识都是从前辈们那里学来的,得努力!

C程序代码编辑

作为初学者的我,只会在主程序 main.c 撰写代码然后调试执行,但看老师的代码压缩包,通常都包括
main.c、.c、.h 这三个文件,于是自己决定以后也要这样写C,下面给出我对这三个文件的理解:

main.c

程序执行的入口。系统执行程序的时候从此开始编译,期间调用一些系统函数库或者我们自己写的.h,可以在main.c敲完我们程序所需要的函数及语句。
main函数在c程序中的重要性:https://blog.csdn.net/gxyqn626/article/details/79252277?biz_id=102&utm_term=main.c%E7%9A%84%E4%BD%9C%E7%94%A8&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-0-79252277&spm=1018.2118.3001.4187

.h

自己的算法或函数或结构体的声明之处,作用是为.c 提供接口。在.h文件里,只需要作出声明,而不需要对其提供代码实现。这里给出了前辈(已注销)的理由:
1.从软件工程的角度,代码的实现不会写在头文件里面。因为它违背了隐蔽细节的原则,也就是我们需要暴露的是接口而不是细节。你不需要告述别人的代码是如何实现的,你只要提供接口就行啦。头文件就是c语言的接口。因为你想调用别人的接口只需要include别人的头文件,再连接或动态的调用别人的库就行啦。
2.从编译的角度,你如果写在头文件里面,改一次代码,和这个头文件有关的文件都要重新编译,这对大型项目来说非常耗时的。

.c

对函数的功能实现的代码区。与main.c不同的地方在于,我们只需在这里补充.h 里函数要实现所需的代码就可(即不需要“void main(){}”或“int main() {}”),其也可调用系统的库和.h文件。

动手开写

因为最近在学栈,所以就用链栈来做例子。
vs2019
建立空项目
取名
右击源文件
新建项
取名main.c
右击头文件
建立a.h
撰写main.c
撰写a.h
撰写b.c
生成exe文件

下面试链栈的相关代码:
main.c

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



void main()
{
	int  i;
	PNode stacklink;
	stacklink = Set_NullStackLink();
	for (i = 0; i < 5; i++)
	{
		Push_StackLink(stacklink);
	}
	while (Jug_NullStackLink(stacklink))
	{

		printf("%d", Top_StackLink(stacklink));
		Pop_StackLink(stacklink);
	}
	system("PAUSE");
}

a.h

#ifndef A_H
#define A_H
typedef int DataType;
struct  Node
{
	DataType data;
	struct  Node* next;
};
typedef struct Node* PNode;
typedef struct Node* LinkStack;

LinkStack  Set_NullStackLink();//创建空链栈
int Jug_NullStackLink(LinkStack top);//判断链栈是否为空,若空返回0;否则返回1
void Push_StackLink(LinkStack top);//进栈
void Pop_StackLink(LinkStack top);//出栈
DataType Top_StackLink(LinkStack top);//取栈顶元素,若空则打印“该链栈为空链栈!”
#endif 

b.c

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


LinkStack  Set_NullStackLink()//创建空链栈
{
	PNode head;
	head = (PNode)malloc(sizeof(struct Node));
	head->next = NULL;
	head->data = 9527;
	return (head);
}
int Jug_NullStackLink(LinkStack top)//判断链栈是否为空,若空返回0;否则返回1
{
	if (top->next)
		return 1;
	else
		return 0;
}
void Push_StackLink(LinkStack top)//进栈
{
	PNode p;
	p = (PNode)malloc(sizeof(struct Node));
	scanf_s("%d", &p->data);
	p->next = top->next;
	top->next = p;
}
void Pop_StackLink(LinkStack top)//出栈
{
	PNode p;
	p = top->next;
	top->next = p->next;
	free(p);
}
DataType Top_StackLink(LinkStack top)//取栈顶元素,若空则打印“该链栈为空链栈!”
{
	if (Jug_NullStackLink(top))
		return (top->next->data);
	else
	{
		printf("该链栈为空链栈!");
		return 9527;
	}


}

关于在写代码的过程中的知识点:
1.生成的exe文件再输入数据后执行完立即关闭窗口。与调试时期不同的是,exe文件在执行完毕后将直接关闭cmd窗口,因为现阶段我的代码对于计算机来说执行完毕是瞬间的。为了能够看到我的输出结果,我在main.c 末尾加上了语句:

system("PAUSE");

实际上这语句也可:

getchar();

方法来源:
https://blog.csdn.net/T1014216852/article/details/47749337?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160251414919724835836388%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=160251414919724835836388&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v3~pc_rank_v2-2-47749337.first_rank_ecpm_v3_pc_rank_v2&utm_term=c%E7%94%9F%E6%88%90%E7%9A%84exe%E6%96%87%E4%BB%B6%E6%89%A7%E8%A1%8C%E5%AE%8C%E8%87%AA%E5%8A%A8%E5%85%B3%E9%97%AD&spm=1018.2118.3001.4187

2关于“#ifndef 、#endif”、“#define ”

#ifndef 、#endif
它是if not define 的简写,是宏定义的一种,实际上确切的说,这应该是预处理功能三种(宏定义、文件包含、条件编译)中的一种----条件编译。
在c语言中,对同一个变量或者函数进行多次声明是不会报错的。所以如果h文件里只是进行了声明工作,即使不使用# ifndef宏定义,多个c文件包含同一个h文件也不会报错。
  但是在c++语言中,#ifdef的作用域只是在单个文件中。所以如果h文件里定义了全局变量,即使采用#ifdef宏定义,多个c文件包含同一个h文件还是会出现全局变量重定义的错误。
使用#ifndef可以避免下面这种错误:如果在h文件中定义了全局变量,一个c文件包含同一个h文件多次,如果不加#ifndef宏定义,会出现变量重复定义的错误;如果加了#ifndef,则不会出现这种错误。
#endif 是伴随着#ifndef一起使用的。
#define
在C或C++语言源程序中允许用一个标识符来表示一个字符串,称为“宏”。“define”为宏定义命令。
  被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。宏定义是由源程序中的宏定义命令完成的。宏代换是由预处理程序自动完成的。
优点:
    (1) 方便程序的修改。这个就不多说了。
    (2) 提高程序的运行效率。使用带参数的宏定义可完成函数调用的功能,又能减少系统开销,提高运行效率。正如C语言中所讲,函数的使用可以使程序更加模块化,便于组织,而且可重复利用,但在发生函数调用时,需要保留调用函数的现场,以便子函数执行结束后能返回继续执行,同样在子函数执行完后要恢复调用函数的现场,这都需要一定的时间,如果子函数执行的操作比较多,这种转换时间开销可以忽略,但如果子函数完成的功能比较少,甚至于只完成一点操作,如一个乘法语句的操作,则这部分转换开销就相对较大了,但使用带参数的宏定义就不会出现这个问 题,因为它是在预处理阶段即进行了宏展开,在执行时不需要转换,即在当地执行。宏定义可完成简单的操作,但复杂的操作还是要由函数调用来完成,而且宏定义所占用的目标代码空间相对较大。所以在使用时要依据具体情况来决定是否使用宏定义。
   
参考链接:https://www.cnblogs.com/challenger-vip/p/3386819.html

总结

     水平有限,肯定会有错误,还是希望您能够指正。实际上在写这篇文章的同时,让我清晰了不少以前的
     比较迷惑概念,也让我看到自己是有多菜。我还是得努力呀!
  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值