强制类型转换是把变量从一种类型转换为另一种数据类型。

实例:

使用强制类型转换运算符把一个整数变量除以另一个整数变量,得到一个浮点数:

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

int main()
{
int sum = 17, count = 5;
double mean;

mean = (double) sum / count;
printf("Value of mean : %f\n", mean );
}
阅读全文 »

头文件是扩展名为 .h 的文件,包含了 C 函数声明和宏定义,被多个源文件中引用共享。
有两种类型的头文件:程序员编写的头文件和编译器自带的头文件。

在程序中要使用头文件,需要使用 C 预处理指令 #include 来引用它。前面我们已经看过 stdio.h 头文件,它是编译器自带的头文件。

A simple practice in CC++ 程序中,建议把所有的常量、宏、系统全局变量和函数原型写在头文件中,在需要的时候随时引用这些头文件。

阅读全文 »

C 预处理器不是编译器的组成部分,但是它是编译过程中一个单独的步骤。简言之,C 预处理器只不过是一个文本替换工具而已,它们会指示编译器在实际编译之前完成所需的预处理。我们将把 C 预处理器(C Preprocessor)简写为 CPP

所有的预处理器命令都是以 # 开头。它必须是第一个非空字符,为了增强可读性,预处理器指令应从第一列开始。

下面列出了所有重要的预处理器指令:

指令 描述
#define 定义宏
#include 包含一个源代码文件
#undef 取消已定义的宏
#ifdef 如果宏已经定义,则返回真
#ifndef 如果宏没有定义,则返回真
#if 如果给定条件为真,则编译下面代码
#else #if 的替代方案
#elif 如果前面的 #if 给定条件不为真,当前条件为真,则编译下面代码
#endif 结束一个 #if……#else 条件编译块
#error 当遇到标准错误时,输出错误消息
#pragma 使用标准化方法,向编译器发布特殊的命令到编译器中
阅读全文 »

打开文件

可以使用 fopen() 函数来创建一个新的文件或者打开一个已有的文件。

1
FILE *fopen( const char * filename, const char * mode );

filename 是字符串,用来命名文件;访问模式 mode 的值可以是下列值中的一个:

模式 描述
r 打开一个已有的文本文件,允许读取文件。
w 打开一个文本文件,允许写入文件。如果文件不存在,则会创建一个新文件。在这里,程序会从文件的开头写入内容。如果文件存在,则该会被截断为零长度,重新写入。
a 打开一个文本文件,以追加模式写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会在已有的文件内容中追加内容。
r+ 打开一个文本文件,允许读写文件。
w+ 打开一个文本文件,允许读写文件。如果文件已存在,则文件会被截断为零长度,如果文件不存在,则会创建一个新文件。
a+ 打开一个文本文件,允许读写文件。如果文件不存在,则会创建一个新文件。读取会从文件的开头开始,写入则只能是追加模式。
阅读全文 »

标准文件

C 语言把所有的设备都当作文件。所以设备(比如显示器)被处理的方式与文件相同。以下三个文件会在程序执行时自动打开,以便访问键盘和屏幕。

标准文件 文件指针 设备
标准输入 stdin 键盘
标准输出 stdout 屏幕
标准错误 stderr 屏幕
阅读全文 »

C 语言提供了 typedef 关键字,可以使用它来为类型取一个新的名字。下面的实例为单字节数字定义了一个术语 BYTE

1
typedef unsigned char BYTE;

在这个类型定义之后,标识符 BYTE 可作为类型 unsigned char 的缩写,例如:

1
BYTE  b1, b2;

按照惯例,定义时会大写字母,以便提醒用户类型名称是一个象征性的缩写,但您也可以使用小写字母,如下:

1
typedef unsigned char byte;
阅读全文 »

如果程序的结构中包含多个开关量,只有 TRUE/FALSE 变量,如下:

1
2
3
4
5
struct
{
unsigned int widthValidated;
unsigned int heightValidated;
} status;

这种结构需要 8 字节的内存空间,但在实际上,在每个变量中,只存储 0 或 1。

在这种情况下,C 语言提供了一种更好的利用内存空间的方式。如果在结构内使用这样的变量,可以定义变量的宽度来告诉编译器,将只使用这些字节。例如,上面的结构可以重写成:

1
2
3
4
5
struct
{
unsigned int widthValidated : 1;
unsigned int heightValidated : 1;
} status;
阅读全文 »

共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式。

定义共用体

为了定义共用体,您必须使用 union 语句,方式与定义结构类似。union 语句定义了一个新的数据类型,带有多个成员。union 语句的格式如下:

1
2
3
4
5
6
7
union [union tag]
{
member definition;
member definition;
...
member definition;
} [one or more union variables];

union tag 是可选的,每个 member definition 是标准的变量定义,比如 int i; 或者 float f; 或者其他有效的变量定义。在共用体定义的末尾,最后一个分号之前,您可以指定一个或多个共用体变量,这是可选的。下面定义一个名为 Data 的共用体类型,有三个成员 i、f 和 str

1
2
3
4
5
6
union Data
{
int i;
float f;
char str[20];
} data;
阅读全文 »

结构体用于存储不同类型的数据项。

定义结构

必须使用 struct 语句。struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下:

1
2
3
4
5
6
struct tag { 
member-list
member-list
member-list
...
} variable-list ;

tag 是结构体标签。
member-list 是标准的变量定义,比如 int i; 或者 float f,或者其他有效的变量定义。
variable-list 结构变量,定义在结构的末尾,最后一个分号之前,您可以指定一个或多个结构变量。下面是声明 Book 结构的方式:

