1972 年,为了移植与开发 UNIX 操作系统,丹尼斯·里奇在贝尔电话实验室设计开发了 C 语言。
1973 年,UNIX 操作系统完全使用 C 语言编写。当今最流行的 Linux 操作系统和 RDBMS(Relational Database Management System:关系数据库管理系统) MySQL 都是使用 C 语言编写的。
Windows、Linux、UNIX、Dos操作系统的核心代码大部分是使用C和C++编写,底层接口用汇编编写.
示例代码解释
(1) stdio.h 是一个头文件 (标准输入输出头文件) , #include 是一个预处理命令,用来引入头文件。 (2)所有的 C 语言程序都需要包含 main() 函数。 代码从 main() 函数开始执行。 (3)/* … */ 用于注释说明。 (4)printf() 用于格式化输出到屏幕。 (5)return 0; 终止 main() 函数,并返回值 0。
1、C 程序由各种令牌组成,令牌可以是关键字、标识符、常量、字符串值,或者是一个符号。
五个令牌: (1)分号 ; 在 C 程序中,分号是语句结束符。 (2)注释 C 语言有两种注释方式:// 单行注释 或者 /* 多行注释 */ (3)标识符 C 标识符是用来标识变量、函数,一个标识符以字母 A-Z 或 a-z 或下划线 _ 开始 (4)关键字 (5)C 中的空格:在 C 中,空格用于描述空白符、制表符、换行符和注释。空格分隔语句的各个部分,
2、数据类型:数据类型指的是用于声明不同类型的变量
变量的类型决定了变量存储占用的空间,以及如何解释存储的位模式。 (1)整数类型 种类型的存储大小与系统位数有关,得到某个类型或某个变量的准确大小,您可以使用 sizeof 运算符。 表达式 sizeof(type) 得到对象或类型的存储字节大小
printf("int 存储大小为 %lu\n", sizeof(int));
注:printf()函数
printf("<格式化字符串>", <参量表>); (2)浮点类型 (3)void 类型 void 类型指定没有可用的值。
3、变量
变量其实只不过是程序可操作的存储区的名称。C 中每个变量都有特定的类型,类型决定了变量存储的大小和布局,该范围内的值都可以存储在内存中,运算符可应用于变量上。 变量的声明有两种情况:
(1)一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间。
(2)另一种是不需要建立存储空间的,通过使用extern关键字声明变量名而不定义它。 例如:extern int a 其中变量 a 可以在别的文件中定义的。
extern int i; //声明,不是定义 int i; //声明,也是定义4、常量
常量是固定值,在程序执行期间不会改变。 在 C 中,有两种简单的定义常量的方式: 使用 #define 预处理器。#define identifier value (#define WIDTH 5) 使用 const 前缀声明指定类型的常量。const type variable = value;(const int WIDTH = 5;)
5、存储类
(1)auto 所有局部变量默认的存储类。auto int month;(auto 只能用在函数内,即 auto 只能修饰局部变量)
(2)register 用于定义存储在寄存器中而不是 RAM 中的局部变量。register int miles; (寄存器只用于需要快速访问的变量,比如计数器)
(3)static 存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。 static 修饰符也可以应用于全局变量。static 是全局变量的默认存储类,static int Count;
(4)extern 用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。extern 是用来在另一个文件中声明一个全局变量或函数。extern void write_extern(); extern int count;
6、运算符
(1)算术运算符
(2)关系运算符
(3)逻辑运算符
(4)位运算符
位运算符作用于位,并逐位执行操作。 假设如果 A = 60,且 B = 13,现在以二进制格式表示
A = 0011 1100 B = 0000 1101异或也叫半加运算, 如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。 c
(5)赋值运算符
(6)杂项运算符 ↦ sizeof & 三元
1、判断
C 语言把任何非零和非空的值假定为 true,把零或 null 假定为 false。
(1)判断语句
(2)? : 运算符(三元运算符) 条件?真:假`
2、循环
(1)while 循环
while( a < 20 ) { printf("a 的值: %d\n", a); a++; }(2)for 循环
for( int a = 10; a < 20; a = a + 1 ) { printf("a 的值: %d\n", a); }(3)do…while 循环(确保至少执行一次循环)
do{ printf("a 的值: %d\n", a); a = a + 1; }while( a < 20 );循环控制语句
1、函数
形式
return_type function_name( parameter list ) { body of the function }(1)返回类型:一个函数可以返回一个值。return_type 是函数返回的值的数据类型。不需要返回值,则return_type 是关键字 void。
(2) 函数名称:这是函数的实际名称。函数名和参数列表一起构成了函数签名。
(3)参数:参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
(4)函数主体:函数主体包含一组定义函数执行任务的语句。
例如
int max(int num1, int num2) { /* 局部变量声明 */ int result; if (num1 > num2) result = num1; else result = num2; return result; }2、作用域规则
作用域是程序中定义的变量所存在的区域,超过该区域变量就不能被访问
#include <stdio.h> /* 全局变量声明 */ int g; int main () { /* 局部变量声明 */ int a, b; return 0; }注:形式参数,被当作该函数内的局部变量,它们会优先覆盖全局变量 a比全局的g优先使用
当局部变量被定义时,系统不会对其初始化,您必须自行对其初始化。定义全局变量时,系统会自动对其初始化,
1、数组
可以存储一个固定大小的相同类型元素的顺序集合。 数组符号用大括号{ }
定义一个数组:double balance[5]; 初始化数组:double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};
大括号 { } 之间的值的数目不能大于我们在数组声明时在方括号 [ ] 中指定的元素数目。 如果您省略掉了数组的大小,数组的大小则为初始化时元素的个数
多维数组
/* 一个带有 5 行 2 列的数组 */ int a[5][2] = { {0,0}, {1,2}, {2,4}, {3,6},{4,8}};2、指针
指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。
指针的常规操作:定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值。
赋为 NULL 值的指针被称为空指针(没有确切的地址可以赋值)。
int *ip; /* 一个整型的指针 */ double *dp; /* 一个 double 型的指针 */ float *fp; /* 一个浮点型的指针 */ char *ch; /* 一个字符型的指针 */ #include <stdio.h> int main () { int var1; printf("var1 变量的地址: %p\n", &var1 ); return 0; }打印结果:
var1 变量的地址: 0x7fff5cc109d4
3、字符串
字符串实际上是使用 null 字符 ‘\0’ 终止的一维字符数组。
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; 等价于 char greeting[] = "Hello"; #include <stdio.h> int main () { char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; printf("Greeting message: %s\n", greeting ); return 0; }执行结果:
Greeting message: Hello
字符串操作
1、结构体 使用 struct 语句
存储不同类型的数据项
struct tag { member-list member-list member-list ... } variable-list ;tag 是结构体标签。 member-list是标准的变量定义,比如 int i; 或者 float f,或者其他有效的变量定义。 variable-list结构变量,定义在结构的末尾,最后一个分号之前,您可以指定一个或多个结构变量。
下面是声明 Book 结构的方式: struct Books { char title[50]; char author[50]; char subject[100]; int book_id; } book;
访问时Books.title
在一般情况下,tag、member-list、variable-list 这 3 部分至少要出现 2 个
struct { int a; char b; double c; } s1;或者
struct SIMPLE { int a; char b; double c; };2、共用体 使用 union 语句
共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式。
union Data { int i; float f; char str[20]; } data;3、枚举enum
在程序中,可能需要为某些整数定义一个别名,我们可以利用预处理指令#define来完成这项工作
#define MON 1 #define TUE 2在此,我们定义一种新的数据类型,希望它能完成同样的工作。这种新的数据类型叫枚举型。
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };(1)枚举型是一个集合,集合中的元素(枚举成员)是一些命名的整型常量,元素之间用逗号,隔开。 (2) DAY是一个标识符,可以看成这个集合的名字,是一个可选项,即是可有可无的项。 (3)第一个枚举成员的默认值为整型的0,后续枚举成员的值在前一个成员上加1。 (4)可以人为设定枚举成员的值,从而自定义某个范围内的整数。 (5) 枚举型是预处理指令#define的替代。 (6)类型定义以分号;结束。
4、位域
有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。 例如在存放一个开关量时,只有 0 和 1 两种状态,用 1 位二进位即可。为了节省存储空间,并使处理简便,C 语言又提供了一种数据结构,称为"位域"或"位段"。
所谓"位域"是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。
位域变量名.位域名 位域变量名->位域名
1、C 预处理器
C 预处理器不是编译器的组成部分,但是它是编译过程中一个单独的步骤。简言之,C 预处理器只不过是一个文本替换工具而已,它们会指示编译器在实际编译之前完成所需的预处理。我们将把 C 预处理器(C Preprocessor)简写为 CPP。
所有的预处理器命令都是以井号(#)开头。它必须是第一个非空字符,为了增强可读性,预处理器指令应从第一列开始。下面列出了所有重要的预处理器指令:
2、typedef关键字
使用它来为类型取一个新的名字 以对结构体使用 typedef 来定义一个新的数据类型名字
typedef struct Books { char title[50]; char author[50]; char subject[100]; int book_id; } Book;typedef vs #define
(1)typedef 仅限于为类型定义符号名称,#define 不仅可以为类型定义别名,也能为数值定义别名,比如您可以定义 1 为 ONE。 (2)typedef 是由编译器执行解释的,#define 语句是由预编译器进行处理的。
3、输出&输入
C 语言把所有的设备都当作文件。所以设备(比如显示器)被处理的方式与文件相同。以下三个文件会在程序执行时自动打开,以便访问键盘和屏幕。 文件指针是访问文件的方式,如何从屏幕读取值以及如何把结果输出到屏幕上。
C 语言中的 I/O (输入/输出) 通常使用 printf() 和 scanf() 两个函数。
scanf() 函数用于从标准输入(键盘)读取并格式化, printf() 函数发送格式化输出到标准输出(屏幕)。
#include <stdio.h> int main() { float f; // %f 匹配浮点型数据 scanf("%f",&f); printf("Value = %f", f); return 0; }getchar() 函数从屏幕读取下一个可用的字符,并把它返回为一个整数。 putchar() 函数把字符输出到屏幕上,并返回相同的字符。
#include <stdio.h> int main( ) { int c; c = getchar( ); putchar( c ); return 0; }gets(char *s) 函数从 stdin 读取一行到 s 所指向的缓冲区,直到一个终止符或 EOF。 puts(const char *s) 函数把字符串 s 和一个尾随的换行符写入到 stdout。
#include <stdio.h> int main( ) { char str[100]; gets( str ); puts( str ); return 0; }4、递归
举个例子: 从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?“从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?‘从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?……’”
函数调用自身 例:15 的阶乘
#include <stdio.h> double factorial(unsigned int i) { if(i <= 1) { return 1; } return i * factorial(i - 1); } int main() { int i = 15; printf("%d 的阶乘为 %f\n", i, factorial(i)); eturn 0; }执行结果:
15 的阶乘为 1307674368000.000000
1、内存管理
C 语言为内存的分配和管理提供了几个函数。在 <stdlib.h> 头文件中
注意:void * 类型表示未确定类型的指针。C、C++ 规定 void * 类型可以通过类型转换强制转换为任何其它类型的指针。
2、动态分配内存
(1)编程时,如果您预先知道数组的大小,那么定义数组时就比较容易。例如,一个存储人名的数组,它最多容纳 100 个字符,所以您可以定义数组,char name[100];
(2)如果您预先不知道需要存储的文本长度,例如您向存储有关一个主题的详细描述。在这里,我们需要定义一个指针,该指针指向未定义所需内存大小的字符,后续再根据需求来动态分配内存 注:当动态分配内存时,您有完全控制权,可以传递任何大小的值。而那些预先定义了大小的数组,一旦定义则无法改变大小
(3)重新调整内存的大小和释放内存 当程序退出时,操作系统会自动释放所有分配给程序的内存,但是,建议您在不需要内存时,都应该调用函数 free() 来释放内存。 或者,您可以通过调用函数 realloc() 来增加或减少已分配的内存块的大小。使用 realloc() 和 free() 函数
3、文件操作
C语言具有操作文件的能力,比如打开文件、读取和追加数据、插入和删除数据、关闭文件、删除文件等。
在C语言中,为了统一对各种硬件的操作,简化接口,不同的硬件设备也都被看成一个文件。对这些文件的操作,等同于对磁盘上普通文件的操作。
件操作标准库函数有: 文件的打开操作 fopen 打开一个文件 文件的关闭操作 fclose 关闭一个文件 文件的读写操作 fgetc 从文件中读取一个字符 fputc 写一个字符到文件中去 fgets 从文件中读取一个字符串 fputs 写一个字符串到文件中去 fprintf 往文件中写格式化数据 fscanf 格式化读取文件中数据 fread 以二进制形式读取文件中的数据 fwrite 以二进制形式写数据到文件中去 getw 以二进制形式读取一个整数 putw 以二进制形式存贮一个整数 文件状态检查函数 feof 文件结束 ferror 文件读/写出错 clearerr 清除文件错误标志 ftell 了解文件指针的当前位置 文件定位函数 rewind 反绕 fseek 随机定位
备注:
学C网址:http://c.biancheng.net/c/10/ 菜鸟教程:https://www.runoob.com/cprogramming/c-tutorial.html