【C语言】关于我回头学的那些基础语法(一)
前言
我的第一门语言就是C,但是学艺不精,中途跑去学了C#和Java后,感觉到了C的重要性,毕竟是最接近底层的语言,又跑回来学C。
毕竟前两门的控制语句,变量什么的都是类似的,回到C后只需要学习一些特定C的语法,比如宏,预编译指令等等,这些对我来说都是陌生的词汇。
所以边学边记录一下陌生的知识。
文章目录
- 前言
- 一、两个.c文件如何相互调用
- 二、格式控制符
- 三、常量
- 四、枚举
- 五、控制语句
- 六、数组
- 1)声明数组
- 2)初始化数组
- 七、函数
- 1)自定义函数
- 1.自定义函数写法1(推荐)
- 2.自定义函数写法2
- 3.外部函数
- 2)API——sizeof()
- 八、存储类
- 1)静态存储类static
- 2)寄存器存储类register
- 3)外部存储类extern
一、两个.c文件如何相互调用
在C语言中,不同的.c
文件可以通过头文件(.h文件)
来进行相互访问。头文件中定义了不同.c文件间需要共享的函数声明、宏定义、结构体定义等内容。
通常,一个.c文件的内容包括函数定义和全局变量定义。对于需要在其他文件中使用的函数和变量,我们需要将其声明在对应的头文件中,并在其他.c文件中引用这个头文件。
举个例子,假设我们有两个.c文件 aa.c 和 bb.c 。如果 aa.c 中定义了一个函数 foo() ,并且 bb.c 需要调用这个函数,那么我们需要做以下几个步骤:
- 在 aa.h 头文件中声明 foo() 函数,例如:
void foo();
- 在 bb.c 中引用 aa.h 头文件:
#include "aa.h"
- 在 bb.c 中调用 foo() 函数即可:
foo();
需要注意的是,在编译时需要同时将 aa.c 和 bb.c 文件编译链接起来才能正常运行程序。一般情况下,我们会将所有的 .c 文件打包成静态库或动态库,在编译时链接相应的库即可。
注意事项:
- 头文件中只需包含函数声明而不是实际的代码实现。
- 确保使用正确的头文件名称和路径。
- 如果需要传递参数,则必须在两个 .c 文件中共享相同的参数类型和名称。
- 为了避免命名冲突,建议在头文件和变量名前加上前缀或者命名空间等标识符来区分不同模块或库中相同名称的变量和函数。
二、格式控制符
在 C 语言中,%d 是格式控制符,用于在 printf() 函数中输出有符号十进制整数。
比如:
int num = 100;
printf("The number is: %d", num);
上述代码中,%d 用于表示整数类型的变量 num 要输出为十进制格式。这里的字符串 "The number is: " 是格式字符串,将会被输出。
在 scanf() 函数中,%d 也被用来读取用户输入的整数,例如:
int num;
scanf("%d", &num);
在这个例子中,%d 表示要读取用户输入的一个整数,并将其存储到变量 num 中。
除了 %d,还有其他一些常用的格式控制符,比如:
- %d:用于打印整型。
- %f :用于打印浮点数。
- %c: 用于打印字符。
- %s :用于打印字符串。
- %p: 用于打印指针地址。
- %% :用于打印百分号本身。
三、常量
在 C 中,有两种简单的定义常量的方式:
- 使用
#define
预处理器。 - 使用
const
关键字。
#define LENGTH 10
const int LENGTH = 10;
一般把常量定义为大写字母形式。
四、枚举
枚举变量的定义,最后要记得加冒号。
前面我们只是声明了枚举类型,接下来我们看看如何定义枚举变量。
我们可以通过以下三种方式来定义枚举变量
1、先定义枚举类型,再定义枚举变量
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};
enum DAY day;
2、定义枚举类型的同时定义枚举变量
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
3、省略枚举名称,直接定义枚举变量
enum
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
五、控制语句
C语言中也有这样的语句,就是goto
语句,goto
语句是一种无条件分支语句,直接执行。
goto 语句的使用格式为:
goto 语句标号;
六、数组
1)声明数组
balance 是一个可用的数组,可以容纳 10 个类型为 double 的数字。
double balance[10];
其他的定义方式:
//代码1
int arr1[10];
char arr2[10];
float arr3[1];
double arr4[20];
//代码2,用宏定义
#define X 3
int arr5[X];
2)初始化数组
double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};
如果您省略掉了数组的大小,数组的大小则为初始化时元素的个数。
double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};
七、函数
1)自定义函数
返回值类型 函数名 (参数列表) { 函数体 }
1.自定义函数写法1(推荐)
#include <stdio.h>
int plus(int x,int y); //此处有分号,表示函数的声明
int main()
{
int a,b,c;
a=1;
b=2;
c=plus(a,b); //函数的调用
printf("%d",c);
return 0;
}
int plus(int x,int y) //此处无分号,表示函数的定义
{
int result;
result=x+y;
return result;
}
2.自定义函数写法2
#include <stdio.h>
int plus(int x,int y); //此处无分号
{
int result;
result=x+y;
return result;
}
int main()
{
int a,b,c;
a=1;
b=2;
c=plus(a,b); //函数的调用
printf("%d",c);
return 0;
}
3.外部函数
在C语言中,外部函数指的是定义在当前编译单元外部的函数。这些函数通常声明在头文件中,并在一个或多个源文件中进行定义。
外部函数可以是库函数或用户自定义函数。库函数通常由操作系统或第三方库提供,可以被程序员直接调用使用。用户自定义函数则是由程序员自己编写并在程序中使用的函数。
当我们需要使用一个外部函数时,必须在代码中包含该函数所在的头文件,并进行相应的链接,以便让连接器找到并正确处理该外部函数。
以下为定义和使用外部函数的示例:
- 定义头文件
// func.h
#ifndef _FUNC_H_
#define _FUNC_H_
int add(int a, int b);
#endif
#ifndef
和 #define
是C语言预处理器指令,用于条件编译。
#ifndef _FUNC_H_
表示如果 _FUNC_H_
宏还没有被定义过(即这是第一次包含该头文件),则执行下面的代码块。如果已经被定义过,则跳过代码块。
#define _FUNC_H_
则用于定义 _FUNC_H_
宏,确保它在当前文件中只被定义一次。这个宏可以在其他文件中被引用和检查。
综合起来,这两行指令的作用是:当第一次引入头文件时,定义一个标记宏 _FUNC_H_
,以避免重复引入同一个头文件。当再次引入时,由于宏已经被定义,头文件内部的代码块将不会被重复执行。
- 定义源文件
// func.c
#include "func.h"
int add(int a, int b) {
return a + b;
}
- 在主程序中使用
// main.c
#include <stdio.h>
#include "func.h"
int main() {
int result = add(1, 2);
printf("The result is: %d
", result);
return 0;
}
通过以上代码,我们在 func.h
文件中声明了一个 add
函数,在 func.c
文件中进行了实现。当我们需要使用 add
函数时,在主程序中引入 func.h
头文件并调用该函数即可。
需要注意的是,在编译时我们需要将 main.c
和 func.c
进行链接,以便让编译器找到 add
函数的定义。这可以通过以下命令进行编译:
gcc main.c func.c -o main
以上是关于C语言中外部函数的简要介绍,希望对您有所帮助。
2)API——sizeof()
在c语言中,sizeof
是一个操作符,用于计算数据类型或变量的大小(即占用的存储空间)。它可以用于任何数据类型,包括基本数据类型(如int、float、double等)和复合数据类型(如结构体、数组等)。使用sizeof
可以帮助程序员确定变量或数据类型在内存中占用的空间大小,从而更好地管理内存和优化程序性能。
举例:
int length = sizeof(arr)/sizeof(arr[0]);
这条语句的作用是计算一个数组arr的长度。其中,sizeof(arr)表示arr数组所占用的内存空间的大小,sizeof(arr[0])表示arr数组中第一个元素所占用的内存空间的大小。因为数组中所有元素的类型和大小都相同,所以arr数组中所有元素所占用的内存空间大小都相同,可以用第一个元素来代表整个数组的大小。最终,通过将arr数组所占用的内存空间大小除以第一个元素所占用的内存空间大小,就可以得到arr数组中元素的个数,即数组的长度。
八、存储类
- 寄存器的(register)
- 外部的(extern)
1)静态存储类static
static
存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static
修饰局部变量可以在函数调用之间保持局部变量的值。
static
修饰符也可以应用于全局变量。当 static
修饰全局变量时,会使变量的作用域限制在声明它的文件内。
全局声明的一个static
变量或方法可以被任何函数或方法调用,只要这些方法出现在跟 static
变量或方法同一个文件中。
2)寄存器存储类register
C语言允许将局部自动变量和形式参数的值放在CPU中的寄存器中,这种变量叫“寄存器变量”,用关键字register作声明。
在需要频繁访问的变量上使用 register 存储类可以提高程序的运行速度,寄存器只用于需要快速访问的变量,比如计数器。还应注意的是,定义 register
并不意味着变量将被存储在寄存器中,它意味着变量可能存储在寄存器中,这取决于硬件和实现的限制。
一个计算机系统中的寄存器数目有限,不能定义任意多个寄存器变量,且局部静态变量不能定义为寄存器变量。
register int a;
3)外部存储类extern
用extern
声明的的变量是外部变量,只声明而不定义。
如果需要在一个源文件中引用另外一个源文件中定义的变量,我们只需在引用的文件中将变量加上 extern
关键字的声明即可。
extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当您使用 extern 时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。
当您有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用 extern 来得到已定义的变量或函数的引用。可以这么理解,extern 是用来在另一个文件中声明一个全局变量或函数。
extern 修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候。
1、一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间。
2、另一种是不需要建立存储空间的,通过使用extern关键字声明变量名而不定义它。 例如:extern int a 其中变量 a 可以在别的文件中定义的。
除非有extern关键字,否则都是变量的定义。
extern int i; //声明,不是定义(表明变量i是在其他文件中定义的)
int i; //声明,也是定义