- 废话
- hello world
- 规范性
- 写作格式
- 命名
- 注释
- 变量与赋值
- 简单类型
- 数值型
- 字符型
- 运算符号说明
- 赋值运算符
- 算数运算符
- 关系运算符
- 逻辑运算符
- 简单结构
- 顺序结构
- 分支结构
- if~else
- switch~case
- 循环结构
- while
- for
- do~while
- break及continue
- 数组
- 一维数组
- 创建及初始化
- 二维数组
- 创建及初始化
- 指针
- 一阶指针
- 创建及初始化
- 多变的*号
- 指针的算术运算
- 指针与数组
- 二阶指针
- 创建及初始化
- 函数
- 常用函数的介绍
- 创建自己的函数
- 函数调用
- 形参与实参
- 结语
打开你的C语言编译器,输入以下代码,成为你的第一条代码。
#includeint main(void) { printf("hello world"); return 0; }
其中以.h结尾的叫做头文件,我们一般用#include包含头文件。
main()为函数主体,int 为main函数的返回类型,若main前面没有指定返回类型,则默认为int,为了增强代码规范性,我们一般不省略。
#includemain(void)···
void为main函数的输入类型,当输入类型为void时可省略。
printf()为头文件stdio.h定义的输出函数,在显示屏输出信息。
return 0中的0与main的返回类型int相对应都为整形。
一个大型程序的开发往往都是一个团队,代码良好的规范性就是两人之间交流的桥梁。规范的代码也可以帮助自己处理bug。
写作格式1.缩进
缩进是最常用的调整格式的方法。合适的缩进可以展现代码的层次感,提高代码的可读性。
需要注意的是因为电脑的差异tab键产生的空格会不同,因此建议使用四个空格进行缩进。
2.大括号
在if、for等结构后有大量代码时,将代码用{}括起来。
不使用大括号
#includeint main() { for(int i=0;i<5;i++) if(i==3) break; else printf("还不如用大括号n"); return 0 }
使用大括号
#includeint main() { for(int i=0;i<5;i++) { if(i==3) { break; } else { printf("有括号很明显for、if的作用范围n"); } } return 0; }
当代码多起来的时候不用大括号很难判断for、if等语句的作用范围。
命名C语言的标识符除了关键字,用户还可以自己定义。例如上面我们定义的i就是。自定义标识符要遵守以下几个规则才能被编译器识别,1.自定义标识符只能由英文字母、阿拉伯数字、下划线_组成。2.自定义标识符不能与C语言提供的关键字相重复。3.自定义标识符一般不超过32个字符。
建议自定义标识符能见字知意,例如show_all_info表示"show all infomation"展示所有的信息。
良好的注释往往可以提高程序的可读性,是沟通的桥梁,因此注释是非常有必要的。
在C语言中,单行注释使用"//“,多行注释使用”",例如
#includeint main() { for(int i=0;i<5;i++) { if(i==3)//如果i等于3,则执行break语句 { break; } else { printf("有括号很明显for、if的作用范围n"); } } return 0; }
需要注意的是注释在代码编译的时候,编译器会自动略过,对程序不产生影响。
变量与赋值在C语言中包括常量如1、2、3、'ch’等,我们无法改变。还包括变量,例如上面的i就是变量,它的值随着程序的运行从0变到5。
简单类型 数值型用于储存数值的变量即为数值型变量,不同数值类型由不同的关键字定义,其能储存的数值范围也不同,自然其储存占用的空间也不同。
| 数据类型 | 类型标识符 | 占用内存/B | 数值范围 |
|---|---|---|---|
| 有符号短整型 | [signed] short [int] | 2 | − 2 15 ∼ 2 15 − 1 -2^{15} {}sim 2^{15}-1 −215∼215−1 |
| 有符号整型 | [signed] [int] | 4 | − 2 31 ∼ 2 31 − 1 -2^{31}sim2^{31}-1 −231∼231−1 |
| 有符号长整型 | [signed] long [int] | 4 | − 2 31 ∼ 2 31 − 1 -2^{31}sim2^{31}-1 −231∼231−1 |
| 无符号短整型 | unsigned short [int] | 2 | 0 ∼ 2 16 − 1 0sim 2^{16}-1 0∼216−1 |
| 无符号整形 | unsigned int | 4 | 0 ∼ 2 32 − 1 0sim 2^{32}-1 0∼232−1 |
| 无符号长整型 | unsigned long [int] | 4 | 0 ∼ 2 32 − 1 0sim 2^{32}-1 0∼232−1 |
| 单精度浮点 | float | 4 | − 2 38 ∼ 2 38 − 1 -2^{38}sim 2^{38}-1 −238∼238−1 |
| 双精度浮点 | double | 8 | − 2 308 ∼ 2 308 − 1 -2^{308}sim 2^{308}-1 −2308∼2308−1 |
备注:float的有效位是7,double的有效位是16
特别要注意的是当数值不在所定义的类型的范围的时候,会发生数据溢出的情况,此时编译器不会报错。
#includeint main() { short a=32768;//short的范围为-32768~32767 short b=32769; printf("a=%d,b=%d",a,b);//本应该为32768,32769的,但结果不是。可以推断出C语言的计数方式是循环的。 return 0; }
结果如下
1.字符型常量与字符串常量
顾名思义,一个字符的为字符型常量,多个字符的为字符串常量
字符型常量:‘x’,‘X’,’ ',‘0’等用’'引起来的以及转义字符序列n等
字符串常量:“nwafu"等用”"引起来的
以下为转义字符序列及其功能
| 转义字符 | 功能 | 转义字符 | 功能 |
|---|---|---|---|
| b | 退格 | \ | 反斜线字符 |
| f | 换页 | ’ | 单引号字符 |
| n | 换行 | " | 双引号字符 |
| r | 回车 | ddd | 1~3位八进制数表示的字符 |
| t | 水平跳格 | xdd | 1或2位十六进制树表示的字符 |
2.字符型变量
使用关键字char创建字符型变量和字符串变量,在C语言中,用字符变量储存字符型常量,用字符数组储存字符串变量。
#include运算符号说明 赋值运算符int main() { char a='o';//创建字符变量储存字符型常量 char b[]="nwafu";//创建字符数组储存字符串常量 printf("%ct%s",a,b); return 0; }
赋值运算符为“
=
=
=”,还有许多复合赋值符——算术运算符与等号结合,例如
a
+
=
b
a+=b
a+=b与
a
=
a
+
b
a=a+b
a=a+b的效果一致,其他复合赋值符作用以此类推。使用复合赋值付可以使代码更紧凑。需注意赋值符的左边只能是变量,不能为常量。
当赋值符号左右两边变量的类型不同时,会强制转化为符号左侧变量的类型
例如:想将double类型的b赋值给int型的a,得到的将会是int型
#includeint main() { int a=10; double b=10.0; a=b; printf("%lf",a); return 0; }
其结果为0.000000,当printf的输出类型为%d时,结果为10。
算数运算符算数运算符包括“
+
+
+”、“
−
-
−”、“
∗
*
∗”、“
/
/
/”。
需注意的是当不同数值型变量进行运算时,会进行隐形的强制类型转换:
char、short
→
rightarrow
→int
→
rightarrow
→unsigned
→
rightarrow
→long
→
rightarrow
→float
→
rightarrow
→double。
例如下面的例子,将int型的变量a与double型的变量b相加并打印,我们比较不同的输出格式对结果的影响。
#includeint main() { int a=10; double b=10.0; printf("%d",a+b); return 0; }
其结果是0;
但当printf处的输出格式为%lf时,其结果为20.000000。
关系运算符有 < < <、 > > > = = == ==、 ! = != !=、 < = <= <=、 > = >= >=,用于比较数的大小。
逻辑运算符逻辑运算符有“
!
!
!”、“
∣
∣
||
∣∣”、“
&
&
&&
&&”,其含义分别为非、或、且,他们的含义都比较简单。
注意当多个关系运算符复合使用时,需添加“()”改变运算顺序。
例如:你想表达1小于2小于,那么他的代码应该是1<2&&2<3而不应该是1<2<3
if
∼
sim
∼else的基本用法为if(表达式)语句;当表达式的值不为0时执行语句,当表达式的值为0时,不执行该语句。
例如:
if(1<2)a=1;
此处的表达式为
1
<
2
1<2
1<2,语句为
a
=
2
a=2
a=2,此时
1
<
2
1<2
1<2的值为真即
1
<
2
1<2
1<2的值为1,故执行语句
a
=
1
a=1
a=1。
需注意if及下面将要介绍的while等结构后的语句表示if后第一个“;”前的语句,若想执行多条语句,则需要使用“{}”构成复合语句。
例如:
#includeint main() { int a=0; int b=0; if(1>2)a=1;b=2; printf("%dn%d",a,b); return 0; }
我们想如果 1 > 2 1>2 1>2,那么a=1,b=2;否则a=0,b=0。然而结果是a=0,b=2;原因是当if的表达式为0时,不执行a=1。然后if语句结束。即无论if中的表达式为何值,都会执行b=2;如果想实现“如果 1 > 2 1>2 1>2,那么a=1,b=2;否则a=0,b=0。”那么代码应该改为
if(1>2){a=1;b=2;}
形成复合语句。
多分支选择结构
if(表达式1)语句1;
if(表达式2)语句2;
if(表达式3)语句3;
…
dots
…
多分支选择结构除了以上表达方式,还可以用接下来要介绍的swith
∼
sim
∼case结构。
其常见结构如下,可以较方便的实现多分枝选择结构
swith(表达式)
{
case 常量表达式1:语句1;
case 常量表达式2:语句2;
case 常量表达式3:语句3;
...
case 常量表达式n:语句n;
default:语句n+1
}
使用swith
∼
sim
∼case需注意的是swith(表达式)中的表达式类型只能是int。
其执行顺序:从第一个case分别比对,若case的常量与表达式相同,则执行对应语句,直到遇到break,否则跳过该语句,进行下一个case的比对。直至所有case完成比对。
case后的常量表达式不能用来进行比较。
default可以放在任意位置,但我们习惯上放在最后
#include循环结构 whileint main() { int x=3;//x为int型 switch(x) { case 1:printf("x=1");//分别比对1,2,跳过 default:printf("I don't know x");//将default放在任意位置都可以 case 2:printf("x=2"); case 3:printf("x=3");break;//比对x,相等,打印出x=3,在遇到break时跳出switch~case结构 } return 0; }
while的原型while(表达式)循环体;
当表达式为真进入循环体,表达式为假跳过循环体。与if类似,循环体是while后第一个";“前的句子,若想执行多个语句,可以使用一个”{}"构成复合语句。
#includeforint main() { while(2<3)//对表达式进行判断,为真,进入循环体,循环体由复合语句 //循环体由两个句子组成复合语句 { printf("2<3"); printf("It is right"); } return 0; }
原型:for(表达式1;表达式2;表达式3)循环体;
表达式1通常为循环变量的初始化,表达式2通常用于判断是否进入循环体,表达式3通常用于循环变量的运算。
先执行表达式1,然后执行表达式2,若表达式2为真,则进入并执行循环体,然后再执行表达式3,若表达式2为假则跳过循环体。
for的3个表达式都可以省略,但表达式之间的";"不可以省略。
#includeint main() { for(int i=0;i<3;i++)//对循环变量i进行初始化,并判断i是否小于3,最后对i进行自增处理 { printf("%d",i); } return 0; }
使用如下代码也可实现上面的功能
#includeint main() { int i=0;//循环变量的初始化 for(;;) { printf("%d",i); if(i>=2)break;//判断i是否小于3 i++;//循环变量的自增处理 } return 0; }
但第二种表达方式我们不常用,它没有第一种紧凑、直观。
do~while原型:do{循环体}while(表达式);
do~while是先执行一次循环体再进行表达式的判断,表达式为真则再次进入循环体,否则跳过循环体。
需注意while后的";"不可省略。
数组是包含多个数据的有序(位序)的集合。也就是说将一些类型相同的数据排成排放在储存空间中。
一维数组 创建及初始化数组的创建与变量相同,例如int arr[5];char str[5];分别创建了一个储存int变量的数组和char变量的数组。
数组的初始化与变量也有相同之处,例如int arr[5]={1,2,3,4,5};数组的初始化是将初始化的内容放在{}中并用","分隔。当{}中的个数大于数组大小时,编译器会报错,当{}中的个数小于数组大小时,将{}中的值赋给数组前面的,其余补成0或对应空值。
数组的命名与上面介绍的变量的命名是一样的
#includeint main() { int arr[5]={1,2,3}; //{}内个数小于数组大小,仅对前面几个进行初始化即arr[0]=1,arr[1]=2,arr[2]=3; //其余都初始化为0,即arr[3]=0,arr[4]=0; for(int i=0;i<5;i++)printf("%d",arr[i]); return 0; }
数组的引用:我们用数组名[下标]对数组进行引用,如上面代码中的arr[0],arr[1]。
二维数组 创建及初始化二维数组是在一维数组的基础上多加了一维。二维数组的创建及初始化与一位数组相类似,例如int arr[4][4];char str[4][4]分别创建了横纵都为4的数组分别储存着int,char类型的数据。
int arr[4][4]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; char str[4][4]={"how","are","you"};
二维数组的初始化与一位数组也类似,当{}内个数大于数组大小时,编译器将会报错,当{}内个数小于数组大小时,其余都被赋0或对应空值。
在前面申明一个变量时,每个变量都会在内存中申请一个地址用于储存变量。在C语言中我们用指针去储存变量的地址。
一阶指针 创建及初始化原型:数据类型 *指针变量名;
例如int *p=NULL;创建了一个名为p的int型的指针。
指针的初始化:int a=0;int *pa=&a;对指针pa进行初始化,将a的地址赋给pa。其中的&为寻址符号。
在我们刚学C语言时,指针往往难以理解,其实我们可以将变量比作酒店的房间,指针就是房间的门牌号,是一个储存房间位置的变量。
在数值运算时*号是数学中乘的含义,在指针创建时是指针标志的含义。
*还有一个含义是间接寻址运算符,int a=0,*pa;pa=&a;创建并初始化指针pa,对指针pa进行间接寻址运算*pa=2;其作用与a=2是一样的。
在上面我们介绍了数组,其实数组名就储存着这个数组第一个变量的地址。
int arr[5]={1,2,3},*pa_begin,*pa_end;//数组、指针的创建
pa_begin=arr,pa_end=&arr[4];//将数组第一个位置赋给pa_begin,将数组最后一个位置赋给pa_end。
//我们也可以用pa_end=pa_begin+5将数组最后一个位置赋给pa_end。
C语言支持指针相减的,如pa_end-pa_begin其表示pa_begin到pa_end之间有多少个数。
指针与数组在数组部分我们用下标的方式对数组进行引用,其实我们也可以用指针的方式对数组进行引用。
#include二阶指针 创建及初始化int main() { int arr[5]={1,2,3},*pa; pa=arr; *(pa+1)=2;//对数组arr[1]赋值2; printf("%d",arr[1]); }
原型:数据类型**指针名
例如int**ip,char**cp。分别创建了一个名为ip,类型为int和一个名为cp,类型为char的二阶指针。
初始化方式为:
int a=10; int *p=&a; int **ip=&p;
他们用于存储一个指针的地址,当然此处的&a可以为取一个一维数组名的地址。
函数 常用函数的介绍函数由函数名、函数返回类型、传入参数、函数体,返回值,五部分组成,函数可以帮助我们将有特殊功能需重复使用的代码进行封装,以提高代码的高效使用。在一开始我们就已经学习了一个不可或缺的函数——main函数,我们第一个程序就是由main函数实现的。
#includeint main() { printf("hello world"); return 0; }
其中main为函数名,int为函数返回类型,()内的为传入参数,此处传入空,printf(...)为函数体,returnn 0为返回值。
我们在前面已经学习了的printf(),scanf()等函数均为前人为了方便使用已经封装好的函数,并将其储存在在stdio.h头文件中,我们仅需要了解该函数怎么用、有什么用就可以了,不必要理解它具体是怎么实现的。
在开发程序过程中,靠前人写好的函数是不够的,往往需要我们根据具体问题编写具体的函数。
函数的原型:
数据类型 函数名(传入参数)
{
函数体
[return 返回值]
}
我们创建一个以下简单函数
void swap(int a,int b)//用于将a,b的值进行交换
{
int c;
c=a,a=b,b=c;
}
该函数的作用为将两个int型的数据相加并返回。
需注意的是return返回值的类型必须与函数返回类型一致。
调用自己写的函数与调用printf函数是差不多的。
#include形参与实参int main() { int a=10,b=5; swap(a,b);//使用c接受a+b的返回值。 printf("a=%d,b=%d",a,b); return 0; }
我们考虑如下两个函数的不同。
void swap1(int a,int b)
{
int c;
c=a,a=b,b=c;
}
void swap2(int *a,int *b)
{
int *c;
c=a,a=b,b=c;
}
很明显我们从形式上看就发现swap1传入两个int值,swap2传入两个int值的地址。我们将代码运行发现,swap1并未将a,b的值进行交换,而swap2则将a,b的值进行了一个交换。
其中的原因很简单,swap1函数出入的为形参,仅仅将a,b的值在swap1函数作用范围内将值进行了交换,而swap2函数是将a,b的地址传入,我们是将a,b的地址进行了交换。
以上简单的仅介绍了C语言的基础内容,C语言的内容远不及这些,在学完以上内容后,希望大家继续在C语言领域深耕学习更高阶的内容。



