导图社区 Linux下的C语言
C语言全套笔记,还有Linux系统下如何编译执行,内容相对还是比较喜欢详细的,大家可以借鉴。
编辑于2022-11-20 10:59:54 河南linux环境搭建
为什么要使用Linux系统
后期要学习Linux系统,提前适应一下Linux环境
windows操作系统是图形界面操作,linux主要是命令操作
Linux系统是开源的系统,内核源代码都是公开的,免费使用的
认识linux操作系统
操作系统
定义
管理软硬件资源(管理硬件资源给应用层提供方便操作接口)
历史
诞生于上个世纪60年代
第一个成型的操作系统unix操作系统
诞生原因
随着硬件的发展单纯的裸机程序不能满足硬件的利用率
每个人编写的裸机驱动不同导致应用层编写麻烦
常见的操作系统
unix:闭源,收费
dos:windows的字符操作界面
windows:个人计算机用户市场90%
linux:开源 免费,IT行业
ios/os:苹果
ucos ecos wince等:小型的嵌入式操作系统
linux操作系统
1991年 芬兰大学生
类UNIX操作系统
加入GNU组织
开源、自由的 软件组织
你可以免费使用的代码,但是基于它的修改你也必须遵循这种协议(GPL协议)
很多开源爱好者、黑客 完善linux操作系统
常见的linux操作系统
linux
linux操作系统内核(核心代码实现)
linux操作系统
在内核的基础上增加应用
常见的操作系统厂商
红帽家族
red hat:企业版(稳定)
cenos:社区版(免费)
fedora:发行版(试运行版)
Ubuntu
界面好看,对网络依赖性强
每年4月份 10月份 准时发布,偶数年份的4月最稳定的
linux操作系统开发流程
1-舍弃windows,安装linux操作系统
2-安装双系统
3-利用虚拟机
1-安装windows下模拟虚拟机的软件(vmware workstation(威睿工作站)、v-box)
安装包:2-VMwareworkstation_full_12.1.0.2487.1453173744.exe
作用
创建虚拟机
2-新建虚拟机
虚拟机的电脑
新建
freecomputer
Ubuntu 16.04
VM(虚拟机配置文件)
DATA(磁盘文件)
3-给虚拟机安装操作系统
4-安装vmware tools工具
让鼠标可以来回切换
可以从windows粘贴复制文件
vmware_tools:交互工具的安装
安装过程中的提示按enter默认就行,一直到安装结束,终端提示符出现,重启虚拟机
linux的基本使用
关于用户
管理员用户名:root 具有所有的权限
普通用户:管理员创建,权限非常的低
路径分类
相对路径
相对于用户当前所在目录
绝对路径
相对于根目录:/
终端提示符
[root@localhost /]#
root:当前用户
localhost:计算机名
/:当前所在路径
#:管理员用户 $:普通用户
基本命令的使用
命令格式:命令+选项+参数
ls:查看路径下文件
-a(all):查看所有文件
-l(long):查看详细信息
clear:清屏
cd:跳转
当前所在路径为 ~:家目录
cd Desktop/ 相对路径
cd /root/Desktop/ 绝对路径
/:根目录
~:当前用户的家目录
..:上一级目录
.:当前目录
-:上一次目录
pwd:显示当前所在路径(绝对路径)
mkdir:创建文件夹
-p(创建多级文件夹)
touch:创建文件
rm:删除
-f:强制删除
-r:递归删除(删除文件夹)
cp(copy):复制
cp 源文件(路径) 目标文件(路径)
注意:拷贝文件夹的时候需要加参数-r
mv
剪切
tar
解压,压缩的命令
-x
解压文件
-v
输出提示信息
-f
后边跟压缩文件名
-c
创建压缩文件
解压
-xvf
压缩
-cvf
sudo
下放管理员权限
编辑器/编译器的使用
编辑器
gedit
配置编辑器:编辑->首选项
ctrl+s:保存 ctrl+q:退出
vim
参考vim文档
编译器
gcc
gcc 目标文件 默认生成a.out ./a.out执行
gcc 目标文件 -o 生成文件名
数据类型
计算机的组成
硬件
软件
操作系统
管理CPU的硬件及软件资源 -- 提供用户接口
系统软件
操作系统底层的编译软件
驱动
让外部硬件工作 -- 理解操作系统框架,懂硬件接口时序
应用
高级语言编程--应用程序
计算机语言的发展
机器语言:计算机能够识别的语言,二进制代码。
10100101 --- 往寄存器里写数据
mov
汇编语言:用指令集代替机器语言。最接近机器语言,执行效率高,阅读性差,可移植性差
高级语言
面向过程
c语言、vb等
应用:底层硬件编写
执行效率高
面向对象
c++、java等
应用:上层应用的编写(C++/QT)
执行效率偏低
数据类型
类型注意点
类型表示方法
类型的大小
类型的意义
基本数据类型(字符型、整型、浮点型)
字符型
表示方法
char
类型的大小
1个字节==8位
256种变化情况(0000 0000 ~ 1111 1111)
类型的意义
存放数字
有符号
(signed)char
-128~127
最高位代表符号位
无符号
unsigned char
0 ~ 255
存放字符(ASCII是数字的另外一种表示方法)
字符的表示形式
''括起来
单个字符
‘\0’ '\n' 'a'
“ ”括起来
字符串
整型
表示方法
int
类型的大小
16位单片机/8位单片机
STC89C51
16位 == 2个字节
32位单片机
32位 == 4个字节
类型的意义:存放整形数据(实数)
int:4个字节
signed:有符号 (signed) int
最高位代表符号:1代表负,0代表正
unsigned:无符号 unsigned int
只能存放大于等于0的整数
long:长整形,4个字节(long int)
short:短整形,2个字节 (short int)
浮点型(小数)
表示方法
float:单精度,4个字节(小数点数据有效位后6位)
double:双精度,8个字节(小数点数据有效位后12位)
意义
存放小数
构造数据类型
数组、指针、结构体、共用体和枚举
数据类型的大小
32位环境下
int --4字节 short--2 long--4 char--1 float --4 double--8
1Byte(字节) = 8bit(位)
1k = 1024B
1M = 1024k
1G = 1024M
几个重要的概念
关键字
编译器已经定义好其作用,可以直接使用。标准c语言一共有32个关键字
int
char
标识符
c语言里面的所有命名
1.字母、数字和下划线组成 2.数字不能放开头 3.不能和关键字重复 4.区分大小写
常量
程序运行过程中不能改变的量
字符型常量
字符常量
单引号引起来的字符
'a' 'b'
'\n':换行
‘\r’:enter
'\0':空字符
字符串常量
双引号引起来的字符
“hello” //等效'h' 'e' 'l' 'l' 'o' '\0'
字符串常量以'\0'结尾
整型常量(实数)
正数
152
负数
-100
小数
表示形式:1.24 1.0 == 1. 0.28 == .28
double
指数形式常量
120000 -- 1.2e5
例如:windows -- RAM存储(这块区域不能修改)
在rom中存储(单片机)
变量
程序运行过程中可以改变的量
变量定义
例如:定义一个整型变量名为num; int num; 例如:定义一个整型变量,名为num1,并初始化为100; int num1 = 100;
类型 标识符 (=初始化);
类型:4种基本类型+5种构造类型
标识符
1.有数字 字母 下滑线组成
2.数字不可以放开头
3.不能与关键字相同
4.区分大小写
变量初始化
不用的变量一般初始化为0
变量操作
变量与常量
例如:定义一个整型变量,名为num2,初始化为0; 给num2赋值为200。 int num2 = 0; num2 = 200;//标识符代表该变量空间
a=100;
变量与变量
定义一个整型变量为num1,并初始化为100; 定义一个整型变量为num2,并初始化为0; 把num1的内容赋值给num2; num2 = num1;
a=b;
输入输出
程序标准格式
#include<stdio.h>//包含标准的输入输出头文件 int main()//主函数,一个程序必须并且只能有一个主函数 { 语句;//函数体 return 0;//主函数的返回值 }
输入/输出
格式化输出
printf("输出内容");
printf("格式符",输出变量);
格式符
%d:以十进制格式打印
%x:以16进制格式打印
%o:以8进制格式打印
%f:打印浮点型数据
%c:打印字符型数据
%s:打印字符串
%u:以十进制格式打印无符号变量
%5d:5代表位宽为5,右对齐
%-5d:位宽为5,左对齐
%.3f:打印小数点后3位,第四位进行四舍五入
格式化输入
scanf("格式符",输入变量的地址);
int a; scanf("%d",&a);
#include int main() { int a,b; scanf("%d%d",&a,&b); printf("%5d%5d\n",a,b); return 0; }
运算符
分类
与操作数的结合数量分类
单目运算符
拥有一个操作数
~
!
++
双目运算符
拥有两个操作数
+ - * / % = == +=
三目运算符
拥有三个操作数
?:
赋值运算符
=
算术运算符
+ - * / %
除 / --两个整数相除 == 整数 5/3 = 1
%:求余运算符
注意:操作数只能为整数
5%3 == 2
5%3.0 //错误
关系运算符
> >= < <= == !=
结果:真(不为0)/假(0)
C语言中,0为假,非0为真
-6
9%3
逻辑运算符
&& || !
结果:0/1
&&:逻辑与 两边都为真时结果为真,否则都为假
表达式1 && 表达式2
||:两边都为假时为假,否则都为真
表达式1 || 表达式2
!:真变假,假变真。
!表达式1
c语言0为假,非0都为真
逗号运算符
分割作用
int a,b,c;
int a,b,c; a = (b=3,c=4); a = 4 取最后一个值
复合运算符
+= *= 等
#include "stdio.h" int main() { int a =100; a += 10;// a = a+ 10; printf("%c\n%d\n",'1','1'); }
int a = 10; a += 5; // a = a+5;
自加自减运算符
++ --
#include "stdio.h" int main() { int a =100; int b =200; b = ++a;//先加,再用 // b = 101,a = 101; /********************************************/ b = a++;//先用后加 //b = 100 a = 101 }
int a = 10,b; b = a++;// a=11 b =10 先取值后自加
int a = 10,b; b = ++a;// a=11 b =11先自加,后取值
条件运算符
语句1?语句2:语句3
判断语句1,成立结果为语句2,不成立结果为语句3
int a=3,b=4,c; c = (a>b)?a:b;
位运算符
& | ^ << >> ~
sizeof运算符
求任意对象(数据类型,变量)的大小(字节)
sizeof(int) == 4
#include int main() { int len; len = sizeof(int); printf("%d\n",len); return 0; }
int a = 10; sizeof(a) == 4
运算符的优先级
当不确定时,加()
算术运算符>关系运算符>逻辑运算符
类型转换
自动类型转换
当两个不同类型的数据进行运算时,自动向高精度类型转换
4/3.14 //结果为double类型
1/2 //结果为0 相同的数据类型计算,结果肯定还是这个数据类型
float a = 5;//5自动转换为float类型
强制类型转换
(数据类型)变量
float a = 1.234; int b = 0; b = (int)a;
取一个float型数据的小数部分
float a = 3.64; float b = a - (int)a;
取一个float型数据的整数部分,并且进行四舍五入
float a= 3.64;
int b = (int)(a+0.5);
编程规范
括号
当程序中需要加括号的时候,两个括号一定要同时打上去
只打一边容易遗漏
tab
学会使用Tab键进行缩进
每一个层次结构要有一定的缩进
注释
养成添加注释的习惯,在重要的地方添加注释,方便今后理解
常用的只是方式有两种
//:后边的内容就是注释的内容
/**/:之间的内容都是注释
模块之间加空行
头文件,宏定义,函数声明,函数,类型定义,函数体,返回值
在这些模块之间添加空行,是程序简单明了,方便其他人阅读程序
九条语句
程序的构成和执行
程序的构成
数据结构+算法
数据结构:数据在内存中的存放形式
编程之前,先写流程图,再编程
程序的执行
编辑:用文本编辑器编写程序 .c
编译:检查程序的错误
链接:生成可执行文件 .exe .out
执行
条件语句
if--else
三种格式
1,if(条件) { 语句; }
如果条件为真,则先执行大括号里边的语句,再顺序执行后边的程序,否则直接执行后边的程序
输入数字,打印对应的语句
1 #include 2 3 int main(void) 4 { 5 int num=0; 6 printf("请输入一个整数\n"); 7 scanf("%d",&num); 8 if(num == 5) 9 { 10 printf("输入的数字是5\n"); 11 } 12 printf("程序结束\n"); 13 return 0; 14 }
2,if(条件) { 语句1; } else { 语句2; }
如果条件为真,则执行语句1,再执行后边的程序;否则执行语句2,再执行后边的语句
输入数字,打印相应的语句
1 #include 2 3 int main(void) 4 { 5 int num=0; 6 printf("请输入一个整数\n"); 7 scanf("%d",&num); 8 if(num == 5) 9 { 10 printf("输入的数字是5\n"); 11 } 12 else 13 { 14 printf("输入的数字不是5\n"); 15 } 16 printf("程序结束\n"); 17 return 0; 18 }
3,if(条件1) { 语句1; } esle if(条件2) { 语句2; } . . else if(条件n) { 语句n; } else { 语句n+1; }
先判断条件1,如果满足执行语句1, 如果不满足判断条件2,满足执行语句2, 不满足判断语句3..... 当所有条件都不满足时,执行else语句。
例程:输入学生成绩,输出对应评价(优、良、中,及格,不及格)
1 #include 2 3 int main(void) 4 { 5 float score = 0; 6 printf("请输入学生成绩\n"); 7 scanf("%f",&score); 8 if(score100) 9 { 10 printf("输入错误\n"); 11 } 12 else if(score>=90) 13 { 14 printf("优秀\n"); 14 printf("优秀\n"); 15 } 16 else if(score>=80) 17 { 18 printf("良好\n"); 19 } 20 else if(score>=70) 21 { 22 printf("中等\n"); 23 } 24 else if(score>=60) 25 { 26 printf("及格\n"); 27 } 28 else 29 { 30 printf("不及格\n"); 31 } 32 printf("程序结束\n"); 33 34 return 0; 35 }
switch
格式
switch(变量) { case 常量1:语句1;break; case 常量2:语句2;break; ... default:语句n;break; }
变量等于常量1,执行语句1,等于常量2,执行语句2...都不相等执行default语句
例程:输入数字,输出对应周几
1 #include 2 3 int main(void) 4 { 5 int num = 0; 6 printf("请输入一个1到7整数\n"); 7 scanf("%d",&num); 8 switch(num) 9 { 10 case 1:printf("星期一\n");break; 11 case 2:printf("星期二\n");break; 12 case 3:printf("星期三\n");break; 13 case 4:printf("星期四\n");break; 14 case 5:printf("星期五\n");break; 15 case 6:printf("星期六\n");break; 16 case 7:printf("星期天\n");break; 17 default:printf("输入错误\n"); 18 } 19 return 0; 20 }
循环语句
起始条件,循环条件,条件修正
for()
格式
for(起始条件;循环条件;条件修正) { 循环体; }
从起始条件开始,判断循环条件,如果不满足结束循环,满足执行循环体,执行结束后执行条件修正,重新判断循环条件..
例程
打印0~9,9~0,0~9的偶数
1 #include 2 3 int main(void) 4 { 5 int i = 0; 6 for(i=0;i 7 { 8 printf("%d ",i); 9 } 10 printf("\n"); 11 for(i=9;i>=0;i--) 12 { 13 printf("%d ",i); 14 } 15 printf("\n"); 16 for(i=0;i 17 { 18 if(i%2==0) 19 printf("%d ",i); 20 } 21 printf("\n"); 22 return 0; 23 }
特殊情况
for(;;)//死循环 { 循环体; }
while()
格式
起始条件 while(循环条件) { 循环体; 条件修正 }
例程
打印0~9
1 #include 2 3 int main(void) 4 { 5 int i; 6 7 i = 0; 8 while(i 9 { 10 printf("%d ",i); 11 i++; 12 } 13 printf("\n"); 14 return 0; 15 }
特殊情况
while(1)//死循环 { 循环体; }
do...while()
格式
起始条件 do { 循环体; 条件修正; }while(循环条件);
先执行循环体,再判断循环条件
例程
打印0~9
1 #include 2 3 int main(void) 4 { 5 int i; 6 7 i = 0; 8 do 9 { 10 printf("%d ",i); 11 i++; 12 }while(i 13 printf("\n"); 14 return 0; 15 }
for循环和while循环区别
for循环适用于循环次数已知的情况
while循环适用于循环次数不定的情况
while和do...while的区别
while先判断循环条件,再执行循环体,如果循环条件不满足要求,直接结束循环。
do...while先执行一次循环体,再判断循环条件,即使循环条件不满足,也会执行一次循环体
1 #include 2 3 int main(void) 4 { 5 int i; 6 7 i = 0; 8 do 9 { 10 printf("%d ",i); 11 i++; 12 }while(i>9); 13 printf("\n"); 14 return 0; 15 }
控制语句
break
跳出循环或者switch语句
跳出循环例程:使用死循环打印0~9
1 #include 2 3 int main(void) 4 { 5 int i = 0; 6 while(1) 7 { 8 printf("%d ",i); 9 i++; 10 if(i==10) 11 { 12 printf("\n"); 13 break; 14 } 15 } 16 return 0; 17 }
跳出switch语句例程:
输入数字,输出对应星期几(使用break)
1 #include 2 3 int main(void) 4 { 5 int num = 0; 6 printf("请输入一个1到7整数\n"); 7 scanf("%d",&num); 8 switch(num) 9 { 10 case 1:printf("星期一\n");break; 11 case 2:printf("星期二\n");break; 12 case 3:printf("星期三\n");break; 13 case 4:printf("星期四\n");break; 14 case 5:printf("星期五\n");break; 15 case 6:printf("星期六\n");break; 16 case 7:printf("星期天\n");break; 17 default:printf("输入错误\n"); 18 } 19 return 0; 20 }
输入数字,输出对应星期几(不使用break)
1 #include 2 3 int main(void) 4 { 5 int num = 0; 6 printf("请输入一个1到7整数\n"); 7 scanf("%d",&num); 8 switch(num) 9 { 10 case 1:printf("星期一\n"); 11 case 2:printf("星期二\n"); 12 case 3:printf("星期三\n"); 13 case 4:printf("星期四\n"); 14 case 5:printf("星期五\n"); 15 case 6:printf("星期六\n"); 16 case 7:printf("星期天\n"); 17 default:printf("输入错误\n"); 18 } 19 return 0; 20 }
continue
结束本层循环,继续下一次循环
例程:使用一个循环打印0~4,6~9
1 #include 2 3 int main(void) 4 { 5 int i; 6 for(i=0;i 7 { 8 if(i==5) 9 { 10 continue; 11 } 12 printf("%d ",i); 13 } 14 printf("\n"); 15 return 0; 16 }
return
结束函数并且返回值给上一级函数
例程:写一个加法函数,实现任意两个整数相加
1 #include 2 3 int add(int a,int b); 4 5 int main(void) 6 { 7 int a,b,sum = 0; 8 printf("请输入两个整数,用空格隔开\n"); 9 scanf("%d %d",&a,&b); 10 sum = add(a,b); 11 printf("%d+%d = %d\n",a,b,sum); 12 return 0; 13 } 14 15 int add(int a,int b) 16 { 17 return (a+b); 18 }
goto
程序跳转到指定位置执行
例程:输入学生成绩,显示等级,若输入的成绩错误,则提示错误信息,并且重新输入。
1 #include 2 3 int main(void) 4 { 5 float score = 0; 6 start: 7 printf("请输入学生成绩\n"); 8 scanf("%f",&score); 9 if(score100) 10 { 11 printf("输入错误,请重新输入!!\n"); 12 goto start; 13 } 14 else if(score>=90) 15 { 16 printf("优秀\n"); 17 } 18 else if(score>=80) 19 { 20 printf("良好\n"); 21 } 22 else if(score>=70) 23 { 24 printf("中等\n"); 25 } 26 else if(score>=60) 27 { 28 printf("及格\n"); 29 } 30 else 31 { 32 printf("不及格\n"); 33 } 34 printf("程序结束\n"); 35 36 return 0; 37 }
使用标号指定文件位置,标号随便写,但是要遵守C语言命名规则,标号后边要加上:
程序错误分析
不能出现中文字符
scanf函数使用加&
int a; a = 3; int b; b = a;//c89标准(错误) c99标准(正确)
/*相同的程序,在Linux下的gcc编译器编译没有问题,在windows下的vc++编译器编译出错*/ 1 #include 2 3 int main(void) 4 { 5 int a; 6 a = 3; 7 int b; 8 b = a; 9 printf("a = %d,b = %d\n",a,b); 10 return 0; 11 }
示例
穷举法
标志位
循环嵌套
判断循环条件,如果满足,执行循环体,不满足结束循环
数组
数组
数组的意义
相同类型数据的集合
当存储大量相同类型的数据时使用
特点
开辟空间地址是连续的
一维数组的使用
定义
类型 数组名[数组长度];
类型(元素的类型)
基本的数据类型
构造数据类型
数组名
1.有数字字母下滑线组成
2.数字不可以放开头
3.不能与关键字相同
4.区分大小写
数组名就是数组的首地址
scanf(“%d”,&m)
int num[3];
scanf("%d",num);
数组长度:常量
定义
1.定义,不初始化 例如:定义一个整型数组名称为num,长度为5的数组。 int num[5];
2.定义,并全部初始化 定义一个整型数组名称为num,长度为5,初始化为1 2 3 4 5 int num[5] = {1,2,3,4,5};
3.定义,初始化一部分 定义一个数组长度为5,名称为num的数组,并初始化为1,2,3 int num[5] = {1,2,3};//没有进行初始化的部分默认为0 int num[5] = {0};//数组元素全部初始化为0
4.数组长度可以省略: -- 数组的长度有后面初始化的长度决定 int num[] = {1,2,3,4,5};
初始化
赋初值
数组只有在定义时,才能整体赋初值
int num[5]; num[5] = {1,2,3,4,5};//错误
元素的调用
元素的表示方法
#include int main() { int i; int num[5]; for(i=0;i { scanf("%d",&num[i]); } for(i=0;i { printf("%-5d",num[i]); } return 0; }
数组名[下标]
下标范围0~数组长度-1
注意:不能越界
int num[5] = {1,2,3,4,5};// 访问:num[0] -- num[4]
数组元素的使用
#include int main() { int num[5] = {1,2,3,4,5}; int num2[5] = {6,7,8,9,10}; int i; for(i=0;i { printf("%-5d",num[i]); } printf("\n"); num[0] = 100;//数组和常量 printf("num[0] = %d\n",num[0]); for(i=0;i { num[i] = num2[i]; } for(i=0;i { printf("%-5d",num[i]); } return 0; }
二维数组
定义
类型 数组名[行长度][列长度](={{},{},{}});
1.定义不初始化 定义一个2维数组:3行4列的整型数组名称为num; int num[3][4]; 2.定义,全部初始化 int num[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int num[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; 3.定义,省略行(列不可以省) int num[][4] = {1,2,3,4,5,6};
类型和一维数组一样
数组名和一维数组一样
行长度 -- 常量
列长度 -- 常量
元素的调用
数组名[行下标][列下标]
行下标:0~行长度-1
列下标:0~列长度-1
使用和一维数组一样。
#include int main() { int num[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; int i,j; for(i=0;i { for(j=0;j { printf("%-5d",num[i][j]); } printf("\n"); } }
数组排序
冒泡排序
int num[5] = {5,67,3,8,4};
#include int main() { int num[5] = {5,67,3,8,4}; int i,j,temp; for(j=0;j { for(i=0;i { if(num[i]>num[i+1]) { temp = num[i]; num[i] = num[i+1]; num[i+1] = temp; } } } for(i=0;i { printf("%-5d",num[i]); } return 0; }
字符数组
字符数组
#include int main() { char str[5]={'C','H','I','N','A'}; int i = 0; for(i=0;i { printf("%c",str[i]); } printf("\n"); }
char 数组名[数组长度](=初始化);
字符串数组
字符串(常量)
表示:""括起来
字符串以'\0'结尾
还是一个字符数组:存放的是字符串
表示:
#include int main() { char str2[] = "CHINA"; char str[20]={0}; printf("str2 = %s\n",str2); scanf("%s",str); printf("str = %s\n",str); }
区别
#include int main() { char str[]={'C','H','I','N','A'}; char str1[]={"CHINA"}; printf("%d\n",sizeof(str)); printf("%d\n",sizeof(str1)); }
字符读写函数
char str[20];
putchar
向屏幕输出一个字符
getchar
从键盘读取一个字符
printf("%s",str);//格式化输出
scanf("%s",str);//格式化输入 不能输入空格
gets(str);//字符串输入函数 可以输入空格
puts(str);//字符串输出函数 打印结束会自动打印换行
#include int main() { char str[20]; // gets(str); // puts(str); scanf("%s",str); printf("%s",str); return 0; }
字符串操作函数
包含头文件:string.h
求字符串长度:strlen()
#include #include int main() { char str[20]={0}; int len; scanf("%s",str); len = strlen(str); printf("len = %d\n",len); return 0; }
不包含'\0'
字符串连接函数:strcat
#include #include int main() { char str[20] = "hello"; char str2[] = "world"; strcat(str,str2); printf("%s\n",str); return 0; }
函数原型:char *strcat(char *dest,char *src); 头文件:#include <string.h> 参数:dest 目标数组指针 src 源字符串指针 返回值:返回指向dest的指针 函数功能:把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。 注意事项:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
字符串比较:strcmp
include #include int main() { char str1[20] = "hello world!"; char str2[20] = "hello C"; int a; a = strcmp(str2,str1); printf("a = %d\n",a); return 0; }
原型:int strcmp(const char *s1,const char * s2); 头文件:#include <string.h> 功能:比较字符串s1和s2。 说明: 当s1<s2时,返回值<0 当s1=s2时,返回值=0 当s1>s2时,返回值>0 即:两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇'\0'为止。如: "A"<"B" "a">"A" "computer">"compare" 特别注意:strcmp(const char *s1,const char * s2)这里面只能比较字符串,不能比较数字等其他形式的参数。
字符串复制:strcpy
#include #include int main() { char str1[20] = "hello world!"; char str2[20] = "ffff"; printf("%s\n",str1); printf("%s\n",str2); strcpy(str1,str2); printf("%s\n",str1); printf("%s\n",str2); return 0; }
原型声明:char *strcpy(char* dest, const char *src); 头文件:#include <string.h> 功能:把从src地址开始且含有\0结束符的字符串复制到以dest开始的地址空间 说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。 返回指向dest的指针。
指针
地址和指针
地址
现实:二七区民主路6号华健商务大厦12楼
c语言:给内存空间进行编号,单位是字节
指针
数据类型,指针变量用来存放地址
除了变量名,其余的都是数据类型
指针的使用
定义
数据类型 *指针名;
数据类型:指针指向空间的数据类型
*:代表定义出来的是一个指针变量
int *p;//定义一个整形指针,该指针可以指向一个整形空间
初始化
int a; int *p = &a;
赋值
int a; int *p; p = &a;
调用
int a = 10,b; int *p = &a; b = *p;//b = a; *指针运算符,访问指针指向的空间
&:取地址
*:取内容
空指针
int *p = 0;
int *p = NULL;
指向0地址单元的指针
野指针
指针指向的空间未知,如果该空间存放系统文件,对其修改会使系统崩溃,所有要避免出现野指针
指针的大小
32位编译环境下,指针的大小为4个字节(32位)
指针和字符串
c语言允许用一个字符串初始化一个指针
char *p = "hello";
char *p="hello world"; 在文本常量区里面,且不可修改。
*p = 'H';//错误
字符串是常量,只读不能修改
char str[20] = "hello"; char *p = str; *p = 'H';//正确
函数参数的传递
值传递
传递的是一个普通变量,子函数不能改变实参的值
地址传递
传递的是一个地址,子函数可以通过该地址访问实参
#include int fun(int a); void fun2(int *p); int main() { int b=10; fun(b); printf("b = %d\n",b); fun2(&b); printf("b = %d\n",b); } int fun(int a) { a = 100; } void fun2(int *p) { *p = 100; }
指针和数组
指针指向一个数组的两种方法
#include int main() { int num[5]; int i; int *p=num; for(i=0;i { //scanf("%d",&num[i]); scanf("%d",(p+i)); } for(i=0;i { printf("%-3d",*(p+i)); } return 0; }
int num[5]={1,2,3,4,5};
int *p = num;
int *p = &num[0];
*p == 1 *(p+1) == 2
指针+1,指针内存放的地址+指针指向空间数据类型的大小
二维数组指针
数组类型的指针(二维数组)
定义:类型 (*标志符)[数组长度];
类型:指向数组的类型
数组长度:指向数组的长度
例如: int num[3][4]; int (*pnum)[4];
1 #include "stdio.h" 2 3 int main(void) 4 { 5 int num[2][3]={{1,2,3},{4,5,6}}; 6 int (*pnum)[3] = NULL; 7 int i,j; 8 //指向num 9 pnum = num; 10 //打印第0行0列的元素 11 printf("num[0][0]=%d\n",num[0][0]); 12 //打印第1行0列的元素 13 printf("num[1][0]=%d\n",num[1][0]); 14 //指针表示: 15 for(i=0;i 16 { 17 for(j=0;j 18 { 19 printf("%-3d",*(*(pnum+i)+j)); printf("%-3d",(*(pnum+i))[j]); 20 } 21 printf("\n"); 22 } 23 return 0; 24 }
指针数组
就是一个数组,数组的每一个元素都是一个指针
#include int main() { int i; char *p[3] = {"hello","abc","world"}; for(i=0;i { printf("%s\n",p[i]); } printf("%d\n",sizeof(p)); return 0; }
char *p[3] = {"hello","abc","world"};
指针和函数
指针函数
就是一个函数,函数的返回值为指针
注意:函数的返回值必须有意义
#include char* fun(void); int main() { char *p; p = fun(); printf("%s\n",p); return 0; } /*指针函数*/ char* fun(void) { /*如果不把str定义为static类型,子函数运行结束之后str的内存空间会被自动释放,所以要加上static*/ static char str[20] = "hello"; return str; }
函数指针
就是一个指针,指向一个函数
返回值类型 (*指针名) (参数类型)
#include int fun(int a); int main() { /*函数指针*/ int (*p)(int); p = fun; p(3);//fun(3); return 0; } int fun(int a) { printf("%d\n",a); }
多级指针
指针指向的空间还是一个指针
int a=10; int *p = &a; int **q = &p;
a &a *p *q **q &p
多级指针演示
#include int main() { int a = 10; int *p = &a; int **pp = &p; printf("%d %d %d\n",a,*p,**pp); printf("%p %p %p\n",p,*pp,&a); printf("%p %p\n",pp,&p); printf("%p\n",&pp); return 0; } /*程序运行结果*/ /*由于程序存储位置不同,所以不同的电脑运行的地址结果不一致*/ 10 10 10 0xbff456a0 0xbff456a0 0xbff456a0 0xbff4569c 0xbff4569c 0xbff45698
函数
函数的作用
函数是工程中最小的单位
一个工程有且只能有一个主函数
main
工程从主函数开始,到主函数结束
函数的作用
使程序模块化
封装代码,提供统一接口
函数的使用
#include #include "string.h" void Max(void); int Max1(void); void Funtion1(void); int Max2(int num3,int num4); int main() { int max1; int num1,num2; printf("请输入两个数:\n"); scanf("%d%d",&num1,&num2); max1 = Max2(num1,num2); printf("最大值为%d\n",max1); } void Max(void) { int num1,num2; int max =0; printf("请输入两个数:\n"); scanf("%d%d",&num1,&num2); max = (num1>num2)?num1:num2; printf("输出最大值为%d\n",max); } int Max1(void) { int num1,num2; int max =0; printf("请输入两个数:\n"); scanf("%d%d",&num1,&num2); max = (num1>num2)?num1:num2; return max; } void Funtion1(void) { printf("11111\n"); return ; printf("22222\n"); } int Max2(int num3,int num4) { int max =0; max = (num3>num4)?num3:num4; return max; }
定义
数据类型 函数名(形参)
int main(void) { return 0; }
数据类型:函数的返回值的类型, --- return对应
4种基本类型 指针 枚举
void
return
返回函数的返回值
结束
函数名:望文生义
1.数字字母下划线
2.数字不可以放开头
3.区分大小写
4.不能与关键字相同
形参:函数定义时的参数
形参开辟空间:函数调用时
和普通定义变量一样
数据类型 函数名(形参)//函数头 { //函数体 }
声明
作用:告诉调用函数子函数的存在
数据类型 函数名(参数);//分号必须加
函数头;
声明放在调用函数上面
调用
#include void fun(void); int sum(int a,int b); int main() { int c; fun(); c = sum(3,4); printf("c = %d\n",c); return 0; } void fun(void) { printf("i am fun\n"); } int sum(int a,int b) { int c; c = a+b; return c; }
函数名(实参)
没有形参,就不用传递实参。
函数调用时注意函数有没有参数和返回值
子函数不会自己执行,只有被调用才会去执行
形参和实参
形参:函数定义时写的参数
形式上的参数
实参:函数调用时写的参数
实际的使用的参数
函数调用时把实参的值赋值给形参
#include void fun2(int a) { a = 100; printf("fun2 a = %d\n",a); } int main() { int d=10; fun2(d); printf("main d = %d\n",d); return 0; }
全局变量和局部变量
全局变量
位置
在函数的外面定义
作用范围
从定义开始,到源程序结束位置
作用时间(释放数据空间)
从定义开始,到整个工程结束。
定义未初始化的时候值是0
局部变量
位置
在函数的内部定义
作用范围
从定义开始,到定义这个变量的函数结束
作用时间
从定义开始(函数调用),到函数结束。
定义未初始化的时候值为乱码
注意点:
当全局变量碰到局部变量,使用局部变量(全局和局部名称相同)
c语言开辟内存的五个大区
栈区
由编译器自动开辟和释放,存放局部变量和形参等。函数结束时自动释放
堆区
由程序管理员开辟和释放,如果开辟完没有释放,到整个工程结束自动释放
全局变量区
由编译器自动开辟和释放,存放全局变量和静态变量等。整个工程结束时自动释放。
静态变量(static 局部变量):
作用范围(局部)
和局部变量一样
作用时间:和全局变量一样
文字常量区
存放常量
只读区域
代码段
存放二进制代码
static和extern关键字
修饰类关键字
static
固定的
修饰全局变量和函数
表示该全局变量或者函数只能在本文件内使用
修饰局部变量表示定义了一个静态变量
#include void fun(void); int main() { fun(); fun(); fun(); return 0; } void fun(void) { static int a=1; printf("a = %d\n",a); a++; }
extern
外来的
修饰全局变量和函数
表示该变量或则函数来自外部文件
结构体
结构体意义
不同数据类型变量的集合
char name[20];//姓名 int id;//学号 int score;//成绩
结构体的使用
结构体的定义
第一种 struct std { char name[20]; int id; int score; }; struct std student1; //先定义结构体类型struct std ,再用该类型定义变量
第二种: struct std { char name[20]; int id; int score; }student1; struct std student2; 定义类型的同时定义变量
第三种 struct { char name[20]; int id; int score; }student1,student2; //定义类型的同时定义变量,之后不能用于定义其他变量
定义的解释
#include "stdio.h" #include "string.h" struct STUDENT //-- 意义描述一个学生的基本信息 { int No;//学号 -- 4个字节 char Name[19];//姓名 -- 19个字节 float Score;//成绩 -- 4个字节 }; void main(void) { //1.找到最大类型 //2.求出所有空间之和(sum) //3.大小必须大于和并且为最大类型的整数倍 printf("%d\n",sizeof(struct STUDENT)); }
结构体的初始化
struct std student1 = {"张三",1,80};
struct std student2; student2 = {"李四",2,60};//错误 student2.id = 2;//int id student2.score = 60;//int score strcpy(student2.name,"李四");
变量的定义以及使用
结构体变量定义和初始化
#include "stdio.h" #include "string.h" struct STUDENT //-- 意义描述一个学生的基本信息 { int No;//学号 -- 4个字节 char Name[19];//姓名 -- 19个字节 float Score;//成绩 -- 4个字节 }; void main(void) { //不初始化 struct STUDENT student_hesi; //初始化 struct STUDENT student_li = {120301,"李明伟",90.0}; }
使用
#include "stdio.h" #include "string.h" struct STUDENT //-- 意义描述一个学生的基本信息 { int No;//学号 -- 4个字节 char Name[19];//姓名 -- 19个字节 float Score;//成绩 -- 4个字节 }; void main(void) { //不初始化 struct STUDENT student_he; //初始化 struct STUDENT student_li = {120301,"李明伟",90.0}; //成员的使用 -- 使用时和普通变量一样 //结构体变量名.成员名 //输入何思的信息 printf("学号:"); scanf("%d",&student_he.No); printf("姓名:"); scanf("%s",student_he.Name); printf("成绩:"); scanf("%f",&student_he.Score); //输出李明伟的相关信息 printf("学号\t姓名\t成绩\n"); printf("%d\t%s\t%f\n",student_li.No,student_li.Name,student_li.Score); printf("%d\t%s\t%f\n",student_he.No,student_he.Name,student_he.Score); }
注意:结构体可以相互赋值
结构体的大小
struct tag { char b;//4 int a; //4 char str[5];//8 };
每次开辟内存空间都是最大数据类型的大小
从上往下存储
结构体元素的访问
#include "stdio.h" #include "string.h" struct STUDENT //-- 意义描述一个学生的基本信息 { int No;//学号 -- 4个字节 char Name[19];//姓名 -- 19个字节 float Score;//成绩 -- 4个字节 }; void main(void) { //不初始化 struct STUDENT student_he = {120302,"何思",90.0}; //初始化 struct STUDENT student_li = {120301,"李明伟",90.0}; struct STUDENT * pstudent = NULL; pstudent = &student_he; printf("学号\t姓名\t成绩\n"); printf("%d\t%s\t%f\n",student_li.No,student_li.Name,student_li.Score); printf("%d\t",pstudent->No); printf("%s\t",pstudent->Name); printf("%f\n",(*pstudent).Score); }
通过变量名
#include struct std { char name[20]; int id; int score; }student1 = {"张三",1,80}; struct std student2 = {"里斯",2,70}; int main() { // struct std *p=&student2; printf("姓名:%s,id:%-3d,成绩:%-3d\n",student1.name,student1.id,student1.score); //printf("姓名:%s,id:%-3d,成绩:%-3d\n",p->name,p->id,p->score); return 0; }
变量名.成员名
通过指针
#include struct std { char name[20]; int id; int score; }; struct std student[3]; int main() { int i; printf("请输入学生信息\n"); for(i=0;i { scanf("%s%d%d",student[i].name,&student[i].id,&student[i].score); } for(i=0;i { printf("name:%-5sid:%-3dscore%-3d\n",student[i].name,student[i].id,student[i].score); } return 0; }
指针名->成员名
不常用:(*指针名).成员名
结构体首地址:&变量名
共用体
可以理解为一个特殊的结构体,数据元素共用内存空间
union share { int a; char str[4]; };
一个整形变量a=0x12345678,打印整形空间每个字节内存放的内容
#include union share { unsigned int a; char str[4]; }; union share share1; int main() { int i; share1.a = 0x12345678; for(i=0;i { printf("%-5x",share1.str[i]); } return 0; }
枚举
把变量可能出现的结果给一一列举出来
enum 枚举类型名{枚举常量1,枚举常量2,枚举常量3....};
#include enum day { monday=1,tuesday,wednesday }; enum day workday; int main() { scanf("%d",&workday); switch(workday) { case monday:printf("1111\n");break; case tuesday:printf("2222\n");break; case wednesday:printf("3333\n");break; } return 0; }
链表
数据结构
相互之间存在关系的数据元素的集合
顺序存储结构
根据数据元素之间的相对位置表示关系,在内存中是连续存储的。
链式存储结构
上一个元素存放下一个元素的地址,通过该地址表示之间的关系,在内存中是不连续存放的。
链表
称链表的数据元素为节点,每一个节点分为数据域和指针域
链表结构
链表头一般不存放数据,链表尾的指针域设为null
内存的动态开辟和释放
动态开辟
void *malloc(size_t size);
动态开辟size个字节大小的内存,并且返回这块内存的首地址,失败返回NULL
动态释放
void free(void *ptr);
释放malloc开辟的内存空间,ptr为内存空间的首地址
链表的使用
链表头的创建
malloc开辟空间
指针域赋空
数据域赋空
链表节点的创建
malloc开辟空间
指针域赋空
连接到前一个节点
链表内容的读写
找到对应的位置
读取或者写入内容
链表的插入
malloc开辟空间
指针域赋空
连接到前一个节点
链表的删除
找到对应的位置
将后一个和前一个连接起来
释放要删除的空间
文件
文件概念
相关数据的有序集合
分类
ASCII码存储
二进制存储
标准输入输出
stdout
标准输出
屏幕
stdin
标准输入
键盘
stderr
标准错误
屏幕
文件操作(文件系统)
基于缓冲区的文件操作
标准c语言支持
输入数据先放在输入缓冲区,遇到一定条件才会被读取
\n
输出数据先放在输出数据缓冲区里边,遇到一定的条件才会在屏幕上显示
程序正常结束
'\n'
fflush
基于非缓冲区的文件操作
文件操作指针
文件打开时,系统自动建立文件结构体,并把指向它的指针返回来,程序通过这个指针获得文件信息,访问文件。文件关闭时,它的文件结构体被释放。
对文件进行操作就是通过该结构体
c语言提供了一些标准的文件操作函数,可以直接使用
文件的打开/关闭
路径
相对路径
绝对路径
fopen
·函数原型: FILE *fopen(char *name, char *mode);
函数参数
name:
文件名/文件路径
mode
打开文件的方式
r
以只读的方式打开文件
不会新建文件
r+
以读写的方式打开文件
不会新建文件
w
以只写的方式打开文件
每次都会新建文件
w+
以读写的方式打开文件
每次都会新建文件
a
以追加的方式打开文件
可以新建文件
a+
以追加的方式打开文件
可以新建文件
·功能:按指定的方式 mode 打开文件名为 name 的文件。
·返回值:正常打开,返回指向文件结构体的指针;打开失败,返回 NULL。
fclose
·函数原型: int fclose(FILE* fp);
·功能: 关闭 fp 所指向的文件
·返回值:正常关闭返回 0;出错时,返回非 0
·使用方法: fclose(fp);
文件的读写
单个字符读写
fgetc:读
函数原型: int fgetc(FILE *fp);
功能:从 fp 指向的文件中读取一字节代码
返回值:正常,返回读到的代码值;读到文件尾或出错,为 EOF(-1)
fputc:写
函数原型: int fputc(int c, FILE *fp);
功能:把一字节代码 c 写入 fp 指向的文件中
返回值:正常,返回 c;出错,为 EOF(-1)
feof
函数原型: int feof(FILE *fp);
功能:判断文件是否到末尾
返回值:文件未结束,返回 0;文件结束,返回真(非 0)
getchar
putchar
两个函数只能针对标准输入输出设备进行操作
字符串读写
fgets
函数原型
char *fgets(char *s, int size, FILE *stream);
函数功能
从文件里边获取size个字节的字符串,存放在s里边
函数返回值
成功返回获得的字符串地址,失败或者到达文件结尾返回NULL
fputs
函数原型
int fputs(const char *s, FILE *stream);
函数功能
将字符串S写入文件里边
函数返回值
成功返回非0值,失败返回EOF(-1)
块读块写
fwrite
函数原型
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
函数功能
将ptr里边的内容写入文件里边,一次写size字节,写nmenb次
函数返回值
成功返回写入的字节数,失败或者到达文件结尾返回0。
fread
函数原型
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
函数功能
从文件里边读取字符到ptr里边,一次读取size字节,读取nmemb次
函数返回值
成功返回读出的字节数,失败或者到达文件结尾返回0。
格式化读写
fprintf
函数原型
int fprintf(FILE *stream, const char *format, ...);
...代表该函数有可变参数
int printf(const char *format, ...);
函数功能
输出字符到文件里边
fscanf
函数原型
int fscanf(FILE *stream, const char *format, ...);
int scanf(const char *format, ...);
函数功能
从文件里边读取字符串
文件指针定位函数
fseek
函数原型
int fseek(FILE *stream, long offset, int whence);
函数功能
可以定位到任何位置
函数参数
stream
文件指针
offset
偏移量
可正可负
whence
参考位置
SEEK_SET
文件开头
SEEK_CUR
当前位置
SEEK_END
文件结尾
函数返回值
成功返回0,失败返回-1
rewind
函数原型: void rewind(FILE *fp)
功能:重置文件位置指针到文件开头
返回值:无
ftell
返回当前文件读写指针的位置,常用来求文件的大小
long ftell(FILE *stream);
参数
文件指针
返回值
成功返回文件指针当前位置
失败返回-1
删除文件
remove
int remove(const char *pathname);
作业
1,练习文件操作内容
2,使用文件操作写学生管理系统,实现保存学生信息
编译预处理
编译预处理
以#开头的命令都是编译预处理命令
包含文件(#include)
#include <stdio.h>
在系统指定目录寻找.h文件
#include "stdio.h"
在整个工程内寻找.h文件
头文件
.h
声明 宏定义相关参数 构造结构体类型等等
源文件
.c
定义函数,定义变量等等
宏定义(#define)
#define A B
用A代表B
A是个字符常量
#define SUCCESS 1 #define FAULT 0
程序执行时
用B完全替换A
不带参数
#define PI 3.14
定义常量
带参数
#include #define SUM(x,y) x+y int main() { int c = 3*SUM(2,3); printf("c = %d\n",c);//9 return 0; }
#define SUM(x,y) (x+y)
完全替换
加()
宏定义后面不要加;
函数和宏定义的比较
宏定义执行效率高,但是没有类型检测,没有函数严谨
条件编译(#if)
#if 表达式 程序1 #else 程序2 #endif
#define N 2 #if (N==1) #include int main() { printf("11111\n"); return 0; } #endif #if (N==2) #include int main() { printf("22222\n"); return 0; } #endif #if (N==3) #include int main() { printf("33333\n"); return 0; } #endif
如果表达式为真,编译程序1,否则编译程序2
和宏定义结合
对操作系统、GUI等等进行裁剪
头文件
#ifndef 标识符 #define 标识符 #endif
防止重复编译
32个关键字
int long short unsigned signed float double char void sizeof 10个
if else switch case default for while do break continue goto return 12
struct union enum
static extern
auto
自动变量,未加任何修饰的局部变量默认就是自动变量。
register
修饰寄存器变量,直接从寄存器内获取变量的值,增加读写速度
编译器有时会把变量自动优化成寄存器变量
volatile
修饰变量,每次取数,都从物理地址取数。(防止编译器优化)
const
修饰的空间不能改变
const int a = 100; a =10;//错误,不能修改a的内容
扩展
const 修饰指针
const int *p;
修饰的是*p
int * const p;
修饰的是p
int const *p;
和第一种相同
修饰的是*p
typedef
类型重定义
typedef
后面的代替前面的使用
#include "stdio.h" typedef struct tagSTUDENT { int no; char name[10]; float score; }STUDENT; int main() { STUDENT student1;//等效struct tagSTUDENT student1; } #include "stdio.h" typedef unsigned int u32;//分号不可以省略 int main() { u32 i = 0;//等效 unsigned int i = 0; }
typedef和宏定义的区别
#include "stdio.h" typedef unsigned int * u32p;//分号不能省略 #define u32p1 unsigned int * int main() { u32p p1,p2;//定义两个指针变量 u32p1 p3,p4;//完全替换 -- unsigned int *p3,p4; p3是指针变量,p4是整形变量 }
位操作
<< >> | & ~ ^
|:位或
任何数或上1结果都为1,或上0为本身,经常用来置1
&:位与
任何数与上0结果都为0,与上1为本身,经常用来置0
~:取反
0变1,1变0
^:异或
不同为1,相同为0
任何数与1异或 -- 取反
任何数与0异或--本身
所有位往左移,左舍弃,右补0
>>:右移
所有位往右移,右舍弃,左补零
示例
把变量b的第a位置1
char b = 10;//0000 1010 char a = 2; 0000 1010 | 0000 0100 0000 1010 | 1<<2 b = b|(1<<a); b |= 1<<a;//把b的第a位置1
把变量b的第a位置0
char b = 10;//0000 1010 char a = 3; 0000 1010 & 1111 0111 0000 1010 & ~(1<<3) b = b&(~(1<<a)); b &= ~(1<<a);//把b的第a位置0
把变量b的第a位取反
b ^= 1<<a;
模块化编程
每一个模块都建立一个.c和一个.h文件, 想使用该模块时,包含对应的.h文件就可以了
.c文件写函数、变量的定义
.h文件写函数的声明、类型的定义等
.h文件要写防止重复编译的预处理命令