c

第1章 绪论

注释

//

/**/

进制数

程序设计语言

程序设计

程序设计概念

算法

程序设计的步骤

C语言发展和C++简介

C语言发展简介

C++简介

集成开发环境

C语言程序的构成

注释

预处理命令

程序级定义

函数原型声明

main函数

用户自定义函数

Visual C++简介

运行简单C程序

编译

连接

运行

程序调试一般过程和手段

Visual C++调试方法和工具

Dev-C++ 5.11简介

C程序的编辑与运行

Dev-C++调试方法和工具

第2章 C语言基础

运算符

  1. 分量运算符: . 、->
  2. 下标运算符: [ ]

C语言词法

基本字符集

关键字

特定字

标识符

运算符

  1. 算术运算符
  2. 关系运算符
  3. 逻辑运算符
  4. 位运算符
  5. 赋值运算符
  6. 自增和自减运算符
  7. 条件运算符
  8. 强制类型转换运算符
  9. 逗号运算符
  10. 指针和地址运算符
  11. 求字节数运算符
  12. 分量运算符
  13. 下标运算符

分隔符

基本数据类型

1、整型

2、实型

3、字符型

字符型用于描述单个字符数据,用关键字char表示

一个字符型数据即可以按字符形式输出,也可以按整数形式输出。

当字符型数据以整数形式输出时,实际上是输出该字符的ASCII码。

字符型数据可以当作整型数据进行算数运算

4、空值型

空值型又称无值型,用关键字 void 表示,其值集为空集。

在C程序中 void 可出现在函数定义的头部。

当函数的返回值类型说明为 void 时,表明该函数没有返回值

而当void出现在函数定义的形参位置时,表示该函数没有参数。

此外,它还可以用来表示通用类型指针

常量

常量指在C程序运行过程中,其值不可改变的量

常量有2中形式,字面常量 和 符号常量

字面常量

字面常量 以 字面值 的形式,直接出现在程序中,也称为 直接常量

160-8// 整型常量
56-3.14// 浮点型常量
'B', 'e', 			  // 字符常量
"How do you do !", 	  // 字符串常量

1、整型常量

十进制整数形式

八进制整数形式

十六进制整数形式

2、实型常量

小数点表示法

指数(科学)表示法

3、字符型常量(重点)

字符型常量占据一个字节的存储空间,实际存放的并不是字符本身,而是该字符的ASCII编码

例如 字符’a’ 在内存中存放的值为 97

由于字符常量实质上存放的是整数,因此,可以按其 ASCII 码值和其他整数一样参与数值运算

单引号是区分 字符 与 非字符 的重要标志

4、字符串常量(重点)

字符串常量是由 一对英文双引号("") 括起来的字符序列。

该字符序列可以是单个字符,也可以是多个字符,还可以没有字符。

没有字符的字符串称为空串。

字符串常量 简称 字符串

字符串常量 中可以包含字母、空格、标点符号、转义字符和其他字符等

"how do you do"
"a"
"123.45"
"China\tBeijing\n"
"\x3b\103\\\""
"" 									//空串

不要将 字符常量 与 字符串常量 混淆

‘a’ 是 字符常量, “a” 是 字符串常量,二者在内存中的存储方式不同

字符常量 在内存中固定占用1个字节,字符串因为长度不固定,系统会在字符串末尾加 一个字符 ‘\0’, 作为字符串的结束标志

因此,字符串 “a” 占用2个字节

符号常量(有名常量)

  1. 用关键字 const 定义
  2. 用编译预处理命令 #define 定义

使用符号常量的好处

  1. 含义清楚,增强程序的可读性

  2. 便于修改,能做到 “一改全改”

  3. 便于保持常量的一致性

变量

变量名

变量的类型

变量的值

变量的地址

变量的定义

变量的初始化

表达式

算术表达式

基本算数运算
基本算术运算的优先级和结合性

双目运算符的结合性是左结合,即 “从左往右” 进行运算

单目运算符的结合性是右结合,即 ”从右往左“ 进行运算

数学函数与数学公式

sqrt(x), 平方根函数

fabs(x), 求x的绝对值

sin(x), 三角函数

exp(x), ex指数函数

pow(x, y), x的y次方

类型转换

隐式类型转换

隐式类型转换遵循以下规则:

1.无条件的隐式类型转换

​ 所有的 char 型 和 short 型 数据参与运算时,必须先转换成 Int 型,再作运算

2.统一类型的隐式类型转换

​ 如果双目运算符两边的操作数类型不一致,则需要将其中类型较低的转换为较高的类型,

​ 然后基于统一类型进行运算,隐式类型转换规则如图

显示类型转换

格式

(类型名) 数据;

赋值表达式

简单赋值运算符
复合赋值运算符
赋值表达式的值
赋值运算符嵌套
赋值运算时的隐式类型转换

自增、自减表达式

逗号表达式

逗号运算符
逗号表达式

第3章 结构程序设计

结构化程序设计方法

  1. 自顶向下分析设计问题
  2. 模块化程序设计

语句的概念

表达式语句

控制语句

  • 选择语句
    • if_else、switch
  • 循环语句
    • while、do_while、for
  • 转向语句
    • break、continue、goto

复合语句

空语句

输入输出函数

格式输出函数

printf("格式控制字符串", 表达式1, 表达式2...,表达式n);

格式输入函数

scanf("格式控制字符串", 输入项地址列表);

字符输出函数

C语言提供了专门用于字符输出的 putchar 函数

格式:

putchar(c);

说明:

putchar函数一次调用只能输出一个字符,不能写成 putchar(a, b, c);

字符输入函数

字符输入函数 getchar 没有参数

格式:

getchar();

顺序结构程序设计举例

第4章 选择结构程序设计

关系表达式和逻辑表达式

关系表达式

逻辑表达式

优先级

算数运算符

关系运算符

&&

||

赋值运算符

if语句

if语句

if…else语句

if语句的嵌套

if…else if语句

条件表达式

switch语句

格式:

switch(表达式)
{
        case 常量表达式1;		// 语句序列1
        case 常量表达式2// 语句序列2
        ...
        case 常量表达式n;		// 语句序列n
        default;			   // 语句序列n+1
}

使用 switch 语句注意点:

1.case 后面只能跟常量表达式,不能出现变量或含变量的表达式,且每个 case 后的常量表达式的值不能相同,否则会出现错误。

​ 但不同常量可以共用同一个语句序列

2.case 后面的常量表达式相当于一个语句标号,

​ 程序执行 switch 语句时,根据 switch 后面表达式的值确定入口标号,

​ 然后从该入口标号后的语句开始往下执行

