基础c语言 part
编程基础知识
- 编辑器:类型记事本一样的用来编写代码的工具。
- 编译器:负责把代码文件翻译成可执行程序的软件。
- gcc 是GNU社区为编译Linux内核开发的一款编译器。
gcc code.c > a.out
编译器如何工作
- 预处理
把代码中以#开头的指令翻译成标准的C代码,生成预处理文件。
gcc -E code.c -o code.i - 汇编
把预处理文件翻译成汇编文件
gcc -S code.i -> code.s - 编译
把汇编文件翻译成目标文件(二进制)
gcc -c code.s -> code.o - 链接
把若干个目标文件合并成一个可执行文件
gcc a.o b.o c.o -> a.out
C语言的数据
为什么要把数据进行分类:
- 现实社会中的数据是自带类别属性。
- 对数据进行分类型可以节约存储空间、提高运行效率。
C语言中数据分类两个大类自建(程序自己设计的,如:结构、联合、类)和内建(C语言自带)。
整型
char、short、int、long、long long
有符号 signed : 它存储数据的二进制位中最高位用来表示正负。
无符号 unsigned :它的所有的二进制位都用来存储数据,只能表示正数。
浮点型
float 单精度
double 双精度
long double 高精度
浮点型数据采用的是科学计数,可以表示较大范围的数据,但是精确度有限。
浮点型的数据由于格式特殊,所以运算的效率不高,编程时优先选择整型。
布尔类型
C语言中没有真正的布尔类型,若使用必须添加头文件stdbool.h
bool true false
字符型
字符其实就是符号或图案,在计算机中是以整数形式存储的,当需要显示时会根据ASCII表中的对应关系,显示相应的符号。
‘\0’ | 0 |
‘0’ | 48 |
‘A’ | 65 |
‘a’ | 97 |
变量
存储数据的容器,需要先定义后使用。
定义:类型 变量名;
注意:刚定义的变量默认值是不确定的,为了安全一定要初始化(养成良好的习惯)。
变量的取名规则(标识符的取名规则)
- 只能由字母、数字、下划线组成。
- 不能以数字开头。
- 不能与关键字重名( 32个关键字)。
- 尽量不要超过30个字符。
- 见名知义(功能+类型+作用域+…)。
C语言中通过使用占位符的方式来告诉printf/scanf变量的类型。
变量的输出:printf 类型 变量名
变量的输入:scanf 类型 变量的地址=&变量名
sizeof 计算变量的字节数。
常量
字面值常量(代码中能直接使用的数量:100,1000),不可被修改,存储在一块只有只读权限的内存中(代码段)。
设置字面值常量的类型:
默认是int(10)类型,或double(3.14)类型。
10u unsigned short
10U unsigned int
10u8 unsigned char
3.14f float
3.14l long double
运算符
算术运算符:+ - * / %
/ % 除数不能为零,如果除数为零程序会提前死亡。
关系运算符:> < >= <= == !=
运算的结果是逻辑:true=1 false=0
==使用时常量放在左边,变量放右边。
num == 10;
10 == num; 防止出错
10 < num < 100; 数学中[11,99],C语言中永远为真。
自变运算符:++/–
可以让变量的值自加1或自减1(只有变量才能使用)。
-
前自变:++/–num,立即有效。
-
后自变:num++/–,下一行代码才会生效。
一行代码中不要多次使用自变运算符。
逻辑运算符:&& || !
在运算之前会把运算对象转换成逻辑值:零值转换成假,非零值转换成真,然后再对逻辑值进行运算,得到的结果也是逻辑值。
A && B => 一假即假
A || B =>一真即真
!A =>对A的值求反
!比&&、||运算级别要高(单目运算符的级别都比较高)。
&&、|| 具有短路特性,当左边的值已经能确定表达式的结果,右边的值则不再计算(注意思维误区,还可以借此形成精简的分支结构)。
int num = 0;
num>0 && num–;
赋值运算符及扩展:= += -= *= /= …
num += 10 <=> num = num + 10;
三目运算符:[1] ? [2] : [3];
当1的值为真时执行2,否则执行3,类似if语句。
不能使用流程控制语句,因为毕竟是运算符,必须要有运算结果。
字节数运算符:sizeof
- sizeof不是函数而是运算符,而且是32个关键字之一。
- 只是推算表达的结果是什么类型、占多少个字节,而不计算表达式。
位运算符:& | ~ ^ << >>
流程控制语句
分支
if(表达式)//单分支
{
表达式为真,则执行此处代码,如果此处代码只有一行,则大括号可以省略(如果没有括号,默认下一行是if的语句体,与缩进无进,但这样会影响代码的可扩展性和安全性)。
}
if(表达式)//双分支
{
表达式为真时执行
}
else
{
表达式为假时执行
}
if(表达式1)
{
表达式1为真时执行
}
else if(表达式2)//可以有任意多个
{
表达式1为真时执行
}
else
{
所有表达式都为假时执行。
}
开关语句
switch(表达式)//表达式的结果必须是整型数据
{
//val必须是常量,现阶段只能是字面值,以后可以是枚举值、宏常量。
//case的数据与表达式的结果进行匹配,如果匹配成功则打开执行开关。
//break可以关闭执行执行开关,如果每个case后都有一个break就会形成分支结构。
case val: 语句; break;
//当所有的case都没有匹配成功,default就会打开执行开关,无论放在任何位置都最后执行。
default: 语句;
}
循环
为了解决一些问题,需要反复执行一些代码,这种可以反复执行代码的结构叫循环结构,有两种循环结构,当型循环(当条件为真进入循环),直到循环(直接条件为假退出循环)。
for循环
for循环是一种非常灵活的循环(1234位置的代码都缺省),但也非常危险的循环,一般采用循环变量来引导for循环的执行,index->i,j,k,l。
可以写出各种格式:
int i=0;
for(; i<10; i++)
{
…
}
for(int i=0; i<10;)
{
…
i++;
}
for( ; ; )//死循环
{
…
}
while循环
while(表达式)
{
表达式的结果为真则执行循环体,为假则结束while循环。
}
while可以当作是for循环的精简版本,跟以下格式的for功能一致。
for(;表达式;)
{
}
for负责解决明确知道循环次数的问题,while负责解决只知道循环条件不确定循环次数的问题。
do while 循环
do{
先执行一次循环体,再判断表达式,为真继续执行do while循环,为假时则结束,因此do while的循环体至少执行一次,相同条件下会比for和while多执行一次,适合解决先干活后检查的问题。
}while(表达式);
跳转语句
goto 只跳转到函数内任意位置执行,是一种非灵活但也非常危险的语句,因为它会破坏之前设计好的分支或循环结构,各公司一般禁止使用goto语句。
goto语句之所以还保留,是因为它在驱动编程时非常适合处理异常(释放资源),具有不可替代的作用。
标签名:
goto 标签;
练习
假如你和你的朋友参加了一个旅游团去海上旅行,不幸遇到龙卷风,一行41人被吹到了一个荒无人烟的小岛,由于所带水和食物有限,只够2个人生存下来因此大家决定了一个自杀方式,41个人排成一个圆圈,由第1个人 开始报数,每报数到3,此人就必须自杀 ,然后再由下一个重新报数,直到剩余两个人,为了你和你朋友能够生成下来,请编程计算出你们要站的位置。
#include <stdio.h>
int main()
{
// 定义arr[41]中等于0为或者,等于1已死亡。
int arr[41] = {},count = 41,step=0,i=0;
while(count > 2)
{
if(0 == arr[i])
{
step++;
}
if(3 == step)
{
arr[i] = 1;
count--;
step = 0;
}
//41个人轮完后i清零,造成圆循环
if(i++ == 40)
{
i=0;
}
}
for(int i=0; i<41; i++)
{
if(0 == arr[i])
{
printf("%d\n",i+1);
}
}
}