C基础班讲义
2020-4-16 2:37 作者:酷帥王子 | c/c++黑客编程 |
C基础班讲义
朱景尧
目 录
1............................ 第一个c语言的hello world
1.1.............................................. include头文件包含
1.2................................................................ main函数
1.3............................................................................ 注释
1.4..................................................... {}括号和代码块
1.5............................................................................ 声明
1.6...................................... C语言自定义名字的要求
1.7............................................................. return语句
2.................................................... C语言的编译
2.1................................................................... 编译过程
2.2........................................................... gcc编译选项
2.3...................................................... printf执行原理
2.4............................................. CPU32位64位简介
3.......................................... C语言中的数据类型
3.1............................................................................ 常量
3.1.1................................................................ #define
3.1.2..................................................................... const
3.2............................................................... 字符串常量
3.3.......................................................... 位,字节,字
3.3.1............................................................................ 位
3.3.2................................................................... 二进制
3.3.3................................................................... 十进制
3.3.4................................................................... 八进制
3.3.5............................................................... 十六进制
3.3.6........................................................................ 字节
3.4.......................................................... sizeof关键字
3.5................ 十进制,二进制,八进制,十六进制
3.6..................................................................... int类型
3.6.1.................................................... int常量,变量
3.6.2............................................... printf输出int值
3.6.3......................... printf输出八进制和十六进制
3.6.4.. short,long,long long,unsigned int
3.6.5............................................................... 整数溢出
3.7................................................................. char类型
3.7.1................................................ char常量,变量
3.7.2................................................. printf输出char
3.7.3....................................... 不可打印char转义符
3.7.4................................... char和unsigned char
3.8.............. 浮点float,double,long double类型
3.8.1.................................................. 浮点常量,变量
3.8.2.............................................. printf输出浮点数
3.9................................................................... 类型限定
3.9.1..................................................................... const
3.9.2................................................................. volatile
3.9.3................................................................ register
4................................... 字符串格式化输出和输入
4.1......................... 字符串在计算机内部的存储方式
4.2................................. printf函数,putchar函数
4.3................................ scanf函数与getchar函数
5.......................................... 运算符表达式和语句
5.1............................................................... 基本运算符
5.1.1............................................................................. =
5.1.2............................................................................. +
5.1.3.............................................................................. –
5.1.4.............................................................................. *
5.1.6........................................................................... %
5.1.7.......................................................................... +=
5.1.8........................................................................... -=
5.1.9.......................................................................... *=
5.1.10.......................................................................... =
5.1.11..................................................................... %=
5.1.12....................................................................... ++
5.1.13.......................................................................... --
5.1.14........................................................ 逗号运算符
5.1.15.................................................... 运算符优先级
5.2................................................................... 复合语句
5.3................................................................... 类型转化
6.................................................... 条件分支语句
6.1............................................................... 关系运算符
6.1.1............................................................................. <
6.1.2.......................................................................... <=
6.1.3............................................................................. >
6.1.4.......................................................................... >=
6.1.5.......................................................................... ==
6.1.6............................................................................ !=
6.2.................................................. 关系运算符优先级
6.3............................................................... 逻辑运算符
6.3.1.......................................................................... &&
6.3.2........................................................................... ||
6.3.3............................................................................... !
6.4.................................................................................. if
6.5........................................................................ if else
6.6.................................................................... if else if
6.7.................................... switch与break,default
6.8.......................................................... 条件运算符?
6.9.................................................... goto语句与标号
7........................................................... 循环语句
7.1......................................................................... while
7.2.................................................................. continue
7.3........................................................................ break
7.4................................................................... do while
7.5.............................................................................. for
7.6................................................................... 循环嵌套
8............................ 整数在计算机内部的存储方式
8.1............................................................................ 原码
8.2............................................................................ 反码
8.3............................................................................ 补码
9.................................................................. 数组
9.1.............................................. 一维数组定义与使用
9.2.......................................... 数组在内存的存储方式
9.3...................................................... 一维数组初始化
9.4.............................................. 二维数组定义与使用
9.5...................................................... 二维数组初始化
10........................................... 字符串与字符数组
10.1........................................................ 字符数组定义
10.2................................................... 字符数组初始化
10.3........................................................ 字符数组使用
10.4....................... 随机数产生函数rand与srand
10.5.......................................... 用scanf输入字符串
10.6............................................... 字符串的结束标志
10.7................................................... 字符串处理函数
10.7.1.................................................................... gets
10.7.2......................................................... fgets函数
10.7.3........................................................... puts函数
10.7.4......................................................... fputs函数
10.7.5........................................ strlen,字符串长度
10.7.6....................................... strcat,字符串追加
10.7.7............................ strncat,字符串有限追加
10.7.8..................................... strcmp,字符串比较
10.7.9.......................... strncmp,字符串有限比较
10.7.10....................................... strcpy字符串拷贝
10.7.11............................ strncpy字符串有限拷贝
10.7.12............................... sprintf,格式化字符串
10.7.13............................................ strchr查找字符
10.7.14............................................. strstr查找子串
10.7.15........................................ strtok分割字符串
10.7.16.............................................. atoi转化为int
10.7.17......................................... atof转化为float
10.7.18........................................... atol转化为long
11................................................................ 函数
11.1............................................... 函数的原型和调用
11.2............................................... 函数的形参与实参
11.3................................... 函数的返回类型与返回值
11.4...................................... main函数与exit函数
11.5............................................................ 函数的递归
11.5.1............................................... 递归的过程分析
11.5.2........................................................ 递归的优点
11.5.3........................................................ 递归的缺点
11.6.............................. 多个源代码文件程序的编译
11.6.1.................................................... 头文件的使用
11.6.2....................... #include与#define的意义
11.6.3........................................... #ifndef与#endif
11.7............................................... 函数的二进制封装
11.7.1........................................ exe加载dll的说明
11.7.2.............. 动态库中代码与位置无关的说明图
11.7.3............................. linux编写so文件的方式
11.7.4.................................................... linux使用so
11.7.5.. 配置profile文件可以在当前目录下查找so文件
11.8................................................................ 作业描述
12................................................................ 指针
12.1......................................................................... 指针
12.1.1........................................................ 指针的概念
12.1.2............................................... 指针变量的定义
12.1.3.................................................................. NULL
12.1.4................................................................ 野指针
12.1.5................................................ &取地址运算符
12.1.6........................................................ 无类型指针
12.1.7.................................................... 指针的兼容性
12.1.8........................................... 指针与数组的关系
12.1.9................................... 通过指针使用数组元素
12.1.10.......................................................... 指针数组
12.1.11.......................................................... 数组指针
12.1.12.................... 指向指针的指针(二级指针)
12.1.13............................ 指针变量做为函数的参数
12.1.14............................ 一维数组名作为函数参数
12.1.15............................ 二维数组名作为函数参数
12.1.16.................................... 指向二维数组的指针
12.1.17........................ 指向常量的指针与指针常量
12.1.18........................ const关键字保护数组内容
12.1.19................................ 指针做为函数的返回值
12.1.20............................................. 指向函数的指针
12.1.21........... 把指向函数的指针做为函数的参数
12.1.22.......................................................... 指针运算
12.1.23.......................................................... 指针小结
13........................................... 字符指针与字符串
13.1........................................................ 指针和字符串
13.2................................... 通过指针访问字符串数组
13.3.......................................... 函数的参数为char *
13.4...................... 指针数组做为main函数的形参
14......................................................... 内存管理
14.1.................................................................... 作用域
14.1.1.................................................. auto自动变量
14.1.2...................................... register寄存器变量
14.1.3............................... 代码块作用域的静态变量
14.1.4.......................... 代码块作用域外的静态变量
14.1.5............................................................ 全局变量
14.1.6........................... 外部变量与extern关键字
14.1.7....................................... 全局函数和静态函数
14.2................................................................ 内存四区
14.2.1................................................................ 代码区
14.2.2................................................................ 静态区
14.2.3..................................................................... 栈区
14.2.4..................................................................... 堆区
14.3................................................... 堆的分配和释放
14.3.1................................................................ malloc
14.3.2..................................................................... free
14.3.3................................................................ calloc:
14.3.4............................................................... realloc
15.................. 结构体,联合体,枚举与typedef
15.1.................................................................... 结构体
15.1.1......................... 定义结构体struct和初始化
15.1.2............................................... 访问结构体成员
15.1.3................................... 结构体的内存对齐模式
15.1.4............................... 指定结构体元素的位字段
15.1.5............................................................ 结构数组
15.1.6............................................................ 嵌套结构
15.1.7.................................................... 结构体的赋值
15.1.8........................................... 指向结构体的指针
15.1.9................................... 指向结构体数组的指针
15.1.10.................... 结构中的数组成员和指针成员
15.1.11.................................... 在堆中创建的结构体
15.1.12.................................... 将结构作为函数参数
15.1.13........................ 结构,还是指向结构的指针
15.1.14............................................. 远指针与近指针
15.2.................................................................... 联合体
15.3................................................................ 枚举类型
15.3.1............................................................ 枚举定义
15.3.2................................................................ 默认值
15.4................................................................. typedef
15.5............................. 通过typedef定义函数指针
16......................................................... 文件操作
16.1...................................................................... fopen
16.2................................... 二进制和文本模式的区别
16.3..................................................................... fclose
16.4............................................... getc和putc函数
16.5................................ EOF与feof函数文件结尾
16.6.................... fprintf,fscanf,fgets,fputs函数
16.7............................................................... stat函数
16.8............................................................ fseek函数
16.9............................................................... ftell函数
16.10.................................... fgetpos,fsetpos函数
16.11......................................................... fflush函数
16.12....................................... fread和fwrite函数
16.13..................................................... fread与feof
16.14...................................................................... 作业
17....................................... 基础数据结构与算法
17.1................................................... 什么是数据结构
17.2............................................................ 什么是算法
17.3......................................................................... 链表
17.3.1.................................................... 单向链表定义
17.3.2................................... 单向链表数据结构定义
17.3.3............................................... 单向链表的实现
17.4......................................................................... 查找
17.4.1............................................................ 顺序查找
17.4.2............................................................ 二分查找
17.5......................................................................... 排序
17.5.1............................................................ 冒泡排序
17.5.2............................................................ 选择排序
1 第一个c语言的hello world
1.1 include头文件包含
头文件包含,写法#include <文件名>,
1.2 main函数
这个就是C语言程序的入口,所有的C程序都是从main开始执行,一个C的源程序必须有一个main函数,也只能有一个main函数
1.3 注释
//注释一行
/* */代表块注释,可以注释多行代码
1.4 {}括号和代码块
代表一个代码单元
1.5 声明
C语言规定,所有的变量和函数必须先声明,然后才能使用.
1.6 C语言自定义名字的要求
可以使用大小写字母,下划线,数字,但第一个字母必须是字母或者下划线
字母区分大小写
变量名最好用英文,而且要有所含义,通过变量的名称就能猜测变量的意思。
1.7 return语句
在C语言当中任何函数遇到return代表这个函数停止,当main函数遇到return,代表整个程序退出
return代表函数的返回值,如果返回类型是void,可以直接写return,而不需要返回任何值
2 C语言的编译
2.1 编译过程
2.2 gcc编译选项
-o代表指定输出文件名
-E代表预编译
预编译处理include的本质就是简单的将include中的文件替换到c文件中
如果include包含的头文件在系统目录下,那么就用#include <>,如果包含的文件在当前目录下,那么用#inlclude “”
-S代表汇编
-c代表编译
2.3 printf执行原理
2.4 CPU32位64位简介
一个字节是8个bit,一个字是两个字节,整型4个字节
8位寄存器
AL 00000000 256
16位寄存器
AX AL AH
0000000000000000
1111111111111111
四个通用寄存器
AX
BX
CX
DX
32位寄存器
EAX 0000000000000000000000000000000000000000000000 1111111111111111111111111111111111
EBX
ECX
EDX
64位寄存器
REAX
REBX
RECX
REDX
3 C语言中的数据类型
重点:**
3.1 常量
常量就是在程序中不可变化的量,常量是不可被赋值的。
3.1.1 #define
#define的本质就是简单的文本替换
通过#define定义的常量,在C语言里面一般叫宏定义
3.1.2 const
const定义一个变量,但是这个变量的值只能在定义的时候赋予,之后就不可以修改。
对于const类型的变量,一定要在定义的时候给变量赋初值,不然定义之后就无法赋值了。
3.2 字符串常量
在C语言当中“”引用的字符串都是字符串常量,常量一旦定义也是不可以被修改的。
3.3 位,字节,字
3.3.1 位
计算机内部都是二进制的,一个二进制的位,就叫做一个bit,就是一位
3.3.2 二进制
逢二加1,在二进制表达数的时候是只有0和1,而没有2这个数的
二进制最大表示的数,就是2几次幂
对于8位的CPU来讲,最大表达的数是2的8次幂
3.3.3 十进制
逢10加1,只有从0 到9的数,没有10这个数,
3.3.4 八进制
从0到7,逢8加1
在C语言中八进制是数字前面加0
3.3.5 十六进制
0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,10
逢16加1,
在C语言当中表达一个十六进制数的方式,数字前面加0x前缀
3.3.6 字节
8个bit为代表一个字节
3.4 sizeof关键字
sizeof与size_t类型
sizeof是计算数据在内存当中占多大空间的,单位字节
由于sizeof永远返回的是一个大于等于0的整数,所以如果用int来表示sizeof的返回值就不合适,size_t一般就是一个无符号的整数.
3.5 十进制,二进制,八进制,十六进制
3.6 int类型
3.6.1 int常量,变量
一个int型数据占据4个字节的内存大小,在16位操作系统下,int是2个字节,在32和64位操作系统下,int是4个字节。
int a;//代表在内存当中开辟一个4个字节大小的空间
a = 10;//代表4个字节的空间内容是常量10
小端对齐和大端对齐
高地址放高位,底地址放低位---小端对齐
高地址放低位,底地址放高位—大端对齐
对于大型unix CPU都是按照大端对齐方式处理int,
但对于x86构架CPU,还有ARM,是小端对齐的
3.6.2 printf输出int值
int a = 0x100;//十六进制
printf(“%d”,a);%d的意思是按照10进制打印一个整数
%x
%X,输出十六进制的时候是用大写的ABCDEF还是小写的abcdef,
3.6.3 printf输出八进制和十六进制
%o
3.6.4 short,long,long long,unsigned int
在32位系统下:
short = 2个字节
long和int一样,是4字节
long long 是8个字节
在64位操作系统下
int,4个字节
long 在大多数64位系统下8个字节
unsigned int//无符号整数
unsigned long//无符号的长整数
unsigned short//无符号短整数
9l,9L,9ll,9LL,9u,9ull,9ULL
3.6.5 整数溢出
当把一个大的整数赋值给小的整数,叫溢出。
int I = 0x12345678
short a = I;
当一个int赋值给short,会将高位抛弃,
3.7 char类型
3.7.1 char常量,变量
char是字符型,代表一个字节的内存
char在内存当中,有符号最大7f,
无符号,最大ff
unsigned char
char的本质就是一个字节,一个BYTE
3.7.2 printf输出char
%c
3.7.3 不可打印char转义符
\a,警报
\b退格
\n换行
\r回车
\t制表符
\\斜杠
\’单引号
\”双引号
\?问号
3.7.4 char和unsigned char
char取值范围为-128到127
unsigned char为0-255
3.8 浮点float,double,long double类型
3.8.1 浮点常量,变量
float f = 2.5;
double f1 = 3.1415926
3.8.2 printf输出浮点数
%f,%Lf
3.9 类型限定
3.9.1 const
const限定一个变量的值不可以改变
3.9.2 volatile
告诉编译器不要自作聪明的给我优化代码,把我的变量优化的寄存器里面计算,只要是volatile类型变量,每一步都需要从内存当中读取。
3.9.3 register
register告诉编译器,这个变量只是用寄存器就好,提高效率,所以说register只是一个建议,而不是必须的结果。
4 字符串格式化输出和输入
重点:*
4.1 字符串在计算机内部的存储方式
字符串是内存中一段连续的char空间,以’\0’结尾
字符串就是0结尾的连续char的内存
4.2 printf函数,putchar函数
printf格式字符
字符 |
对应数据类型 |
含义 |
d |
int |
接受整数值并将它表示为有符号的十进制整数 |
hd |
Short int |
短整数 |
hu |
Unsigned short int |
无符号短整数 |
o |
unsigned int |
无符号8进制整数 |
u |
unsigned int |
无符号10进制整数 |
x / X |
unsigned int |
无符号16进制整数,x对应的是abcdef,X对应的是ABCDEF |
f |
float或double |
|
e / E |
double |
科学计数法表示的数,此处"e"的大小写代表在输出时用的“e”的大小写 |
c |
char |
|
s / S |
char * / wchar_t * |
字符串。输出字符串中的字符直至字符串中的空字符(字符串以'\0‘结尾,这个'\0'即空字符) |
p |
void * |
以16进制形式输出指针 |
% |
% |
输出一个百分号 |
printf附加格式
字符 |
含义 |
l |
附加在d,u,x,o前面,表示长整数 |
- |
左对齐 |
m(代表一个整数) |
数据最小宽度 |
0 |
将输出的前面补上0 |
N(代表一个整数) |
宽度至少为n位 |
printf是打印一个字符串
putchar是打印一个字符
4.3 scanf函数与getchar函数
5 运算符表达式和语句
重点:***
5.1 基本运算符
5.1.1 =
数据对象:泛指数据在内存的存储区域
左值:表示可以被更改的数据对象
右值:能赋给左值的量
5.1.2 +
5.1.3 –
5.1.4 *
5.1.5 /
5.1.6 %
取模,取余数
5.1.7 +=
int a = 10;
a = a + 5;
可以简写成a += 5;
5.1.8 -=
a = a – 5;a -= 5;
5.1.9 *=
a = a * 5;a *= 5;
5.1.10 /=
5.1.11 %=
5.1.12 ++
笔试面试特别容易考,也是特别容易出错的地方
5.1.13 --
5.1.14 逗号运算符
int I = 6 + 5, 3 + 2
逗号表达式先求逗号左边的值,然后求右边的值,整个语句的值是逗号右边的值。
5.1.15 运算符优先级
优先级 |
运算符 |
结合性 |
1 |
++(后缀),--(后缀),()(调用函数),{}(语句块),.,-> |
从左到右 |
2 |
++(前缀),--(前缀),+(前缀),-(前缀),!(前缀),~(前缀),sizeof,*(取指针值),&(取地址),(type)(类型转化) |
从右到左 |
3 |
*, /, % |
从左到右 |
4 |
+,- |
从左到右 |
5 |
<< >> |
从左到右 |
6 |
< > <= >= |
从左到右 |
7 |
== != |
从左到右 |
8 |
& |
从左到右 |
9 |
^ |
从左到右 |
10 |
| |
从左到右 |
11 |
&& |
从左到右 |
12 |
|| |
从左到右 |
13 |
? |
从右到左 |
14 |
=,*=,%=,+=,-=,<<=,>>=,&=,|=,^= |
从右到左 |
15 |
,(逗号运算符) |
从左到右 |
5.2 复合语句
{}代码块
5.3 类型转化
double d = 10.2;
int a = d;//隐式转换
int a1 = 3;
int a2 = 2;
double mid = (double)a1 / (double)a2;//显示的强转
printf("mid = %f\n", mid);
6 条件分支语句
重点:***
6.1 关系运算符
在C语言中0代表假,非0代表真,
在计算机程序判断是根据一个条件返回是真还是假来做不同的操作。
6.1.1 <
6.1.2 <=
6.1.3 >
6.1.4 >=
6.1.5 ==
一个=号在C语言里面是赋值的,不是比较的,但是很多初学者爱犯一个严重的错误,就是用=号来比较两个数是否相等
6.1.6 !=
!=
6.2 关系运算符优先级
前四种相同,后两种相同,前四种高于后两种优先级
6.3 逻辑运算符
6.3.1 &&
逻辑与
6.3.2 ||
逻辑或
6.3.3 !
逻辑非
6.4 if
6.5 if else
两路分支if语句,只可能执行一路,不可能同时执行两路,也不可能两路都没有被执行
6.6 if else if
if else if 这种于语法可以实现多路的分支,但只有一路被执行。
else永远是和最近的一条if语句配对。
6.7 switch与break,default
switch是为多重选择准备的,遇到break语句,switch就终端执行
6.8 条件运算符?
一个求绝对值的例子
int i = -8; int x = (i < 0) ? -i: i; |
?号用法
当?号 前面括号内容为真的时候,执行?号之后冒号之前的语句,否则执行冒号之后的语句
6.9 goto语句与标号
尽量不要在程序当中使用goto语句,
7 循环语句
重点:***
7.1 while
while(条件),如果条件为真,那么循环就执行,否则循环退出
7.2 continue
continue意思是跳过下面语句,继续执行循环
7.3 break
break中断循环,
7.4 do while
do
语句
while (条件);
对于do while来讲,至少能执行一次,
7.5 for
可以指定循环次数的语句
7.6 循环嵌套
特别需要掌握的技术,
8 整数在计算机内部的存储方式
重点:****
8.1 原码
将最高位做为符号位(0代表正,1代表负),其余各位代表数值本身的绝对值
+7的原码是00000111 -7的原码是10000111 +0的原码是00000000 -0的原码是10000000
|
8.2 反码
一个数如果值为正,那么反码和原码相同
一个数如果为负,那么符号位为1,其他各位与原码相反
+7的反码00000111 -7的反码11111000 -0的反码11111111 |
8.3 补码
原码和反码都不利于计算机的运算,如:原码表示的7和-7相加,还需要判断符号位。
正数:原码,反码补码都相同
负数:最高位为1,其余各位原码取反,最后对整个数 + 1
-7的补码:= 10000111(原码) 111111000(反码) 11111001(补码) +0的补码为00000000 -0的补码也是00000000 |
补码符号位不动,其他位求反,最后整个数 + 1,得到原码
用补码进行运算,减法可以通过加法实现 |
7-6=1 7的补码和-6的补码相加:00000111 + 11111010 = 100000001 进位舍弃后,剩下的00000001就是1的补码 |
-7+6 = -1 -7的补码和6的补码相加:11111001 + 00000110 = 11111111 11111111是-1的补码 |
9 数组
重点:**
内存连续,并且是同一种数据类型的变量,C语言的数组小标好是从0开始的,到n-1.
9.1 一维数组定义与使用
类型 变量名称[数组元素的个数];
9.2 数组在内存的存储方式
在内存当中是连续的内存空间地址。
9.3 一维数组初始化
int array[10] = {0};//将数组所有元素都初始化为0
int array[10] = {0,1,2,3,4,5,6,7,8,9}
数组中找最大值思路
数组中找第二大值思路
逆置数组思路
测量楼宇高度的说明
测量地球太阳距离的说明
测量太阳木星距离的说明
9.4 二维数组定义与使用
int array[3][4];//12个元素的二维数组
9.5 二维数组初始化
int a[3][4] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }; |
10 字符串与字符数组
重点:***
10.1 字符数组定义
char buf[100];
对于C语言字符串其实就是一个最后一个元素为’\0’的char数组.
10.2 字符数组初始化
char buf[] = “hello world”;
10.3 字符数组使用
10.4 随机数产生函数rand与srand
头文件stdlib.h
#include <time.h> int t = (int)time(NULL); srand(t); for (int i = 0; i < 10; i++) { printf("%d\n", rand()); } |
|
10.5 用scanf输入字符串
char buf[100] = {0};
scanf(“%s”, buf);
scanf("请输入i的值%d", &i);
10.6 字符串的结束标志
10.7 字符串处理函数
10.7.1 gets
gets没有解决缓冲区溢出的问题.
10.7.2 fgets函数
gets函数不检查预留缓冲区是否能够容纳用户实际输入的数据。多出来的字符会导致内存溢出,fgets函数改进了这个问题。
由于fgets函数是为读取文件设计的,所以读取键盘时没有gets那么方便
char s[100] = { 0 }; fgets(s, sizeof(s), stdin); |
10.7.3 puts函数
puts函数打印字符串,与printf不同,puts会在最后自动添加一个’\n’
char s[] = "hello world"; puts(s); |
10.7.4 fputs函数
fputs是puts的文件操作版本,
char s[] = "hello world"; fputs(s, stdout); |
10.7.5 strlen,字符串长度
strlen返回字符串的长度,但是不包含字符串结尾的’\0’
char buf[10]
sizeof(buf);//返回的是数组buf一共占据了多少字节的内存空间.
10.7.6 strcat,字符串追加
char str1[100];
char str2[100];
strcat(str1, str2);//把str2追加到str1的后面
str1一定要有足够的空间来放str2,不然会内存溢出.
10.7.7 strncat,字符串有限追加
strncat(str1, str2, sizeof(str1) – strlen(str1) - 1);
10.7.8 strcmp,字符串比较
strcmp(a, “str”);//如果两个参数所指的字符串内容相同,函数返回0
10.7.9 strncmp,字符串有限比较
strncmp(str, “exit”, 4);
10.7.10 strcpy字符串拷贝
strcpy(str, “hello world”);//存在溢出的问题,
10.7.11 strncpy字符串有限拷贝
strcpy(str, “hello world”, 7);
10.7.12 sprintf,格式化字符串
printf是向屏幕输出一个字符串
sprintf是向char数组输出一个字符串,其他行为和printf一模一样
sprintf也存在缓冲区溢出的问题
10.7.13 strchr查找字符
strchr(str, ‘c’);
返回值是字符’c’在字符串str中的位置
10.7.14 strstr查找子串
10.7.15 strtok分割字符串
字符在第一次调用时strtok()必需给予参数s字符串,往后的调用则将参数s设置成NULL每次调用成功则返回指向被分割出片段的指针
char buf[] = "abc@defg@igk"; char *p = strtok(buf, "@");; while (p) { printf("%s\n", p); p = strtok(NULL, "@"); } |
10.7.16 atoi转化为int
10.7.17 atof转化为float
10.7.18 atol转化为long
作业说明:
不可以用任何已有的函数,完全自己写代码,完成十进制字符串转化为十进制的整数
作业思路:
11 函数
重点***
11.1 函数的原型和调用
在使用函数前必须定义或者声明函数
double circle(double r); int main() { double length = circle(10); printf("length = %f\n", length); return 0; }
double circle(double r) { return 2 * 3.14 * r; } |
11.2 函数的形参与实参
在调用函数的时候,函数大多数都有参数,主调函数和被调用函数之间需要传递数据。
在定义函数时函数名后面括弧中的变量名称为“形式参数”,简称形参。在调用函数时,函数名后面括号中的变量或表达式称为“实际参数”,简称实参。
1形参在未出现函数调用时,他们并不占用内存单元,只有在发生函数调用的时候形参才被分配内存,函数调用完成后,形参所占的内存被释放
2实参可以是变量,常量或者表达式
3在定义函数时,一定要指定形参的数据类型
4形参与实参的数据类型一定要可兼容
5在C语言中,实参与形参的数据传递是“值传递”,即单向传递,只由实参传递给形参,而不能由形参传递给实参。
11.3 函数的返回类型与返回值
1函数的返回值通过函数中的return获得,如果函数的返回值为void可以不需要return语句。
2函数return语句中的返回值数据类型应该与函数定义时相同。
3如果函数中没有return语句,那么函数将返回一个不确定的值。
11.4 main函数与exit函数
在main函数当中遇到return语句,代表整个程序结束。在子函数当中遇到return代表子函数结束。
不论程序的任何位置调用exit函数,代表整个程序退出。
函数的学习难点是递归
11.5 函数的递归
函数可以调用自己,这就叫函数的递归
void recurse(int i) { if (i > 0) { recurse(i - 1); } printf("i = %d\n", i); }
int main() { recurse(10); return 0; } |
11.5.1 递归的过程分析
void up_down(int n) { printf("in %d, location %p\n", n, &n); if (n < 4) up_down((n + 1)); printf("out %d, location %p\n", n, &n); }
int main() { up_down(1); return 0; } |
有n个人排成一队,问第n个人多少岁,他回答比前面一个人大2岁,再问前面一个人多少岁,他回答比前面一个人大2岁,一直问到最后问第一个人,他回答10岁
int age(int n) { int i; if (n == 1) i = 10; else i = age(n - 1) + 2; return i; } |
将10进制数转化为二进制数的例子
234在十进制下为2 * 10的2次方 + 3 * 10的1次方 + 4*10的0次方。
奇数的二进制最后一位一定是1,偶数的二进制最后一位一定是0。
可以通过 number % 2 得到二进制形式的最后一位,如果要将一个完整的整数转化为二进制就需要用到递归函数。
在递归调用之前,计算 number % 2的值,然后在递归调用语句之后进行输出,这样计算出的第一个数值反而在最后一个输出。
为了得出下一个数,需要把原数除以2,这种计算相当于十进制下把小数点左移一位,如果此时得出的数是偶数,,则下一个二进制的数值是0,如果得出的是奇数,那么下一个二进制数为1。
直到被2除的结果小于2,就停止递归。
void to_binary(unsigned int n) { unsigned int i = n % 2; if (n >= 2) to_binary(n / 2); printf("%c", i + 0x30); } |
斐波那契数列例子
斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...
第0项是0,第1项是第一个1。
这个数列从第2项开始,每一项都等于前两项之和。
int fib(int n) { if (n == 0) return 0; if (n == 1) return 1; if (n > 1) return fib(n - 1) + fib(n - 2); } |
汉诺塔的例子
有三根针1,2,3。1针上有4个盘子,盘子大小不等,大的在下,小的在上,
要求把这4个盘子从1针一到3针,在移动过程中可以借助2针,每次只允许移动一个盘子,并且在移动过程中在三根针上都要保持大盘子在下,小盘子在上。
可以分为以下步骤:
1、将1针上n-1个盘借助3针移动到2针上;
2、将1针上剩下的一个盘移动到3针上;
3、将n-1个盘从2针借助1针移动到3针上。
void hanoi(int n, int one, int two, int three) { if (n == 1) printf("%d->%d\n", one, three); else { hanoi(n - 1, one, three, two); printf("%d->%d\n", one, three); hanoi(n - 1, two, one, three); } } |
11.5.2 递归的优点
递归给某些编程问题提供了最简单的方法
11.5.3 递归的缺点
一个有缺陷的递归会很快耗尽计算机的资源,递归的程序难以理解和维护。
11.6 多个源代码文件程序的编译
11.6.1 头文件的使用
如果把main函数放在第一个文件中,而把自定义函数放在第二个文件中,那么就需要在第一个文件中声明函数原型。
如果把函数原型包含在一个头文件里,那么就不必每次使用函数的时候都声明其原型了。把函数声明放入头文件是很好的习惯。
11.6.2 #include与#define的意义
11.6.3 #ifndef与#endif
11.7 函数的二进制封装
11.7.1 exe加载dll的说明
11.7.2 动态库中代码与位置无关的说明图
11.7.3 linux编写so文件的方式
1首先gcc编译的时候要加-fPIC选项,-fPIC是告诉gcc生成一个与位置无关的代码
2gcc链接的时候要加-shared选项,意思是生成一个so共享库。
对于linux或者unix,一个so文件,文件扩展名必须是so,文件名的前三个字母必须是lib
11.7.4 linux使用so
gcc链接的时候需要加-L. 代表从当前目录下找相关的so文件,-l文件名(但不包括文件名开头的lib和扩展名so)
例如编译一个main.o文件,要用到当前目录下的liba.so库
gcc –o main.out –L. –la main.o
11.7.5 配置profile文件可以在当前目录下查找so文件
linux不在当前目录下寻找可执行程序,同时也不早当前目录下找so库文件
修改用户配置文件的方法
1
cd
2
vi .bash_profile
3
export LD_LIBRARY_PATH = $LD_LIBRARY_PATH:.
4
保存退出
5
. .bash_profile
11.8 作业描述
int sum1(int n);//n = 10 0,1,2,3,4,5,6,7,8,9,10的和
要求不可以用循环,只可以用递归
int sum2(int n);//n = 10 从0到n范围内所有素数的和
要求不可以用循环,只可以用递归
12 指针
重点:*****
12.1 指针
12.1.1 指针的概念
指针也是一个变量,做为指针变量的值是另一个变量的地址。
指针存放的内容是一个地址,该地址指向一块内存空间
12.1.2 指针变量的定义
可以定义一个指向一个变量的指针变量。
int *p;//表示定义一个指针变量。
*p;//代表指针所指内存的实际数据
切记,指针变量只能存放地址,不能将一个int型变量直接赋值给一个指针。
int *p = 100;
12.1.3 NULL
一个指向NULL的指针,我们称之为空指针,意味着这个指针不指向任何一个变量。
12.1.4 野指针
定义之后没有初始化值的指针
12.1.5 &取地址运算符
12.1.6 无类型指针
定义一个指针变量,但不指定它指向具体哪种数据类型。可以通过强制转化将void *转化为其他类型指针,也可以用(void *)将其他类型指针强制转化为void类型指针。
void *p
在C语言当中,可以将任何一种地址赋值给void *指针
12.1.7 指针的兼容性
指针之间赋值比普通数据类型赋值检查更为严格,例如:不可以把一个double *赋值给int *
12.1.8 指针与数组的关系
一个变量有地址,一个数组包含若干个元素,每个元素在内存中都有地址。
int a[10];
int *p = a;
比较p和&a[0]的地址是否相同
在C语言当中数组的名称代表数组的首地址,如果取数组名称的地址,C语言认为就是取数组的首地址。
12.1.9 通过指针使用数组元素
通过指针计算,不是把指针当做一个整数,计算结果,而是指针在内存当中移动
p + 1代表&a[1],也可以直接使用p[1]表示a[5]
p + 5 代表&a[5]
p++
在C语言里面数组名称是个常量,值是不可改变的
12.1.10 指针数组
int *p[5];
12.1.11 数组指针
int (*P)[5];
12.1.12 指向指针的指针(二级指针)
指针就是一个变量,既然是变量就也存在内存地址,所以可以定义一个指向指针的指针。
int i = 10;
int *p1 = &i;
int **p2 = &p1;
printf("%d\n", **p2);
以此类推可以定义3级甚至多级指针。
12.1.13 指针变量做为函数的参数
函数的参数可以是指针类型。,它的作用是将一个变量的地址传送给另一个函数。
12.1.14 一维数组名作为函数参数
当数组名作为函数参数时,C语言将数组名解释为指针
当数组名作为函数参数传递给被调用函数时,被调用函数是不知道数组有多少元素的
int func(int array[10]);
相当于传递是一个地址,那么就可以通过地址来修改实参的值。
只要传递是数组名,那么形参一定可以通过地址修改实参的值。
12.1.15 二维数组名作为函数参数
二维数组做函数参数时可以不指定第一个下标。
int func(int array[][10]);
12.1.16 指向二维数组的指针
int a[3][5]
a |
二维数组名称,数组首地址 |
a[0], *(a + 0), *a |
0行,0列元素地址 |
a + 1 |
第1行首地址 |
a[1], *(a + 1) |
第1行,0列元素地址 |
a[1] + 2, *(a + 1) + 2, &a[1][2] |
第1行,2列元素地址 |
*(a[1] + 2), *(*(a + 1) + 2), a[1][2] |
第1行,2列元素的值 |
12.1.17 指向常量的指针与指针常量
const char *p;//定义一个指向常量的指针
char *const p;//定义一个指针常量,一旦初始化之后其内容不可改变
12.1.18 const关键字保护数组内容
如果将一个数组做为函数的形参传递,那么数组内容可以在被调用函数内部修改,有时候不希望这样的事情发生,所以要对形参采用const参数
func(const int array[])
12.1.19 指针做为函数的返回值
char *func();//返回值为char *类型的函数
12.1.20 指向函数的指针
指针可以指向变量,数组,也可以指向一个函数。
一个函数在编译的时候会分配一个入口地址,这个入口地址就是函数的指针,函数名称就代表函数的入口地址。
函数指针的定义方式:int (*p)(int);//定义了一个指向int func(int n)类型函数地址的指针。
1定义函数指针变量的形式为:函数返回类型(*指针变量名称)(参数列表)
2函数可以通过函数指针调用
3int( * P)()代表指向一个函数,但不是固定哪一个函数。
void man() { printf("抽烟\n"); printf("喝酒\n"); printf("打牌\n"); }
void woman() { printf("化妆\n"); |