3.case 子句中常以 break 语句结束 switch 语句,但 break 语句不是必需的。

​ 当执行遇到 break 语句时,从 switch 语句退出,转去执行 switch 的后续语句

​ 若没有遇到 break 语句,将继续执行紧接其后的语句,直至遇到 break 语句 或 switch 语句结束

4.case 子句允许有多个语句(语句系列),可以不用{}括起来

5.各 case 子句 和 default 子句的先后顺序可以变动,不会影响程序执行结果。习惯上把 default 写在 switch 语句的最后

6.default 子句是可选性,可以不出现。

​ 当表达式的值与所有 case 后的常量表达式均不限通时,

​ 如果有 default 子句,则执行default 子句

​ 如果没有 default 子句,则不作任何操作,接着转去执行 switch 语句的后续语句,

​ 为了避免程序忽略一些意外情况,在 switch 语句中使用 default 子句是一种良好的程序设计习惯

第5章 循环结构程序设计

for语句

while语句

do…while语句

格式

do
{
    
}while;		//注意 while 后面有分号;

循环的嵌套

break语句和continue语句

goto语句

语法格式

goto 语句标号;
...
语句标号:语句;

例子

//5.6.1 用一个goto语句退出多层循环的示例
#include<stdio.h>
int main () {
    int i, j, k;
    for (i=1; i <= 99; i++)
        for(j=1; j<=99; j++)
            for(k=1; k<=99; k++)
                if (i*i + j*j + k*k > 100) goto bottom; // goto语句退出三层循环
    bottom: printf("i = %d, j = %d, k = %d\n", i, j, k);
    return 0;
}

常用算法举例

累加法

穷举法

第6章 函数

函数定义与调用

函数定义

函数调用

函数原型声明

函数间数据传递

函数参数

函数返回值

函数的嵌套与递归

函数嵌套调用

函数递归调用

函数应用举例

变量属性

变量的生存期和可见性

  1. 生存期
  2. 可见性

变量的作用域

局部变量
全局变量

如果变量在所有函数之外定义,则称该变量为全局变量,也称外部变量

它既可以定义在源文件的开头,也可以定义在两个函数的中间或源文件的尾部

作用域:从定义的位置开始到本源文件结束

全局变量可以被其作用域范围内的所有函数使用,还可以通过引用声明,使其作用域扩展至整个源文件,甚至扩大到本程序的其他源文件

所以全局变量的作用域是文件级或者程序级的

全局变量在程序的整个执行期间都占有固定的内存单元,并保留其值。

所以在整个程序的运行期(不管在函数内外)总是存在

需要强调的是,除非十分必要,一般不提倡使用全局变量

不提倡使用全局变量的原因

1.虽然利用全局变量可以增加函数之间数据联系的渠道,但全局变量在程序的整个执行过程中都占用存储单元,增加空间的开销

2.在函数之间通过全局变量传递数据,要求主调函数和被调函数都得使用相同的全局变量名,从而影响了函数的独立性

3.在程序结构化设计中,在划分模块时要求模块的 “内聚性” 强,与其他模块的 “耦合性” 弱,即模块的功能要单一,不要把许多互不相干的功能放到一个模块中,与其他模块的相互影响要尽量少。

而在函数中使用全局变量,使各模块之间的互相影响变大,从而使函数之间的 “耦合性” 强

4.在函数中使用全局变量,会降低程序的清晰性,可读性变差。因为在各函数被调用时都可能改变全局变量的值,使人难以清楚地判断出每个瞬间各个全局变量的值,从而容易因疏忽或使用不当而导致全局变量值的意外改变,从而引起副作用,产生难以查找的错误。

一般选择变量可遵守以下原则

1.当变量只在某函数使用时,不要定义成全局变量

2.当多个函数都引用同一个变量时,在这些函数之前定义全局变量,而且定义部分尽量靠近这些函数

重点重点重点

如果全局变量和局部变量同名,在局部变量的有效作用范围内,同名全局变量被屏蔽,即同名全局变量不可见

全局变量引用声明

如果全局变量不在源文件开头定义,其有效范围只限于变量定义处到本源文件尾,

如果在定义点之前的函数想引用该全局变量,则应该在引用之前用关键字 extern 对该变量作引用性声明,以告诉编辑器该变量在本文件的某处已经被定义

有了此声明,才能合法地使用别处已定义的外部变量

变量的存储类别

auto局部变量

若在函数内按如下格式定义变量:

auto 数据类型名 变量名列表;

称这样定义的局部变量为自动类型局部变量,简称自动变量

register局部变量

若在函数内部或复合语句内按如下格式定义变量:

register 数据类型名 变量名列表;

称这些变量为寄存器变量

static局部变量

若在函数(或复合语句)内按如下格式定义变量:

static 数据类型名 变量名列表;

称这些局部变量为静态局部变量

静态局部变量属于静态存储类

编译时将静态局部变量分配在内存的静态存储区

与自动变量相同的是,

静态局部变量的作用域也是从定义的位置起,到函数体(或复合语句)结束为止

与自动变量不同的是,

1.在程序的整个运行期间,静态局部变量在内存的静态存储区中占据固定的存储单元,即在定义该变量的函数调用结束后其所占据的存储单元并不释放,下次改函数在此被调用时,静态局部变量仍使用原来的存储单元。

由于并不释放这些存储单元,上次调用结束时保存在存储单元的值仍然保留

2.静态局部变量的初值是在编译时赋给的(仅赋值一次),即在程序运行已经初始化,定义该变量的函数每次被调用时不再初始化,而是保留上次函数调用结束时的值。

如果静态局部变量在定义时未赋初值,编译时会自动被初始化为0。

而对自动变量,系统不会自动为其初始化,因此在定义自动变量时若没有初始化,其值是不确定的

全局变量

全局变量也称外部变量,属于静态存储类

可以用 static 限定全局变量的作用范围,使它只能被本源文件中的函数引用,格式如下:

static 数据类型名 变量名列表;

称这样定义的变量为静态全局变量

第7章 编译预处理

宏定义

不带参数的宏

带参数的宏

取消宏定义

文件包含

条件编译

#if 和 #endif命令

#ifdef 和 # ifndef命令

defined预处理运算符

第8章 数组

一维数组

一维数组的定义

一维数组的引用

一维数组的初始化

一维数组引用举例

// 例8.1.7 用冒泡法对n个整数排序
#include<stdio.h>
int main () {
    int i, j, t, n, a[100];
    printf("n=");
    scanf("%d",&n);
    printf("输入数字:\n");
    for(i=0; i<n; i++) 
        scanf("%d",&a[i]);
    for (i=1; i<n; i++) {
        for (j=0; j<n-i; j++) {
            if (a[j] > a[j+1]) {
                t=a[j];
                a[j]=a[j+1];
                a[j+1]=t;
            }
        }
    }
    printf("排序后的数字:\n");
    for(i=0; i<n; i++)
        printf("%d\t", a[i]);
    printf("\n");
    return 0;
}