1
2
3
4
5
6
7
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} book;

在一般情况下,tagmember-listvariable-list 这 3 部分至少要出现 2 个。

阅读全文 »

C 字符串

在 C 语言中,字符串实际上是使用 null 字符 \0 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。

C 编译器会在初始化数组时,自动把 \0 放在字符串的末尾。

'a' 表示是一个字符,"a" 表示一个字符串相当于 'a'+'\0';
'' 里面只能放一个字符;
"" 里面表示是字符串系统自动会在串末尾补一个 0

阅读全文 »

函数指针

函数指针是指向函数的指针变量。

函数指针可以像一般函数一样,用于调用函数、传递参数。

函数指针变量的声明:

1
typedef int (*fun_ptr)(int,int); //声明一个指向同样参数、返回值的函数指针类型
阅读全文 »

一,常见指针

& 是取地址运算符,* 是间接运算符。

1,int p;

整型变量,32位CPU的话,占有32个bite。

2,int *p;

整型指针变量,用于存放一个整型变量的地址。

解析:

从 p 处开始,先与 * 结合,所以说明 p 是一个指针, 然后再与 int 结合, 说明指针所指向的内容的类型为 int 型。

3,int p[3];

整型数据组成的数组。

解析:

首先从 p 处开始,先与 [] 结合,说明 p 是一个数组, 然后与 int 结合, 说明数组里的元素是整型的, 所以 p 是一个由整型数据组成的数组。

4,int *p[3];

这是一个数组,该数组里面的成员是整型的指针,分别指向 int 型的内存。

解析:

首先从 p 处开始, 先与 [] 结合,因为其优先级比 * 高,所以 p 是一个数组, 然后再与 * 结合, 说明数组里的元素是指针类型, 然后再与 int 结合, 说明指针所指向的内容的类型是整型。

微信截图_20210528161733.png

5,int (*p)[3];

这是一个指针,指向一个 int 型数组,地址类型是int [3]型。

解析:

首先从 p 处开始, 先与 * 结合,说明 p 是一个指针然后,再与 [] 结合(与 () 这步可以忽略,只是为了改变优先级), 说明指针所指向的内容是一个数组, 然后再与 int 结合, 说明数组里的元素是整型的。

微信截图_20210528162431.png

6,int **p;

这是一个整型指针变量,用于存放一个整型变量的地址,

解析:

首先从 p 开始, 先与 * 结合, 说是 p 是一个指针, 然后再与 * 结合, 说明指针所指向的元素是指针, 然后再与 int 结合, 说明该指针所指向的元素是整型数据。

7,int p(int);

这是一个函数,函数的返回值是一个整型数据。

解析:

从 p 处起,先与 () 结合, 说明 p 是一个函数, 然后进入 () 里分析, 说明该函数有一个整型变量的参数, 然后再与外面的 int 结合, 说明函数的返回值是一个整型数据。

8,void *p(int);

这是一个函数,函数的参数是 int,返回值是 void *

9,int (*p)(int);

这是一个指针,指向一个函数,该函数形参是 int,返回值是 int

解析:

从 p 处开始, 先与指针结合, 说明 p 是一个指针, 然后与 () 结合, 说明指针指向的是一个函数, 然后再与 () 里的 int 结合, 说明函数有一个 int 型的参数, 再与最外层的 int 结合, 说明函数的返回类型是整型。

10,int (*p[3])(int);

解析:

  • p 先和[3]结合,说明 p 是一个数组;
  • p[3] 外面 * 结合,所以数组元素是一个指针;
  • 假定 (*p[3])X,外面是 int (X)(int),所以指针是指向函数,函数的形参是 int 型,返回值是 int 型。

微信截图_20210528165552.png

11,int *(*p(int))[3];

解析:

从 p 开始,先与 () 结合, 说明 p 是一个函数, 然后进入 () 里面,与 int 结合, 说明函数有一个整型变量参数, 然后再与外面的 * 结合, 说明函数返回的是一个指针, 然后到最外面一层, 先与 [] 结合, 说明返回的指针指向的是一个数组, 然后再与 * 结合, 说明数组里的元素是指针, 然后再与 int 结合, 说明指针指向的内容是整型数据。

所以 p 是一个参数为一个整数,且返回一个指向由整型指针变量组成的数组的指针变量的函数。

阅读全文 »

每一个变量都有一个内存位置,每一个内存位置都定义了可使用 & 运算符访问的地址,它表示了在内存中的一个地址。

指针

指针也就是内存地址,指针变量是用来存放内存地址的变量。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:

1
type *var-name;
阅读全文 »

语法格式

1
2
3
4
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};

第一个枚举成员的默认值为整型的 0,后续枚举成员的值在前一个成员上加 1。

以在定义枚举类型时改变枚举元素的值:

1
enum season {spring, summer=3, autumn, winter};

没有指定值的枚举元素,其值为前一元素加 1。也就说 spring 的值为 0,summer 的值为 3,autumn 的值为 4,winter 的值为 5

阅读全文 »

传递数组给函数

这三种类型,都是将整型指针传递给函数。

方式 1

形式参数是一个指针:

1
2
3
void myFunction(int *param)
{
}

方式 2

形式参数是一个已定义大小的数组:

1
2
3
void myFunction(int param[10])
{
}

方式 3

形式参数是一个未定义大小的数组:

1
2
3
void myFunction(int param[])
{
}
阅读全文 »