C语言简介:
BCPL->newB->C->UNIX->Minix->Linux->gcc
C语言诞生于1970-1973年之间,在肯.汤普逊和丹尼斯.里奇的主导下编写完成,目前C语言归属于美国贝尔实验室
C语言是专门为了编写操作系统而诞生的语言,所以天生适合硬件编程,以运行速度快而著称,也非常适合实现数据结
构与算法。由于出现时间过早,C语言是存在非常多的缺陷。但前辈们总结了一些经验,可以用于避免大部分缺陷。(
《C语言的陷阱与缺陷》C语言三剑客)
C语言语法自由,也意味着危险(自由源于自律)
C89语法标准,gcc默认的语法标准
C99语法标准,是对C89的扩展和增强(gcc -std=gnu99)
C11语法标准,全新的升级
第一个C程序
#include<stdio.h>
程序员所编写的代码并不是标准的C代码,需要一段程序把它翻译成标准的C代码,负责翻译的程序叫做预处理器,翻译的过
程称为预处理,被翻译的的代码叫做预处理指令,以#开头的代码都是预处理指令
#include 是把一个头文件导入到当前文件中
#include<>中“<>”是指从系统指定的目录下导入头文件
#include""中“""”先从当前路径下加载头文件,如果找不到,再从系统指定路径下加载头文件
(操作系统是通过设置环境变量来指定加载头文件路径的)
stdio.h 头文件:以.h结尾,里面存储的是一些辅助性代码,绝大部分是函数的声明
源文件:以.c结尾,里面存储的是功能性代码
(C语言标准委员会为C语言以函数的形式提供了一些基础功能,这些函数就被封装到libc.so
库文件中,并用很多头文件负责对库中的函数进行分类说明,常用的有stdio.h、string.h...)
stdio.h 负责对输入输出功能函数进行说明
int main()
{
printf("Hello,world!\n");
return 0;
}
main函数:
C语言以函数为单位来管理代码,是管理代码的最小单位,一个函数就是一段具有某项功能的代码段
main函数是程序执行的路口,有且只有一个
int 是一种数据类型,它表示main函数的执行结果是一个整数
return 功能有两个:1、结束函数的执行
2、返回一个数据给函数的调用者
(main函数是由操作系统调用,它的返回值返回给操作系统,反映了程序是怎样结束的,通常有三种
情况:
正数 出现异常(别人的错误)
0 一切正常
负数 出现错误(自己的错误)
可以通过 echo $? 命令来查看上一个程序的返回值
printf/scanf 是标准库中的函数,负责输入、输出数据,用来调试代码
printf("----------\n");
转义字符:
键盘上一些按键是没有符号的,用一些特殊的字符组合来表示,这些特殊的字符组合就是转义字符
\n 换行
\b 退一个字符
\r 回到行首
\t 制表符,用于对齐数据
\a 铃响
\\ 表示一个“\”
%% 表示一个“%”
C语言以分号作为一行代码的结束,并使用大括号划分区域
编译器:
负责把人能看懂的记录了代码的文本文件,翻译成计算机能看懂的二进制文件,由预处理器、编译
器、链接器组成
gcc是由GUN组织为了编译Linux内核代码而开发的一款免费、开源的编译器,默认采用C89标准,可用
-std=gnu00设置语法为C99语法标准
常用的参数:
-E 显示预处理结果
-c 只编译不链接
-o 设置编译结果的名字 (gcc hello.c -ohello)
-I 指定头文件的加载路径
-S 生成汇编代码
-l 指定要使用的库文件
-Wall 以更严格的标准来检查代码,尽可能多地显示警告
-Werror 把警告当错误处理
C代码变成可执行程序的过程
1、预处理 把源文件翻译成预处理文件
gcc -E code.c 显示预处理结果
gcc -E code.c -o code.i 生成以.i结尾的预处理文件
2、编译 把预处理文件翻译成汇编文件
gcc -S code.i
3、汇编 : 把汇编文件翻译成二进制目标文件
gcc -c code.s 生成以.o结尾的目标文件
4、链接 把若干个目标文件合并成一个可执行文件
gcc a.o b.o c.o... 默认生成一个a.out的可执行文件
C语言文件类型:
.h 头文件(头文件编译结果为.h.gch)
.c 源文件
.i 预处理文件
.s 汇编文件
.o 目标文件
.a 静态库文件
.so 共享库文件
数据类型:
为什么要对数据进行分类:
1.现实中的数据本来就自带类别属性
2.对数据进行分类可以节约存储空间、提高运行速率
存储空间的单位:
Bit 比特 一个二进制位,只能存储0或者1,计算机存储数据的最小单位
Byte 字节 八个二进制位,计算机存储数据的基本单位
Kb 1024字节
Mb 1024Kb
Gb 1024Mb
Tb 1024Gb
Pb 1024Tb
C语言中数据分为两大类:自建(程序员自己设计的:结构、联合、类)和内建(C语言自带的)
内建中:(可使用sizeof运算符计算
整型:有符号 signed
signed char 1 -128~127
signed short 2 -32768~32767
signed int 4 正负20亿
signed long 4/8
signed long long 8 正负9开头的19位整数
无符号
unsigned
unsigned char 1 0~255
unsigned short 2 0~65536
unsigned int 4
unsigned long 4/8
unsigned long long 8 0~以1开头的20位整数
注意:由于定义无符号数据 时比较麻烦,标准库把这些无符号的类型重新定义成了以下类型
使用时需要包含头文件:stdint.h
uint8_t uint16_t uint32_t uint64_t
int8_t int16_t int32_t int64_t
size_t
浮点型:
float 4
double 8
long double 12/16
注意:浮点数都是采用科学计数法存储的,二进制与整型数据之间需要进行换算,因此浮点
浮点型数据耗时比整数型多得多,编程时应尽量选择整数型(小数点后六位有效)
(time ./a.out 计算程序运行时间)
模拟型:
字符型char
字符其实就是符号或图案,内存中存储的是整数,当需要显示成字符时会根据ASCII码
表中对应的关系显示处相应的符号或图案
'\0' 空字符,对应ASCII码为0
'0' 48
'A' 65
'a' 97
布尔型bool(先有了C语言之后才有了bool类型,所以C语言中是不可能有真正的布尔类型,C语
言中用stdbool.h头文件对布尔类型进行了模拟)
变量与常量:
变量:程序在运行期间数据可以变化的称为变量(相当于存储数据的盒子)
定义方式:类型 变量名;
取名方式:
1.由字母、字符、下划线组成
2.不能以数字开头
3.不能与32个C语言关键字重名
数据类型相关:
内建类型:void char short int long float double
自建类型:struct union enum sizeof
类型限定符:signed unsigned auto const static volatile register extern typedef
流程控制相关:
分支:if else switch case default
循环:while for do
跳转:break continue return goto
4.见名知意
注意:变量的默认值是随机的,为了安全起见要对变量进行初始化,一般初始化为0
变量的输入、输出:
int printf(const char *format, ...);
功能:输出数据
format:"双引号包含的格式信息(提示信息+占位符)"
... : 变量列表
返回值:输出字符的个数
类型占位符:C语言通过类型占位符的方式来传递变量的类型
整型:%hhd %hd %d %ld %lld 有符号
%hhu %hu %u %lu %llu 无符号
浮点型:
%f %lf %LF
字符型:
%c %s
int scanf(const char *format, ...);
功能:输入数据
format: "双引号包含的格式信息(占位符)"
...: 变量地址列表 &变量名
返回值:成功输入的变量个数
注意:scanf需要的是变量的类型和地址(即 &+变量名 )
常量:程序运行期间数值不能变化的称为常量
100 默认int型
100u unsigned int
100lu unsigned long
100llu unsigned long long
100l long
100ll long long
3.14 默认double
3.14f float
3.14l long double
问题:100年有多少秒?
#define SEC(3600*24*365*100u)
带格式的输入输出
%nd 显示n个字符宽度(不够则自动补空格,右对齐)
%-nd 显示n个字符宽度(不够则自动补空格,左对齐)
%0nd 显示n个字符宽度(不够则自动补0,右对齐)
%n.mf 显示n个字符宽度(小数点算一位,不够则自动补空格,四舍五入保留小数点后m位)
%g 不显示小数点后多余的0
运算符
自变运算符:++/-- 使变量的值自动+1或者-1
前自变:++num/--num 立即有效
后自变:num++/num-- 在下一行语句生效
注意:尽量不要在同一行内多次使用自变运算符
算数运算符:+ - * / %
整数/整数 结果为整数
/ % 除数不能为0(错误提示:浮点数例外,核心已转储)
关系运算符:> < >= <= == !=
比较的结果必须是0或者1,比较的结果还能继续参与运算
int num=-5;
if(1<num<10) 永远为真,运算规则与数学不一样(建议常量放左边)
逻辑运算符:&& || !
会先把运算对象转化成逻辑值,0转化为假,非0转为真
A && B 全真为真
A || B 有真即真
!A 求反
&& 和 ||短路特性:当左边的运算对象已经能够确定整个表达式的运算结果时,右边的运算对象
不再执行。
三目运算符:运算对象有三个部分
A?B:C 判断A的值是否为真,是的话执行B,不是则执行C
(该语句不能使用流程控制语句,因为它必须要有运算结果)
赋值运算符:
a += b: a=a+b;
a -= b;a=a-b
a*=b
a/=b
...
位运算符:& | ~ >> <<
sizeof 也是运算符,但是sizeof括号内的表达式不会计算
类型转换:
自动类型转换:只有相同类型的数据才能运算,不同类型的数据必须转换成相同的类型才能进行运算
转换规则:1.以不丢失数据为基础,可以适当牺牲一些空间
2.字节少的向字节多的转
3.有符号的向无符号的转
4.整型向浮点型转
强制类型转换:
(新类型)数据: 有丢失数据的风险,慎重使用
分支语句
if(表达式) //单分支
{
表达式为真时,执行此处语句。
}
if(表达式) //双分支
{
表达式为真时,执行此处语句。
}
else
{
表达式为假时,执行此处代码
}
if(表达式) //多分支
{
表达式为真时,执行此处语句。
}
else if(表达式2)
{
表达式2为真时,执行此处代码
}
...
else
{
表达式都为假时,执行此处代码
}
注意:大括号建议上下对齐,当大括号内语句只有一条时,大括号可以省略
开关语句
switch(n) //n可以时数值或表达式,但不可为小数
{
case val: ... // val必须是整数常量
break;
case val: ...
.
.
default: ... // 如果所有的case都没有匹配成功,则打开该执行开关,并且放在任何位置都可以
}
注意:如果每个case后都有break,就形成了分支结构;switch不能与continue配合使用
case a...b:可以表示一个范围,但是属于GUN专属语法不建议使用
循环语句(让一段代码反复执行)
for循环语句:(是一种比较灵活但是与其他循环相比具有一定危险性的一种循环)
一般用一个变量来引导for循环的运行,即循环变量,一般为 i (index)
基本结构:
for([1];[2];[3])
{
[4];
}
1.给循环变量赋初值,只有C99的标准才可以在此处定义循环变量
2.判断循环条件,一般判断循环变量是否到达边界
4.如果2为真则执行此处代码(此处也称为循环体)
3.改变循环变量,防止出现死循环一般为(i++/i--)
for循环的多种写法
for(;;)
{
//死循环
}
int i=0;
for(;i<10;i++)
{
}
for(i=0;i<10;)
{
i++;
}
while循环:
while(条件)//当条件为真时执行循环体,为假时结束循环
{
...
//循环体
}
while循环相当于佛如循环的精简版本for(;条件;)
for循环负责解决明确知道循环次数的问题
while循环负责解决只知道结束条件,而不确定循环次数的问题
do while 循环:
do{
//循环体
}while(条件); //分号不能少
先执行循环体,再判断循环条件是否为真(该循环至少执行一次)
适合先干活,再检查的特殊情况 例如:密码问题
问题:解释 for、while、do-while 有什么区别
循环的嵌套:
外层循环执行一次,内层循环执行n次
小练习:
1;计算所有的水仙花数
2:输入一个正整数,判断是否是素数
3:输入一个正整数,判断是否为回文数
4:输入一个六位密码,正确显示“登录成功”,错误提示“还剩几次机会”,错误超过三次显示“账号已锁定”
5:输入一个整数分解显示