多维数组

二维数组的定义和引用

二维数组的初始化

int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};

二维数组应用举例

字符串

字符型数组

字符串

字符串就是一串字符,是程序设计中经常使用的数据

例如学生的姓名、商品的名称等

在C语言中,并没有专门设置 “字符串类型” ,而是将字符串作为字符数组来处理

字符数组是一种构造数据,不能整体处理。而在实际应用中,经常把字符串当做基本类型的数据,需要对字符串进行整体处理。

为此,C语言对字符数据进行了补充定义

对于字符型数组、字符串数组赋值的几种方式,总结一下,看看要不,只记几种,然后在程序中大量使用这几种,

不然,到现在为止,对于字符型数组、字符串数组赋值,感觉还是比较乱

字符串结束符
字符数组初始化

上面各语句都是定义字符数组c,数组的长度为6,。

字符数组的值为字符串 Hello, 字符串的长度为5.

所谓字符串长度就是字符串所包含的字符个数(不包括字符串结束符)。

可见存储 字符串的 字符数组长度 必须大于 字符串长度

注意:

char c[] = "Hello"char c[] = {'H', 'e', 'l', 'l', 'o', '\0'} 等价
char c[] = "Hello"char c[] = {'H', 'e', 'l', 'l', 'o'} 不等价

如果不把字符数组看做字符串,字符数组中不一定要包含值为 ‘\0’ 的元素

字符数组的输入和输出

对字符数组进行输入和输出,

可以使用格式符 “%c” 逐个字符 输入 或 输出,

可以使用格式符 “%s” 对 字符数组 整体 输入 或 输出

字符串处理函数

为了减轻一般用户的编程工作量,C语言提供了大量的字符串处理函数,

这些字符串处理函数主要应用于字符串输入输出、字符串复制、合并、修改、比较、转换和搜索等。

其中用于输入输出的字符串函数原型声明包含在 头文件 “stdio.h” 中,(所以puts, gets 就不需要写 string.h了)

其他字符串函数原型声明包含在 头文件 “string.h” 中

字符串输出函数puts

格式

puts (字符串);

功能:将字符串输出到屏幕并换行

说明:指定的字符串可以是字符串常量或字符数组

字符串输入函数gets

格式

gets (字符数组);

功能:从键盘上输入一串字符,赋给指定的字符数组

说明:从键盘输入的字符串以回车符结束,其中可以包含空格字符。

这也是 gets (s) 函数和 scanf("%s",s)函数的主要区别

字符串连接函数strcat

格式:strcat(字符数组,字符串)

功能:将“字符串”连接到“字符数组”之后,并把字符数组的首地址返回

说明:函数中的字符串可以是字符串常量或字符串变量(即字符数组)。

函数调用后,“字符串”的值不变,“字符数组”的长度为原来两串长度之和

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

int main() {
    char a[5] = "abc", b[5] = "123";
    puts(strcat(a, b));
    // puts中,放 字符数组
    puts(a);
    puts(b);
    return 0;
}
字符串比较函数strcmp

格式

strcmp (字符串1, 字符串2);

功能:比较两个字符串的大小

当两字符串相等时,返回函数值 0

当字符串1的值小于字符串2的值时,返回函数值 -1

当字符串1的值大于字符串2的值时,返回函数值 1

测字符串长度函数strlen

格式

strlen(字符串);

功能:返回 “字符串” 的长度(不包括字符串结束符 ‘\0’)

说明:要注意字符数组的长度和字符串长度的区别

小写字符串函数strlwr

格式

strlwr (字符数组);

功能:把 “字符数组” 中的所有大写字母转化为小写字母,其他字符不变

说明:函数的实际参数只能是字符数组,不能是字符串常量

大写字符串函数strupr

格式

strupr (字符数组);

功能:把 “字符数组” 中的所有小写字母转化为大写,其他字符不变

说明:函数的实际参数只能是字符数组,不能是字符串常量

字符串应用举例

第9章 结构体、共用体和枚举类型

结构体

数组类型用于表示一组相关联的、同类型的数据集合

一个数组不仅存储一批同类型数据,而且能表达各数据元素之间的线性关系

在C语言中,为了将这些互相联系而类型不相同的数据作为一个整体处理,引入了一种称为结构体类型的数据类型

即结构体类型由一组相关联的数据元素构造而成,各元素的数据类型可以相同或不相同

结构体类型的定义

struct Commodity
{
    char Name[20];
    int Price, Count;
    char Provenance[30];
}

在结构体定义中,成员项可以是已经定义的各种数据类型,包括已经定义的结构体类型

如果结构体的成员项又是结构体,称为嵌套结构体

struct Date
{
    int year, month, day;
}

struct Commodity_Date
{
    char Name[20];
    int Price;
    int Count;
    struct Date Production_Date;
    char Provenance[20];
}

结构体的类型知识定义了一种数据类型,只规定了这种数据类型的变量在内存中的存储分配模式,并没有分配实际的内存空间

当定义了结构体变量之后,系统才在内存为变量分配存储空间,

可见,结构体类型定义是为结构体变量定义服务的

结构体变量定义和初始化

struct 结构体类型名 结构体变量名;
struct Commodity_Date TV;

结构体变量的引用

结构体数组

结构体数组是数组元素类型为结构体类型的数组。

结构体数组和整型数组、字符数组相比较,概念上并没有什么差别,只是结构体和数组嵌套,可以表示更复杂的数据结构

struct Commodity
{
    char Name[20];
    int price;
};

struct Commodity aTV[3];

上面定义了一个结构体数组 aTV,aTV有三个元素,分别是aTV[0], aTV[1], aTV[2]

aTV个元素类型是 Commodity,各元素有两个成员项

结构体数组的数组名表示该结构体数组的存储区域首地址,数组中各个元素在内存中依次连续存放,数组元素中的各成员项也是依次连续存储。

共用体

共用体类型的定义

共用体变量的定义

枚举类型

枚举类型的定义

枚举变量的定义

typedef语句

typedef 是 type define 的缩写

typedef 并没有定义新的数据类型,而是为已定义的数据类型取别名

例如,typedef语句给结构体类型取别名,以缩短类型名的长度

typedef struct Commodity
{
    char Name[20];
    int Price;
    int Count;
    char Provenance[30];
}COMMODITY;

