c语言基础知识|整理
C语言程序设计·
一、整体要求·
- C语言的特点以及C语言程序的组成:
- C语言主要的数据类型,包括整型、实型、字符型等常量与变量和变量的赋值;理解原码、反码和补码;用
typedef
定义类型; - C语言各种类型数据之间的混合运算;
- C语言算术表达式、关系表达式和逻辑表达式,表达式
sizeof
的含义。
二、知识要点·
1. C 程序的基本结构·
(1)C语言的特点 (2)C程序的基本组成
- 函数是c程序的基本组成单元,由函数头和函数体两部分组成
- 每个 C 程序都至少有一个主函数main()
- 主函数参数:argc 用来统计命令行参数个数,argv 用来存放参数字符串;
- 预处理指令:是在真正编译开始之前由编译器调用的独立程序指令;
- 头文件:调用库功能;加强类型安全检查;<> 适用于工程或标准头文件;"" 适用于自定义头文件;
- 宏定义:用于定义一个标识符常量或带参的宏,本质上是一种文本替换;
2. C语言常量、变量和表达式·
(1) 常量: 数字常量、字符常量和字符串字面量
小写字母比大写字母的ASCII码值大32
(2) 变量: 变量名和变量类型,变量的赋值和类型转换
整数类型
int
可以表示正数、负数和 0,一般是 32 位,在典型实现中表示的范围是 到 。而 unsigned int
表示非负整数,范围是 0 到。
类型 | 存储大小 | 值范围 |
---|---|---|
char | 1 字节 | -128 到 127 或 0 到 255 |
unsigned char | 1 字节 | 0 到 255 |
signed char | 1 字节 | -128 到 127 |
int | 2 或 4 字节 | -32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647 |
unsigned int | 2 或 4 字节 | 0 到 65,535 或 0 到 4,294,967,295 |
short | 2 字节 | -32,768 到 32,767 |
unsigned short | 2 字节 | 0 到 65,535 |
long | 4 字节 | -2,147,483,648 到 2,147,483,647 |
unsigned long | 4 字节 | 0 到 4,294,967,295 |
浮点类型
类型 | 存储大小 | 值范围 | 精度 |
---|---|---|---|
float | 4 字节 | 1.2E-38 到 3.4E+38 | 6 位有效位 |
double | 8 字节 | 2.3E-308 到 1.7E+308 | 15 位有效位 |
long double | 16 字节 | 3.4E-4932 到 1.1E+4932 | 19 位有效位 |
(3) 算术表达式: 算术运算符、增量(自增)和减量(自减)运算符、位运算和复合赋值运算符
常用的位运算符有&
(按位与)、|
(按位或)、^
(按位异或)、~
(按位取反)。
(4) 强制类型转换
-
强制类型转换运算符:(类型名)(表达式) 例如 (int)(x + y) : 将 x+y 的值转换成int型
-
强制类型转换时,得到所需中间数据,原来变量的数据的类型没有发生变化。
-
强制类型转换符优先级高于%运算。
-
优先级:单目运算符 > 算术运算符 > 关系运算符 > 逻辑运算符 条件运算符 > 赋值运算符。
(5)数据输入/输出函数
scanf函数的使用
1 | scanf("%d",&n); |
输出控制符 | 数据类型 |
---|---|
%d | int |
%ld | long int |
%c | char |
%f | float |
%lf | double |
%x(或%X, #x %#X) 2f 2F 0x2f 0X2F |
int 或 long int 或 short int |
%s | 字符串 |
在scanf中,除了char数组整个输入的情况不加&之外,其他变量类型都需要加&。
三种实用的输出格式
(1) %md
%md可以使不足 m 位的 int 型变量以m位进行右对齐输出,其中高位用空格补齐;如果变量本身超过 m 位,则保持原样。
1 | int a = 123, b = 1234567; |
(2) %0md
%0md只是在%md中间多加了0。和%md的唯一不通点在于,当变量不足m位时,将在前面补足够数量的0而不是空格。
(3) %m.nf
%m.nf 指定数据宽度和小数位数,%7.2f指定 输出的数据占7列,其中包括2位小数,注意小数点占一位。
常用math函数
pow(x,y) | 计算x^y的值 |
---|---|
sqrt(x) | 计算x的平方根 |
round(double x) | 将 x 四舍五入 |
floor(x)和 ceil(x) | 计算x的向下取整和向上取整,返回类型为 double 型。 |
fabs(x) | 计算 x(高精度的double,float)的绝对值 |
abs(x) | 计算 x(整数)的绝对值 |
(6)常量的符号表示方法:常量宏、枚举常量
#define
:宏定义,C的一种编译预处理指令。是纯粹的文字替换,不进行类型检查。结尾不加 ;
1 |
const
:定义的常数是变量,也带类型,存在于程序的数据段,并在堆栈中分配了空间。如果一个变量被const修饰,那么它的值就不能再被改变。
3. C语言条件语句和开关语句·
(1) 关系运算符和逻辑运算符
关系运算符:>、<、==、>=、<=、!=
逻辑运算符:!、&&、||
(2)常考运算符优先级·
- 高优先级:()、->、前自增自减;!、寻址、取址、后自增自减;
- 中优先级:乘除;加减;左移右移;比较运算符;
- 低优先级:与;异或;或;逻辑和;逻辑或;
- 最低优先级:逗号。
(3) 逻辑表达式
- 表示逻辑运算结果时,以数值1代表“真” , 以 0 代表“假” 。
a && b && c
只有a为真(非0),才需要判断b的值,只有当a和b都为真的情况下才需要判别c的值。如果a为假就不必判断b和c(此时整个表达式已经确定为假),a为真,b为假,就不用判别c。a || b || c
只要a为真(非0),就不必判断b和c。 只有a为假 ,才判别b。a 和 b都为假才判别c。
(4)条件语句:条件、复合语句、条件语句的嵌套和级联、条件运算符和条件表达式
- 三目运算符:
表达式1 ?表达式2 :表达式3
,表达式1成立返回表达式2的值,否则返回表达式3的值 。
(5) switch
语句
- break 语句的使用: 在每个 case 标签的代码块结束处通常需要使用 break 语句来终止 switch 语句的执行。如果没有 break 语句,程序将会继续执行下一个 case 标签中的代码,直到遇到 break 语句或 switch 语句结束。
- switch 表达式的类型: switch 语句中的表达式必须是整数类型(char、short、int或枚举),或者是能够隐式转换为整数类型的表达式。
- 默认情况的可选性: switch 语句中的 default 标签是可选的。如果没有匹配的 case 标签,则会执行 default 标签下的代码块(如果存在)。
- case 标签的唯一性: 在 switch 语句中,每个 case 标签必须是唯一的,不能有重复的值。
4. C 语言循环语句和 goto 语句·
(1) while 语句、for 语句和 do while 语句
- while是先判断循环条件是否成立,do while是先执行一遍循环体,再进行判断循环条件。
(2)循环语句的选择和使用
(3)逗号表达式
(4)循环语句的嵌套
(5)循环中的非常规控制(break和continue)、goto 语句
- break语句:结束整个循环,不再判断循环条件是否成立。
- continue语句:只结束本次循环,直接执行下一次循环。
5. C 语言函数·
(1) 函数的基本概念
(2) 函数的调用、结构和定义
(3) 函数的调用关系和返回值
(4) 局部变量和全局变量
-
局部变量和全局变量同名,会怎样?
在局部变量的作用范围内,局部变量有效,全局变量被“屏蔽”,即全局变量不起作用。
-
只有 全局变量初始化时 的默认值为0,而 局部变量 默认值是不确定的
-
static声明一个变量的作用是:
1)对局部变量用static声明,把它分配在静态存储区,该变量在整个程序执行期间不释放,其所分配的空间始终存在。 2)对全局变量用static声明,则该变量的作用域只限于本文件模块(即被声明的文件中)。
(5)函数参数的传递
- 传值调用:该方法把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数不会影响实际参数。
- 引用调用:通过指针传递方式,形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。
(6)标准库函数 (7)递归函数
6. C语言数组·
(1) 一维数组:定义和初始化、复制、数组参数·
-
定义数值型数组时未被指定初始化的数组元素,系统自动初始化为0(字符型数组,初始化为’\0’ , 如果是指针型数组,则初始化为NULL,即空指针。)
-
memset通常只用于用于字符数组的初始化, 如果使用memset初始化int数组,初始值只能设为0或-1
1
2
3//void *memset(void *s, int c, unsigned long n);
char a[5];
memset(a,'a',sizeof(a));// "aaaaa" -
动态计算数组的元素个数
1
-
数组存储元素是从所占用的低字节开始存储,而变量的内存寻址是从大到小, 所以存储数据时会从高字节开始存储
-
数组的地址就是数组首个元素的地址,也是数组名的地址。
-
C语言没有数组越界检查,如果访问超过定义的数组长度,结果不可预期,有可能报错,有可能可以访问但访问到的是脏数据。
-
mencpy复制数组
1
2
3
4
5char *s="http://www.runoob.com";
char d[20];
memcpy(d, s+11, 6);// 从第 11 个字符(r)开始复制,连续复制 6 个字符(runoob)
// 或者 memcpy(d, s+11*sizeof(char), 6*sizeof(char));
// d runoob
(2) 字符串和字符数组·
- C语言中没有字符串类型,字符串存放在字符型数组中。
- 字符串结束标志:
'\0'
,存储字符串时会自动加一个'\0'
作为结束符。因此字符串数组长度:数组长度 = 字符串长度 + 1
;
(3) 标准字符串函数·
-
使用字符串处理函数,要在本文件开头添加:#include<string.h>
-
char *strcat(char *dest, char *src)
: 把字符串src添加到dest结尾处(覆盖dest结尾处的’\0’)并添加’\0’ -
char *stpcpy(char *dest, char *src)
: 拷贝一个字符串到另一个,并返回dest -
char *strncpy(char *dest, char *src, int n)
:把字符串src中前n个字符复制到dest中,并返回dest -
i
nt strcmp(char *str1, char *str2)
: str1 > str2,返回一个正整数。 str1 < str2,返回一个负整数。 str1 = str2,返回函数值0。
即:两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇’\0’为止。
-
unsigned int strlen(char *s)
:计算字符串s的长度,不包含’\0’ -
strlwr函数——转换小写字母
-
strupr函数——转换为大写的函数
(4) 二维数组:定义、引用、访问、数组参数·
7. C 语言指针·
(1) 地址与指针
- & 取地址运算符。&a是变量a的地址。
- * 指针运算符(或称“间接访问” 运算符 ),*p代表指针变量p指向的对象。
(2) 指针变量: 定义和赋值、访问、参数和返回值
-
专门用来存放另一变量的地址(即地址)的变量,称为“指针变量”
-
int* p1, p2 ;
* 只会结合第一个变量,即只有p1是int *
型的 -
给指针变量赋值:
1
2int a;
int *p=&a;注意 p 是变量名,类型是
int *
,p存放a的地址,通过*p可以访问a的地址获得a的值。 -
通过指针交换变量值:
1
2
3
4
5void swap(int* a,int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
(3) 指针运算:指针与整数的加减、指针相减和比较、强制类型转换和 void*指针、不合法的指针运算、指针类型与数组类型的差异: (4) 指针与数组
-
数组名可以作为数组首地址使用,即
a = &a[0]
-
数组指针(也称为行指针) 定义为:int( * p)[n]; (注意优先级:()>[]> *)(int (*p)[5]定义了一个指向含有5个元素的一维数组的指针。)当数组指针指向一个一维数组时:
1
2
3int( * p)[n]; //定义了指向含有n个元素的一维数组的指针
int a[n]; //定义数组
p=a; //将一维数组首地址赋值给数组指针p()优先级高,说明p是指针,指向一个整型的一维数组。这个一维数组的长度是n,也可以说p的步长为n。当p+1时,p指针会跨过n个整型数据的长度。
当数组指针指向一个二维数组时:
1
2
3
4int(* p)[4]; //定义了指向含有4个元素的一维数组的指针
int a[3][4];
p=a; //将二维数组的首地址赋值给p,也可是a[0]或&a[0][0]
p++; //表示p跨过行a[0][],指向了行a[1][]所以,数组指针也成为指向一维数组的指针,也就是行指针。
-
指针数组
定义为:int p[n]*; (注意优先级:()>[]> *)
[]> * ,所以p是数组,是一个由n个指针类型元素组成的指针数组,或者说这个当一个数组里含有的元素为指针类型的时候,它就被成为指针数组。当p+1时,则p指向下一个数组元素。(需注意,p=a;这种赋值方法是错的,因为p是一个不可知变量,只存在p[0],p[1],p[2],但可以这样 p=a; 这里p表示指针数组第一个元素的值,a的首地址的值)
将二维数组赋值给指针数组:
1
2
3
4int *p[3]; //定义指针数组
int a[3][4];
for(i=0;i<3;i++)
p[i]=a[i]; //通过循环将a数组每行的首地址分别赋值给p里的元素这里int * p[3]表示一个一维数组内存放三个指针变量,分别是p[1],p[2],p[3]。如果要引用二维数组时,可以有多种表达方式:如表示数组中i行j列一个元素::* (* (p+i)+j)、(* (p+i) )[j]、p[i][j]、 * (p[i]+j)
(5) 指向二维数组的指针、多重指针和指针数组;
(6) 函数指针
动态分配内存·
1 | int * p = (int *)malloc(int len); |
8. C语言结构和联合·
(1) 结构:结构类型的定义和访问、包含结构的结构·
1 | struct s { |
结构体与链表
1 | struct Student { |
(2) 联合union:联合类型的定义和访问
- 各成员共用一块内存空间,并且同时**只有一个成员可以得到这块内存的使用权(对该内存的读写),各变量共用一个内存首地址。**因而,联合体比结构体更节约内存。**一个union变量的总长度至少能容纳最大的成员变量,而且要满足是所有成员变量类型大小的整数倍。
(3) 类型定义语句(typedef)
typedef 用来为一个已有的数据类型定义一个别名,格式为:typedef 原类型名 新类型名
;
可以用于原类型名太长而需要简化的情况,比如:
1 | typedef long long ll; |
枚举类型 enum :
1 | enum Weekday { |
9. 输入/输出和文件·
(1) 输入/输出的基本过程和文件类型
- 数据文件可以分为 ASCII文件(文本文件)和二进制文件(映像文件)
(2) 文件的打开、创建和关闭
-
使用fopen函数来打开文件,fclose来关闭文件。
1
2
3
4//打开文件
FILE * fopen ( const char * filename, const char * mode );
//关闭文件
int fclose ( FILE * stream );
文件使用方式 | 含义 | 如果指定文件不存在 |
---|---|---|
"r"(只读) | 为了输入数据,打开一个已经存在的文本文件 | 出错 |
"w"(只写) | 为了输出数据,打开一个文本文件 | 建立一个新的文件 |
"a"(追加) | 向文本文件尾添加数据 | 建立一个新的文件 |
"rb"(只读) | 为了输入数据,打开一个二进制文件 | 出错 |
"wb"(只写) | 为了输出数据,打开一个二进制文件 | 建立一个新的文件 |
(3) 文件数据的正文(文本)格式读写
-
文件的输出/写入就是将数据写入到文件当中,而文件的输入/读取就是将文件中的内容读取到内存当中。
功能 函数名 适用于 字符输入函数 fgetc 所有输入流 字符输出函数 fputc 所有输出流 文本行输入函数 fgets 所有输入流 文本行输出函数 fputs 所有输出流 格式化输入函数 fscanf 所有输入流 格式化输出函数 fprintf 所有输出流 二进制输入 fread 文件 二进制输出 fwrite 文件
(4) 读写操作中的定位
(5) 文件数据的二进制格式读写
C语言程序从编写到运行历经的几个阶段
预处理
预处理过程实质上是处理“#”,将#include包含的头文件直接拷贝到hell.c当中;将#define定义的宏进行替换,同时将代码中没用的注释部分删除等
编译
编译的过程实质上是把高级语言翻译成汇编语言
汇编(Assembly) 汇编阶段是将汇编语言代码转换成目标文件的过程。这个阶段由汇编器完成,它会将汇编语言代码转换成机器代码,
链接(Linking) 链接阶段是将多个目标文件和库文件合并成一个可执行文件的过程。