进行上述定义之后,就可以用 COMMODITY TV; 代替 struct COMMODITY TV

又如,不同的C系统,int型数据占用的字节数不同,

有的 C 系统 int型数据占用 4 个字节(如VC++),

有的系统int型数据占用2个自己(如Turbo C),

如果要把一个C程序从VC++环境移植到Turbo C,可能会引起 int型数据溢出,

一种方法是把程序中的某些 int 改成 long int,但这样做既麻烦又有可能遗漏

另一种方法是在程序中用标识符INTEGER 定义整型变量,然后在程序的开始处用 typedef 对 INTEGER 进行定义

例如在VC++环境中执行

typedef int INTEGER;

而当移植到 Turbo C 环境时,把 typedef 改成

typedef long INTEGER;

第10章 指针

地址与指针变量

内存单元地址

计算机主存储器由一批存储单元组成,微型计算机以字节作为基本存储单元,

每个存储单元具有唯一的地址,存储单元的地址是一个无符号整数,主存储器的所有存储单元的地址是连续的

指针

存储整数的变量称为整型变量

存储字符的变量称为字符变量

存储某个变量的地址的变量应该称为 “地址变量”

C语言中,把 “地址变量” 称为 指针变量

指针变量存储的是另一个变量的地址,即指针变量 “指向” 另一个变量对应的存储区域

这种指向是通过地址来体现的,因此 地址 也被称为 指针,那么存放某个变量地址的变量就被称为指针变量

变量的地址由系统分配,变量地址一经分配就不会改变,因此变量地址是一个常量

变量地址可由 运算符 & 和 变量运算 获得。

例如程序中经常使用的输入函数 scanf("%d", &a),其中表达式 &a 的值就是变量a的地址,执行该函数从键盘读取一个整数,存入变量 a 的存储区域中

数组名也是地址,它代表该数组首元素的地址

设 a 为 一维数组,则有 a == &a[0],即 a 代表 a[0] 的地址

指针变量的定义和初始化

指针变量 属 简单变量,一个 指针变量 存储 一个变量的地址

定义形式

基类型 *指针变量名;

“基类型” 是某个已定义的数据类型,

  • 可以是系统预定义的类型,也可以是用户自己定义的类型
  • 可以是简单类型,也可以是构造类型

符号 “*” 表示定义的是一个指向 “基类型” 的指针变量

例如

int var = 10;
int * pointer = &var; 

上面第一个语句定义了整型变量 var,并初始化为 10,

第二个语句定义了指针变量 pointer,并用整型变量的地址 &var 对它初始化

注意

指针变量的变量名是 pointer,而不是 * pointer

说法:指针变量 pointer,指针 pointer,其他如 指针变量 p,指针 p

指针变量 pointer 的基类型为 int,表示变量 pointer 只能存储一个整型变量的地址,不能存储其他类型变量的地址

例如下面的初始化是错误的

float f;
int * p = &f;

当定义一个指针变量而没有初始化,指针变量的值没有确定,即该指针不指向特定的变量。

这时使用这个变量是危险的,可能造成不可预测的结果

可以把指针变量初始化为 0,即不指向任何变量

例如

int * pointer = 0;int * pointer = NULL;

标识符 NULL 是系统定义的宏,在头文件 stdio.h 中定义,即定义为

#define NULL 0

指针值为 0 和 指针值不确定的意义完全不同

指针的运算

指针专用运算符

取地址运算符 &

运算符 & 是单目运算符,结合方向是右结合的

& 的运算对象只能是变量名(包括 简单变量 和 构造型变量)、数组元素 或 结构体成员,不能是表达式

& 的运算结构就是 运算对象(变量)的地址

指向运算符 *

在这里, * 称为指向运算符 或 间接访问运算符,是 单目运算符,结合方向 是 右结合

* 的 运算对象 只能是 指针变量,* 的 运算结果 得到运算对象(指针变量)所指的变量

例如

p1 = &a, *p1 表示 变量a,是对变量a 的间接引用

*p1 是整型变量,不是指针,*p1 是整型变量,不是指针,*p1 可以像 一般整型变量 一样使用

注意符号 * 出现在不同位置含义不同

在变量定义语句 int * p; int * 是 类型名,p 是变量名

在表达式中,符号 * 既可表示乘法,也可表示指向。

一个运算符有多个功能,在C语言中称为 运算符重载,系统会根据程序的上下文自动识别,读者应根据程序需要灵活应用

重点重点重点

说法问题,这个说法,和上面的 用心体会 一下,要真正理解了

以后明确

*p 叫 变量

p 叫 指针

赋值运算
算数运算
关系运算

指针与函数

指针变量作为函数参数

函数的返回值为指针

函数调用可以返回一个值,即函数值。

函数值可以是整型、实型 或 字符型,当然也可以是 指针型,即函数调用后返回一个地址

返回 指针 的函数定义格式如下

类型名* 函数名(参数表);

例如:

int* fun(int x, int* p);

表示函数 fun 有2个参数(1个整型参数,1个指针型参数)。

函数名 fun 之前有符号*,表示函数返回值 是 指向 整数 的指针

指向函数的指针

到目前为止,都是通过 函数名 调用 函数

编译后的函数存储在内存中,因此函数也有地址,函数地址是指 函数的 入口地址(即 函数代码的起始地址)。

事实上,函数名指定的就是 函数 的 入口地址。也可以用 一个指针变量 指向函数,然后通过该 指针变量 调用 此函数

定义指向函数的 指针变量 的一般形式如下:

数据类型 (* 指针变量名) ()

例如

int (* p)();

指针变量p 是 指向某整型函数的 指针变量。

在定义 指向函数的指针时,需要2个括号。

第1个括号表示优先级,表示符号 * 和 p 优先结合

第2个括号 表示 *p 是函数

如果没有第1个括号,即

int * p();

这是函数原型说明,声明 p 函数的 返回值 是 一个指针

定义函数指针变量的目的之一 是 将函数作为另一个函数的参数。

使得函数参数不仅能传递数值和地址,还能传递代码(函数)。

指针与数组

一维数组与指针

字符串与指针

指针数组

元素类型为指针型的数组称为指针数组

格式:

类型名 *数组名[数组长度];

指针数组作为 main 函数的形参

到目前为止,主函数main()都不带形参。其实主函数 main() 也可以带参数。

当主函数带参数时,需要解决2个问题:

  1. 函数的形参如何表示
  2. 函数的实参如何提供

一个程序总是从主函数开始执行的,然后才通过主函数调用其他函数,调用函数时,主调函数把实际参数的值传递给被调函数的形式参数。

其实主函数也是被调用的,主函数被操作系统调用,因此如果主函数有参数,对应的实际参数应由操作系统提供

通过双击程序文件名而执行程序或在VC环境下选择“运行”命令而执行程序,用户没有机会为主函数提供实际参数。

但如果用文本命令方式执行程序,就可以在输入程序名的同时为主函数输入实际参数

C语句规定,主函数main() 的形式参数只能有2个,而且必须是2个。

同时进一步规定,第1个参数类型必须是整型,第2个参数类型必须是字符指针数组型。

习惯把第一个参数写成 argc,把第2个参数类型写成 argv(当然,参数名只要符合标识符规则即可,不一定非得写成 argc 和 argv )

因此带参数的主函数头部形式如下

int main(int argc, char* argv[])
#include <stdio.h>
int main(int argc, char* argv[]) {
    int i;
    printf("argc = %d\n", argc);
    for (i = 0; i < argc; i++) {
        printf("argv[%d] = %s\n ", i, argv[i]);
    }
}

指针与结构体

指向结构体的指针

结构体指针的定义

和定义其他类型的指针变量一样,也可以定义指向结构体的指针变量

指向结构体的指针存储的是结构体变量所占内存区域的首地址

struct Commodity
{
    char Name[20];
    int Price;
};
struct Commodity tv, aTV[3], *p1, *p2, *p3;

其中p1、p2和p3都是指向结构体变量的 指针
类型名 变量名;

p1 = &tv;			// 把结构体变量的地址赋给结构体指针变量
p2 = aTV;			// 把结构体数组的首地址赋给结构体指针变量
p3 = &aTV[1];		// 把结构体数组元素的地址赋给结构体指针变量
用指针引用结构体成员

结构体变量 使用 "."运算符 访问其成员。

例如 tv.Price;

假设 p1 = &tv,使 p1 指向 tv,即 *p1 代表 tv,(要体会并理解这句话)

因此,用指针引用结构体成员可以写成

(*p1).price;

除了用上述方法引用结构体成员外,

C语言专门定义了一个用指针引用结构体成员的运算符 “->”,即 (*p1).Price 和 p1->Price 等价,

p1->Price 表示 p1 指针所指的结构体变量(这里是 tv)的 Price 成员

使用运算符 “->” 引用结构体成员更直观高效

结构体变量 和 结构体指针 都可以作为函数的 参数,

前者传递的是 结构体变量 的 值,而后者传递的是 结构体变量 的 地址

//10.4.1 结构体作为函数参数示例

#include<stdio.h>
struct Commodity
{
    char Name[20];
    int Price;
};

void fun1(Commodity s);
void fun2(Commodity *p);
int main()
{
    struct Commodity c = {"shanghai", 2000};
    fun1(c);
    printf("main:Name = %s\tPrice = %d\n", c.Name, c.Price);
    fun2(&c);
    printf("main:Name = %s\tPrice = %d\n", c.Name, c.Price);
    return 0;
}

void fun1(Commodity s)
{
    s.Price = 1800;
    printf("fun1:Name = %s\tPrice = %d\n", s.Name, s.Price);

}

void fun2(Commodity *p)
{
    p->Price = 1800;
    printf("fun2:Name = %s\tPrice = %d\n", p->Name, p->Price);
}

动态存储分配

malloc函数

malloc 函数的原型

void* malloc(unsigned size);

调用 malloc 函数,要求系统在内存中分配一块存储空间。

函数的形参是一个无符号的整数,用于确定存储空间的长度(字节数),

函数返回存储空间的首地址

重点

函数返回的 指针 是无类型的,用户要根据存储空间的用途把 它 强制转换成相应的类型

// 10.4.2 动态存储空间分配示例。
#include<stdio.h>
#include<stdlib.h>
int main ()
{
    int* p;
    p = (int* )malloc(4);
    *p = 10;
    printf("*p = %d\n", *p);
    return 0;
}
calloc函数

calloc 函数的原型

void* calloc(unsigned n, unsigned size);

callco 函数的功能是为一维数组分配存储空间。

形参 n 为数组长度(数组元素个数),形参 size 为数组元素长度(每个数组元素占用多少字节)

free函数

free 函数的原型

void free(void* p);

free 函数的功能是释放由 p 指向的存储区域

程序中的变量都有其生存期,采用动态分配方式定义的变量属于全程变量,但指向动态变量的指针往往是局部变量

链表

单链表的建立
单链表的输出过程
单链表的查找
在单链表中删除指定的结点

第11章 文件

文件概述

文本文件和二进制文件

结构文件和非结构文件

按文件中数据的组织方式分类,有结构文件和非结构文件

结构文件由记录组成,各记录具有相同的、确定的数据类型

例如数据VFP的表文件(dbf)就是结构文件

高级语言 PASCAL 也支持结构文件

C语言不支持结构文件,C语言把文件看做是字符流或字节流。

即文件是由一系列字符或字节按一定次序组成

C语言以字节作为文件的基本存取单位,从文件中读写数据的过程只受程序控制,不受物理符号的控制

因此,

往文本文件中写数据时,各数据之间要人为加入分隔符号,系统不会自动分隔各数据,

往二进制文件中写数据时,应记住数据类型,否则以后无法读出,或读出后无法使用

缓冲文件系统和非缓冲文件系统

根据系统对文件中数据的读写方式不同,可分为缓冲文件系统和非缓冲文件系统

C语言提供了两种文件系统对文件进行操作,即提供了两套操作函数来存取文件

缓冲文件系统又称为标准文件系统或高层文件系统,它与具体及其无关,通用性好,使用方便。VC使用的是缓冲文件系统

非缓冲文件系统又称为低级文件系统,与机器有关,使用较困难,但节省内存,执行效率较高。UNIX系统用非缓冲文件系统处理二进制文件

当程序读写文件时,需要频繁启动磁盘,这必然降低程序的执行效率

为提高效率,在内存中开辟一块称为缓冲区的区域用于 I/O操作

对于输出操作,每次输出的数据先存储于缓冲区,只有当缓冲区数据存满后,才一次将缓冲区中的数据全部输出到外存文件中

对于输入操作,每次读入的数据也都来自缓冲区,当缓冲区没有所需的数据时,则系统一次从外存文件中读入足够的数据填满缓冲区,

缓冲文件系统中有关缓冲区大小的定义,缓冲区的分配和管理是由系统自动完成的,

非缓冲文件系统并不是没有缓冲区,而是有关缓冲区的管理和操作是由用户自己在应用程序中定义

文件的打开和关闭

文件的打开

  1. 在外部设备中找到或创建指定的文件
  2. 在内存中为文件建立缓冲区
  3. 建立文件变量
  4. 确定文件的使用方式

fopen函数的原型

FILE* fopen(char* filename, char* mode)

格式

FILE *fp;			// 定义文件指针 fp
fp = fopen("file1.txt", "r");

文件打开方式

文本文件二进制文件
mode含义mode含义
r读取(文件已存在)rb读取(文件已存在)
w写入并创建文件wb写入并创建文件
r+读取或写入r+b读取或写入
w+读取或写入w+b读取或写入
a追加ab追加
a+读取或追加a+b读取或追加

说明

  • 以 r 或 rb 方式打开文件,只能从文件中读取数据,不能向文件写入数据,因此打开文件必须已存在,否则出错

  • 以 w 或 wb 方式打开文件,只能向文件中写入数据,不能从文件读取数据。如果文件不存在,则创建文件,否则清除原文件内容,文件只保存新写入的数据

  • 以 a 和 w 方式的区别,a方式打开文件,文件必须已经存在,否则出错。新写入的数据添加到原数据之后

  • r+ 和 w+ 功能相同,都是以读写方式打开文件,即打开文件后,可把数据写入文件,也可从文件中读取数据

  • a+ 和 w+的区别是,文件打开后,文件的读写位置指示器的初始值不同。在 FILE型变量中,有一个用于指示文件当前可读或可写字符位置的成员,俗称文件位置指示器。

    • 用w方式打开文件,文件位置指示器指向文件的第一个第一个字符(字节),
    • 用a方式打开文件,文件位置指示器指向文件末尾,即文件最后字符(字节)之后

注意:在Visual C++系统,并不区分 r 和 rb

文件的关闭

flose 函数的原型

fclose(FILE *f);

其中函数参数 f 是指向被关闭文件的指针变量

如果文件关闭成功返回函数值 0,否则返回 -1

fclose(fp);

关闭了文件指针 fp 所指向的文件,即关闭了与变量 fp 关联的 file1.txt 文件

在 Visual C++等系统中,具有较完善的文件保护功能,如果用户没有关闭文件,系统释放文件指针变量 fp 之前会自动关闭与 fp 关联的文件

C语言把标准输入输出设备也看作文件,并定义了文件指针 stdin 和 stdout 分别指向标准输入设备文件(键盘)和标准输出设备文件(显示器)。

标准输入和标准输出文件的打开和关闭操作由系统自动完成

文件的读写

读写文本文件和读写二进制文件所使用的函数不同

文本文件的读写

标准输入文件(stdin)和标准输出文件(stdiout)都是文本文件。

系统专门为标准文件定义了一套读写函数,如 printf、scanf等

其实之前使用过的标准输入/输出函数并不都是真正的函数,它们有的是由其他函数派生出来的宏,

例如 getchar 和 putchar 就是宏,它们在 stdio.h 中定义如下:

#define getchar()		getc(stdin)
#define putchar()		putc(c, stdout)

但就使用角度而言,并不关心系统如何实现的具体细节,所以不管是真正的函数还是宏,一般都统称为输入/输出函数

字符函数

putc 和 fputc

字符输出函数

putc 和 fputc 函数功能相同,都是把一个字符写到文件中

puts 函数的原型

putc(char c, FILE* f);

调用该函数把参数 c 的值输出到 f 所指向的文件中。

如果调用成功把 c 作为函数值返回,否则返回 -1

//11.3.1 把字符串写到文本文件abc.txt中

#include<stdio.h>
int main()
{
    FILE* fp;
    char msg[] = "Welcome to study Programming in Language C";
    int i = 0;
    
    fp = fopen("abc.txt", "w");
    
    while(msg[])
        putc(msg[i++], fp);
    fclose(fp);
    return 0;
}

getc 和 fgetc

字符输入函数

getc 和 fgetc 函数功能相同,都是从文件中读取一个字符

gec 函数的原型

getc(FILE* f);
// 11.3.2 读取文件abc.txt中的所有字符并显示到屏幕上

#include<stdio.h>
int main()
{
    FILE* fp;
    char c;
    
    //以"只读"方式打开文件
    fp = fopen("abc.txt", "r");
    
    //feof()是文件测试函数
    //当文件位置指针指向文件末尾时结束循环
    while(!feof(fp))
    {
        //从与 fp 关联的文件中读一个字符并赋给变量c
        c = getc(fp);
        
        //把变量c的值输出到文件stdout中,即显示到屏幕
        putc(c, stdout);
    }
    
    //向显示器输出换行
    putc('\n',stdout);
    
    fclose(fp);
    return 0;
}

feof文件测试函数

当以 r 方式打开文件时,位置指示器 指向文件第一个字符

每次调用 getc(fp) 函数,读取 位置指示器 指示的字符,然后 位置指示器 指向下一个字符。

位置指示器 指向文件某字符时,feof(fp) 的值为 0

位置指示器 指向文件结束符时,feof(fp) 的值 非0

字符串函数

fputs

字符串输出函数

功能:把一个字符串写到文件中

fputs 函数原型

fputs(char* s, FIFE* f);
// 11.3.3 把字符串写到文本文件中

#include<stdio.h>
int main()
{
    FILE* fp;
    char msg[] = "Welcome to study Programming in Language C";
    
    //以 "写入" 方式打开文件
    fp = fopen("abc2.txt", "w");
    
    //把字符串msg的值写入fp所指向的文件
    fputs(msg, fp);
    
    fclose(fp);
    return 0;
}

fgets

字符串输入函数

功能:从文件中读取一个指定长度的字符串

fgets 函数原型

fgets(char* str, int len, FILE* f);
// 11.3.4 读取文件abc2.txt中的所有字符并显示到屏幕上

#include<stdio.h>
int main()
{
    FILE* fp;
    char s[50];
    
    //以 "只读" 方式打开文件
    fp = fopen("abc2.txt", "r");
    
    //从 fp 所指文件中读取49个字符并存储于字符串 s 中
    fgets(s, 50, fp);
    
    //把变量s的值输出到屏幕
    puts(s);
    fclose(fp);
    return 0;
}

fprintf

格式化输出函数

功能:按指定格式向文本文件写入数据

fprintf 函数原型

fprintf(FILE* fp, const char* format, 输出项列表);

参数 fp 是指向输出文件的指针,

format 是格式字符串,由格式字符和非格式字符组成

输出项列表是将输出到文件中的数据项,可以是常量、变量或表达式的值

(输出项的个数应和格式符的数量相同)

printf 和 fprintf 的区别

printf, 专用于向标准输出文件(显示器)输出

printf, 可向一般文件输出

printf(“abc\n”); 等价于 fprintf(stdout, “abc\n”);

//11.3.6 把2-500之间的所有素数存入文件prime.txt

#include<stdio.h>

int prime(int k);

int main()
{
    FILE* outf;
    outf = fopen("prime.txt", "w");
    for (int i = 2; i <= 500; i++)
        if(prime(i))
            fprintf(outf, "%d\t", i);
    fclose(fp);
    return 0;
}

//prime函数的功能是判断 k 是否质数,是则返回1,否则返回0
int prime(int k)
{
    int b = 1;
    for (int i = 2; i <= k/2; i++)
        if(k % i == 0)
        {
            b = 0;
            break;
        }
    return b;
}

fscanf

格式化输入函数

功能:从文本文件中读取数据

fscanf 函数原型

fscanf(FILE* fp, const char* format, 输入项地址列表);

scanf("%d", &a); 和 fscanf( stdin, “%d”, &a); 等价

// 11.3.7 从文件prime.txt中读数据,并显示到屏幕

#include<stdio.h>

int main()
{
    FILE* fp;
    
    //以 "只读"方式打开文件
    inf = fopen("prime.txt", "r");
    int k, i = 1;
    
    while(!feof(inf))
    {
        fscanf(inf,"%d",&k);
        printf("%d\t",k);
        
        if(i++ % 10 == 0)
            printf("\n");
    }
    
    fclose(inf);
    return 0;
}

二进制读写函数

fwrite

写数据块函数

fwrite 函数原型

fwrite(void* ptr, int size, int count, FILE* fp);

其中 ptr 为数据块的首地址;

参数 size 为数据块的长度;

参数 count 为数据块数量;

参数 fp 为指向二进制文件的指针

功能是把以 ptr 为首地址的,总长度为 size*count 个字节的数据块原样地写到 fp 指针指向的文件中

fread

读数据块函数

二进制文件中的数据由函数 fread 读出

fread 函数原型

fread (void* ptr, int size, int count, FILE* fp);

功能是从 fp 所指向的文件中读取 size*count 个字节存入到 ptr 指定的内存空间

因此 ptr 必须是已定义的变量地址

定位函数

rewind

复位函数

rewind 函数原型

rewind(FILE* f);

fseek

定位函数

fseek 函数原型

fseek(FILE* f, int offset, int origin);

ftell

显示位置指针函数

ftell 函数原型

ftell(FILE* f);

12 其他

附录A ASCII编码字符集

附录B C语言运算符的优先级和结合性

口诀

算术、关系

逻辑、条件

赋值

getch()

Windows下getch()在conio.h的头文件中,

要使用getch()函数需要引用conio头文件

https://docs.microsoft.com/zh-cn/cpp/error-messages/compiler-warnings/compiler-warning-level-3-c4996?f1url=%3FappId%3DDev16IDEF1%26l%3DZH-CN%26k%3Dk(C4996)%26rd%3Dtrue&view=vs-2019

注意事项

visual studio 2019中,getch() 需要使用 _getch() 否则报错

visual studio 2019中,scanf() 需要使用 scanf_s() 否则报错

进一步理解 scanf(" %d", &x);这个里面 %d前面有空格 和 getch()的区别

参考链接

https://blog.csdn.net/moon19870104/article/details/5897958?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2allfirst_rank_v2~rank_v25-12-5897958.nonecase&utm_term=c++%E7%94%A8windows.h%E5%81%9A%E7%95%8C%E9%9D%A2&spm=1000.2123.3001.4430

使用

#include<stdio.h>
#include<conio.h>

system()

参考链接

https://www.cnblogs.com/zhiyinglky/p/4776873.html

system函数 是可以调用一些DOS命令,

比如

system("cls");//清屏,等于在DOS上使用cls命令

system(“cls”);//清屏,等于在DOS上使用cls命令

命令

下面列出常用的DOS命令,都可以用system函数调用:

ASSOC显示或修改文件扩展名关联
AT计划在计算机上运行的命令和程序。
ATTRIB显示或更改文件属性
BREAK设置或清除扩展式 CTRL+C 检查
CACLS显示或修改文件的访问控制列表(ACLs)
CALL从另一个批处理程序调用这一个
CD显示当前目录的名称或将其更改
CHCP显示或设置活动代码页数
CHDIR显示当前目录的名称或将其更改
CHKDSK检查磁盘并显示状态报告
CHKNTFS显示或修改启动时间磁盘检查
CLS清除屏幕
CMD打开另一个 Windows 命令解释程序窗口
COLOR设置默认控制台前景和背景颜色
COMP比较两个或两套文件的内容
COMPACT显示或更改 NTFS 分区上文件的压缩
CONVERT将 FAT 卷转换成 NTFS。您不能转换当前驱动器
COPY将至少一个文件复制到另一个位置
DATE显示或设置日期
DEL删除至少一个文件
DIR显示一个目录中的文件和子目录
DISKCOMP比较两个软盘的内容
DISKCOPY将一个软盘的内容复制到另一个软盘
DOSKEY编辑命令行、调用 Windows 命令并创建宏
ECHO显示消息,或将命令回显打开或关上
ENDLOCAL结束批文件中环境更改的本地化
ERASE删除至少一个文件
EXIT退出 CMD.EXE 程序(命令解释程序)
FC比较两个或两套文件,并显示不同处
FIND在文件中搜索文字字符串
FINDSTR在文件中搜索字符串
FOR为一套文件中的每个文件运行一个指定的命令
FORMAT格式化磁盘,以便跟 Windows 使用
FTYPE显示或修改用于文件扩展名关联的文件类型
GOTO将 Windows 命令解释程序指向批处理程序中某个标明的行
GRAFTABL启用 Windows 来以图像模式显示扩展字符集
HELP提供 Windows 命令的帮助信息
IF执行批处理程序中的条件性处理
LABEL创建、更改或删除磁盘的卷标
MD创建目录
MKDIR创建目录
MODE配置系统设备
MORE一次显示一个结果屏幕
MOVE将文件从一个目录移到另一个目录
PATH显示或设置可执行文件的搜索路径
PAUSE暂停批文件的处理并显示消息
POPD还原 PUSHD 保存的当前目录的上一个值
PRINT打印文本文件
PROMPT更改 Windows 命令提示符
PUSHD保存当前目录,然后对其进行更改
RD删除目录
RECOVER从有问题的磁盘恢复可读信息
REM记录批文件或 CONFIG.SYS 中的注释
REN重命名文件
RENAME重命名文件
REPLACE替换文件
RMDIR删除目录
SET显示、设置或删除 Windows 环境变量
SETLOCAL开始批文件中环境更改的本地化
SHIFT更换批文件中可替换参数的位置
SORT对输入进行分类
START启动另一个窗口来运行指定的程序或命令
SUBST将路径跟一个驱动器号关联
TIME显示或设置系统时间
TITLE设置 CMD.EXE 会话的窗口标题
TREE以图形模式显示驱动器或路径的目录结构
TYPE显示文本文件的内容
VER显示 Windows 版本
VERIFY告诉 Windows 是否验证文件是否已正确写入磁盘
VOL显示磁盘卷标和序列号
XCOPY复制文件和目录树

用法

使用 system 函数,需要引用 stdlib.h 头文件

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

注意事项

system是stdlib.h中的函数, 用来执行类似cmd的命令

之所以不会报错, 主要是因为有些IDE会自动回给你添加进去

比如有些IDE你即使不添加stdio.h也能使用printf一个道理

所以, 关键问题还是在编译器上.

功 能: 发出一个DOS命令

用 法: int system(char *command)

system函数已经被收录在标准c库中,可以直接调用

使用举例

功 能: 发出一个DOS命令
用 法: int system(char *command);
system函数已经被收录在标准c库中,可以直接调用
程序例:

#include <stdlib.h>
#include <stdio.h>
int main(void)
{
    printf("About to spawn command.com and run a DOS command\n");
    system("dir");
    return 0;
}

system(“pause”)可以实现冻结屏幕,便于观察程序的执行结果;

system(“CLS”)可以实现清屏操作。

而调用color函数可以改变控制台的前景色和背景,具体参数在下面说明。

用 system(“color 0A”); 其中color后面的0是背景色代号,A是前景色代号。

各颜色代码如下:

0=黑色

1=蓝色

2=绿色

3=湖蓝色

4=红色

5=紫色

6=黄色

7=白色

8=灰色

9=淡蓝色

A=淡绿色

B=淡浅绿色

C=淡红色

D=淡紫色

E=淡黄色

F=亮白色

(注意:Microsoft Visual C++ 6.0 支持system)

system在C程序设计中的应用实例

例一:
C语言调用DOS命令实现定时关机:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int print()
{
    printf(" ╪╪╪╪╪╪╧╧╧╧╧╧╧╧╪╪╪╪╪╪\n");
    printf("╔═══╧╧ C语言 关机程序 ╧╧═══╗\n");
    printf("║※1.实现10分钟内的定时关闭计算机 ║\n");
    printf("║※2.立即关闭计算机 ║\n");
    printf("║※3.注销计算机 ║\n");
    printf("║※0.退出系统 ║\n");
    printf("╚═══════════════════╝\n");
    return 0;
}

void main()
{
    system("title C语言关机程序");//设置cmd窗口标题
    system("mode con cols=48 lines=25");//窗口宽度高度
    system("color 0B");
    system("date /T");
    system("TIME /T");
    char cmd[20]="shutdown -s -t ";
    char t[5]="0";
    print();
    int c;
    scanf("%d",&c);
    getchar();
    switch(c)
    {
        case 1:printf("您想在多少秒后自动关闭计算机?(0~600)\n");scanf("%s",t);system(strcat(cmd,t));break;
        case 2:system("shutdown -p");break;
        case 3:system("shutdown -l");break;
        case 0:break;
        default:printf("Error!\n");
    }
    system("pause");
    exit(0);
}

例二:
用C语言删除文件,例如文件的位置是d:\123.txt
用system()函数执行windows命令。

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

int main(void)
{
    system("del d:\123.txt");
    return 0;
}

windows.h

参考链接

https://www.zhihu.com/question/63992355

windows.h中包含了很多其他的.h文件,Win32中用户态的很大一部分API函数引用了它就能使用了

windows.h里的东西非常有用啊,里面有许多可以用的API,比如打开网页,实现按键,鼠标点击

都是可以的

这是Windows API的头文件,不是C语言库函数的头文件,学习C语言的时候没必要管它。

windows.h就是Windows API,同理unistd.h是Linux下的标准库。

以延时函数为例,在windows环境下需要#include<windows.h>,用Sleep()调用;在linux环境下需要#include<unistd.h>,用sleep()调用。

rand()

头文件,是 #include<stdilib.h>

rand()函数用来产生随机数,

但是,rand()的内部实现是用线性同余法实现的,是伪随机数,

由于周期较长,因此在一定范围内可以看成是随机的。

rand()会返回一个范围在0到RAND_MAX(至少是32767)之间的伪随机数(整数)。

在调用rand()函数之前,可以使用srand()函数设置随机数种子,如果没有设置随机数种子,rand()函数在调用时,自动设计随机数种子为1。

随机种子相同,每次产生的随机数也会相同。

rand()函数原型:int rand(void);

使用rand()函数产生1-100以内的随机整数:int number1 = rand() % 100+1。

使用rand()和srand()产生指定范围内的随机整数的方法,“模除+加法”的方法因为,对于任意数,0<=rand()%(n-m+1)<=n-m,因此,

0+m<=rand()%(n-m+1)+m<=n-m+m,因此,如要产生[m,n]范围内的随机数num,可用:

int num=rand()%(n-m+1)+m。其中的rand()%(n-m+1)+m算是一个公式,记录一下方便以后查阅。比如产生10~30的随机整数:

srand(time(0)),int a = rand() % (21)+10

案例

C语言历史

13 MFC

微软基础类库(英语:Microsoft Foundation Classes,简称MFC)是微软公司提供的一个类库(class libraries),

C++类的形式封装了[Windows API](https://baike.baidu.com/item/Windows API/6088382),并且包含一个应用程序框架,以减少应用程序开发人员的工作量。

其中包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装

MFC(Microsoft Foundation Classes)是微软基础类库的简称,是微软公司实现的一个c++类库,

主要封装了大部分的[windows API](https://baike.baidu.com/item/windows API/6088382)函数,vc++是微软公司开发的c/c++的集成开发环境,

所谓集成开发环境,就是说利用它可以编辑,编译,调试,而不是使用多种工具轮换操作,灵活性较大。

vc也指它的内部编译器集成开发环境必须有一个编译器内核,例如DevC++其中一个编译器内核就是gcc

MFC除了是一个类库以外,还是一个框架,在vc++里新建一个MFC的工程开发环境会自动帮你产生许多文件,同时它使用了

mfcxx.dll

xx是版本,它封装了mfc内核,所以你在你的代码看不到原本的SDK编程中的消息循环等等东西,

因为MFC框架帮你封装好了,这样你就可以专心的考虑你程序的逻辑,而不是这些每次编程都要重复的东西,

但是由于是通用框架,没有最好的针对性,当然也就丧失了一些灵活性和效率。但是MFC的封装很浅,所以效率上损失不大。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值