提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
本文将介绍C语言的基础知识,包括数据类型,运算符,表达式,语句,循环,分支,跳转,函数,数组,结构体,联合体,指针和宏定义等
提示:以下是本篇文章正文内容,下面案例可供参考
数据类型决定:
特点:无小数点,有范围限制
三种表示形式:
十进制整数:由数字0~9和正负号表示。 如123,-456,0
八进制整数:由数字0开头,后跟数字0~7表示。 如0123,011
十六进制整数:由0x或0X开头,后跟0~9,a~f,A~F表示。 如0x123,0Xff
长整型常量:789L、017L、0x12aL(用l或L引出)
2.实型常量
特点:带小数点的数,绝对值很大但不带小数点的数
表示方式:小数 例:12.3
指数形式 例:1.23e1
3.字符常量
特点:用‘’括起来的单个普通字符或转义字符
表示方式:普通字符 例: ‘a’
转义字符 例: ‘\n’
字符的ASCII码值
4.字符串常量
字符串:双引号括起来的一串字符
字符串结束标志:’\0’
字符串的内部表示方法
注意:
字符和字符串表示形式的区别
数字和数字字符的区别
空字符‘\0’和空格字符‘ ’的区别
5.符号常量
特点:利用预处理命令定义
例如:#define PI 3.14
运算符:C语言中描述数据运算的特殊符号。
表达式:用运算符将C语言的各种运算对象连接起来,组成符合C语法要求的式子。
##C的运算符的三要素:
优先级(决定混合运算中的先后次序)
几目 (操作数的个数)
结合方向
五种基本算术运算符
加法运算符或正值表达式(+)
减法运算符或负值表达式(-)
乘法运算符(*)
除法运算符(/)
求余运算符(%)两端必须均为整型
算术表达式
由算术运算符、括号和任何有值的对象连接起来的符合C语言要求的式子称为算术运算表达式
2.自增(减)运算符与表达式
*自增(++)、自减(- -)运算
作用:自增运算使单个变量的值加1,自减运算使单个变量的值减 1
*表达式: 变量++(++变量)
1)自增、自减运算符单独使用时,前置和后置运算方法完全相同。
2)自增、自减运算符和其他运算符组成复合表达式时前置和后置运算是两种不同的方法:
a. 前置运算──运算符放在变量之前: ++变量、–变量 先自增(减)后运算
b.后置运算──运算符放在变量之后:变量++、变量-- 先运算后自增(减)
说明:
自增、自减运算,常用于循环语句和指针变量中。
自增、自减运算符,不能用于常量和表达式。
在表达式中,最好避免连续使同一变量进行自增或自减运算
3.赋值运算符与表达式
简单的赋值运算符 :=、
功能:将一个数据值写入到变量对应的内存空间中。
赋值表达式:变量=确定的值 例如:a=4; c=a+b;
赋值表达式的值即变量的值。
4.复合赋值运算
复合赋值运算符是由赋值运算符之前再加一个双目运算符构成的。
复合赋值运算的一般格式为:
变量 双目运算符 = 表达式
└──┬──┘
复合赋值运算符
等价于:变量= 变量 双目运算符 (表达式)
求解:变量=变量 <运算符>表达式
C 语言规定的10 种复合赋值运算符如下:
+= -= = /= %= /复合算术运算符 5 种/
&= ^= |= <<= >>= /复合位运算符 5种/
例如:
x += 3 / 等价于x=x+3 /
y = x + 6 / 等价于y=y(x+6),而不是 y=y*x+6 */
5.位运算符
&:只有参与运算的两个二进位均为1时,结果位才为1,否则为0,参与运算的数以补码方式出现
0&0=0 0&1=0 1&0=0 1&1=1
| :只要参与运算的二个二进位有一个为1时,结果位就为1,参与运算的两个数均以补码出现
0|0=0 0|1=1 1|0=1 1|1=1
^ :参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1,参与运算数仍以补码出现。 相同为0,不同为1
0^0=0 0^1=1 1^0=1 1^1=0
>>:把“>>”左边的运算数的各二进位全部右移若干位,“>>”右边的数指定移动的位数,对于有符号数,在右移时,符号位将随同移动。当为正数时,最高位补0,而为负数时,很多系统规定为补1。
<<:把“<<”左边的运算数的各二进位全部左移若干位,由“<<”右边的数指定移动的位数,高位丢弃,低位补0
~:对参与运算的数的各二进位按位求反
注意:
运算对象只能是整型或字符型的数据,不能为实型数据
位运算主要是针对二进制位的运算
6.条件运算符
条件运算符是C语言中唯一一个三目运算符(Ternary Operator),带三个操作数,它的形式是表达式1 ? 表达式2 : 表达式3
这个运算符所组成的整个表达式的值等于表达式2或表达式3的值,取决于表达式1的值是否为真,可以把它想像成这样的函数:
if (表达式1) return表达式2; else return表达式3;
7.逗号运算符
逗号运算符也是一种双目运算符,它的形式是表达式1, 表达式2
,两个表达式不要求类型一致,左边的表达式1先求值,求完了直接把值丢掉,再求右边表达式2的值作为整个表达式的值。逗号运算符是左结合的,类似于±*/运算符,根据组合规则可以写出表达式1, 表达式2, 表达式3, ...
, 表达式n这种形式,表达式1, 表达式2可以看作一个子表达式,先求表达式1的值,然后求表达式2的值作为这个子表达式的值,然后这个值再和表达式3组成一个更大的表达式,求表达式3的值作为这个更大的表达式的值,依此类推,整个计算过程就是从左到右依次求值,最后一个表达式的值成为整个表达式的值。
注意,函数调用时各实参也是用逗号隔开,那个逗号不能看作逗号运算符。但可以这样:
f(a, (t=3, t+2), c)传给函数f的有三个参数,第二个参数的值是表达式t+2的值。
C语句分为以下五类:
1.控制语句(9条)
2.表达式语句
3.空语句
4.复合语句
5.函数调用语句
1.控制语句
条件判断语句:
if语句 (用于实现双分支选择)
switch语句 (用于实现多分支选择)
循环执行语句:
do while语句 (用于实现直到型循环)
while语句 (用于实现当型循环)
for语句 (用于实现当型循环)
转向语句:
break语句
continue语句
goto语句
return语句 (函数返回语句)
2.表达式语句
表达式语句由一个合法的C语言表达式加上分号“;”组成。
一般形式为: 表达式;
3.空语句
只有分号“;”组成的语句
一般用来完善选择结构和循环结构
4.复合语句
用{}把多条语句括起来成为复合语句,又称块语句
5.函数调用语句
由函数名、实际参数加上分号“;”组成。
一般形式为:
函数名(实际参数表列);
在C语言中有四条可以实现循环结构的语句:
1)while 语句
2)for 语句
3)do – while 语句
4)if – goto 语句
1.while 语句
功能:用于实现当型循环结构
一般形式:`
while(逻辑量)
{ 循环体语句;}
当逻辑量值为真的时候,执行循环体语句
注意事项:
循环体有可能一次也不执行
尽量避免无限循环,如:while(1)死循环
循环体内可以加入break、return、goto结束循环
循环体内包含一个以上的语句,应该用{}括起来组成复合语句。
2.do-while循环
功能:用于实现直到型循环
一般形式:
do
{
循环体语句;
}while(逻辑量);
执行循环体语句,直到逻辑量为假结束
注意while(逻辑量)后边的“;”
3.for语句
功能;用来实现当型循环
一般形式:
for(表达式1;表达式2;表达式3)
{
循环体语句;
}
执行过程:
1.先计算表达式1
2.计算表达式2,为真执行循环体语句,否则结束循环
3.计算表达式3
4.转到第二步继续执行
for语句使用最多的情况:
for(循环变量赋初值;循环条件;循环变量增量)
{
循环体语句;
}
注意:for语句后边括号中的三个表达式可以省略,可是括号中的两个分号不能省略
for语句格式补充说明:
语法格式:
for(表达式1;表达式2;表达式3)
循环体语句;
循环体多步操作构造复合语句
表达式1、2、3均可省略
表达式1省略:循环控制变量之前已初始化
表达式2省略:条件为真
表达式3省略:循环体内处理
‘;’是格式要求,不能省略
循环嵌套
三种循环可互相嵌套,层数不限
外层循环可包含两个以上内循环,但不能相互交叉
嵌套循环的执行流程
嵌套循环的跳转
while()
{ ……
while()
{ ……
}
…...
}
do
{ ……
do
{ ……
}while( );
…...
}while( );
while()
{ ……
do
{ ……
}while( );
…….
}
for( ; ;)
{ ……
do
{ ……
}while();
……
while()
{ ……
}
…...
}
break 和continue语句
为了使循环控制更加灵活,C语言提供了break 语句和continue 语句。
一般格式
break;
continue;
功能
break :强行结束循环。
continue :结束本次循环,跳过循环体其余语句,转向执行下次循环。
注意:
break 能用于循环语句和switch 语句中,continue 只能用于循环
循环嵌套时,break 和continue 只影响包含它们的最内层循环,与外层循环无关。
1.if语句
形式1:
if(表达式)语句
若需要多个语句,则应该使用花括号标识,使一组语句构成复合语句
形式2:
if(表达式)语句1
else语句2
形式3:
if(表达式1)语句1
else if(表达式2)语句2
else if(表达式3)语句3
……
else if(表达式m)语句m
else 语句n
2.switch语句
switch(表达式)
{undefined
case 常量表达式1:语句1
case 常量表达式2:语句2
……
case 常量表达式n:语句n
default:语句n+1
C 语言中关于函数的约定:
一个C程序可以由多个文件组成;
一个源程序文件由一个或多个函数组成,但有且仅有一个main()函数
C程序从main()开始执行,由主函数结束
函数之间的关系相互独立,不存在从属关系
函数之间是通过函数调用来连接的。
主函数只能调用别的函数,但不能被别的函数调用
其他自定义函数既可调用别的函数,又可被别的函数调用
函数的一般形式:
类型说明符 函数名(形参表列)
{
数据描述;
算法实现;
}
1.有值函数
定义的方法:
确定函数的原型
实现函数的功能
有值函数需要给主调函数一个返回值,使用return语句实现。
return语句的一般格式:
return(表达式); 或 return 表达式;
功能
向主调函数带回一个返回值;
释放在子函数运行中分配的所有内存空间;
结束该被调函数的执行,使程序流程跳转至主调函数继续执行;
函数类型与return语句中表达式的值数据类型不一致时,以函数类型为主。
2.无值函数
无值函数无需给主调函数带回返回值,此类函数的类型为void,函数体中省略return语句。
3.函数的声明及调用
在C语言中,用户可以根据需要调用任何函数来完成某种处理,一个函数调用另一个函数称为函数调用。
其中调用者称为主调函数,被调用者称为被调函数
函数调用可以作为表达式中的一个分量,也可以单独构成语句。
4.无参函数
在函数的声明、定义和调用中均不带参数,特点:在调用无参函数主调函数并不将数据传输给被调用函数,此类函数通常被用来完成指定的功能,可以返回或不返回函数值。
一般表达式
类型说明 函数名()
{
// 函数体
}
*/
int max()
{
// 函数体
}
空函数 无函数体
类型说明 函数名()
{
//无函数体 因程序设计需要,确定模块需求 先占位置 后在补上
}
int max()
{
}
5.有参函数
在函数定义、声明都都有参数。特点:主调函数调用被调函数时,主调函数必须把值传输给形参,以供被调函数使用
int max(int a,int b) // 有参函数
{
函数体
}
函数的参数有两类:形参和实参
函数定义时的参数称为形参,参数在函数未被调用时是没有确定值的,只是形式上的参数
函数调用时使用的参数称为实参
#include "stdio.h"
void order(int a,int b) // a,b为形式参数(形参)
{
int t;
if(a>b) // 如果a>b,就执行一下3条语句
{
t=a;
a=b;
b=t;
}
printf("从小到大的顺序:%d %d\n",a,b); // 输出交换后的a,b的值
}
void main()
{
int x,y;
printf("请输入两个整数"); // 键入两个整数
scanf("%d%d",&x,&y);
order(x,y); // x,y为实际参数(实参)
}
1、参数可以是常量,变量,其他构造数据类型或表达式,调用时可写成
order(2,3); // 实参时常量
order(x+y,x-Y); // 实参时表达式
实参是表达式时,先计算表达式的值,再将实参的值传递个形参,但要求它有确切的值,因为调用是要将值传递给形参的。
2、定义函数时必须说明形参的类型,形参只能是简单的变量或数组,不能是常量或表达式
3、函数被调用前,形参不占内存的存储单元;调用以后,形参才被分配内存单元;函数调用结束后,形参所占用的内存也被收回或者释放。
4、实参的个数、出现的顺序和实参的类型,应该与函数定义中形参的设计一一对应。
函数参数的传递方式
c语言规定,实参对形参的数据传递是“值传递”,即单向传递,只是把实参的值传递给形参,而不能把实参的值再传递给实参。再内存当中,实参与形参是不同的单元,不管名字是否相同,因此函数中对形参值的任何改变都不会影响到实参的值。
例如:
#include "stdio.h"
void swap(int a,int b) // 自定义函数 无返回值类型的有参函数
{
int temp;
temp=a;a=b;b=temp; /*交换a,b的值*/
printf("a=%d,b=%d\n",a,b);
}
void main()
{
int x,y;
printf("请输入两个整数:\n");
scanf("%d%d",&x,&y); // 输入两个整数
printf("调用函数之前\n");
printf("x=%d,y=%d\n",x,y);
// 输出调用swap函数之前x,y的值
printf("调用函数中:\n");
swap(x,y); // x,y 实参
printf("调用函数之后:\n");
printf("x=%d,y=%d\n",x,y); // 输出调用swap函数之后x,y的值
}
函数调用
C程序是从主函数main()开始执行的,以main()函数体结束为止在函数体的执行过程中,通过不断地对函数的调用来执行的。
调用者 被称为主调函数一般为main()函数,
被调用者 称为被调函数一般为自定义函数或者库函数。
被调函数执行结束,从被调函数结束的位置再返回主调函数当中,继续执行主调函数后面的语句。
函数调用的三种格式
1.函数调用语句
beep();
2.将有值函数调用参与表达式构成语句
x=max(a,b);
3.有参函数的调用作为另一个函数调用的实际参数
y=max(max(a,b),c);
函数的嵌套调用
C语言不允许嵌套定义函数,但可以嵌套调用函数,即在调用一个函数的时候调用另一个函数
函数的递归调用
函数在其函数体内直接或间接调用自身称为函数的递归调用,在递归调用中主调函数又是被调函数
例如:
#include
void main()
{ int m;
double fac;
scanf("%d",&m);
fac=fact(m);
printf("%d!=0.0lf\n”,m,fac);
}
double fact(int n)
{ double f;
if(n>1)
f=n*fact(n-1);
else f=1;
return f;
}
1.一维数组
1)一维数组的定义
数组的维数是指表示数组使用的下标个数,如果数组中每个元素只带有一个下标,称这样的数组为一维数组。
定义形式为:
类型说明符 数组名[常量表达式];
类型说明符指出数组元素的数据类型
数组名是标识符
元素个数使用方括号和常量表达式
2)一维数组的引用
引用数组实际上是逐个引用数组的每一个元素
方法:数组名[下标]
int a[10] ;
数组元素:a[0] ,a[1] ,a[2] … a[9]
数组元素的下标只能是整型表达式,且应在有效范围内引用
3)一维数组初始化
一维数组定义时可以用花括号对全部或前面一部分数组元素赋初值,叫初始化。
例如:int a[5]={1,2,3,4,5};
说明:
可以只对部分元素赋初值
长度可以省略
不初始化时,数组元素值为随机值
不能对数组整体访问(引用)
4)数组元素的访问方法
注意:
用 数组名[下标]和*(指向数组的指针变量)都可以表示数组的各个元素。
指向数组元素的指针变量是一个变量,而数组名则是一个常量
使用指向数组元素的指针变量时,必须注意指针变量的当前值
指向数组元素的指针变量允许指向数组以外的内存单元。
2.二维数组
1)二维数组的定义
二维数组:数组中每个元素带有两个下标。
定义形式为:
类型说明符 数组名[整型常量表达式1] [整型常量表达式2];
逻辑上,可把二维数组看成是一个矩阵,常量表达式1 表示矩阵有几行,常量表达式2 表示矩阵的列数。
可以把二维数组看作是一种特殊的一维数组,它的元素又是一维数组。即二维数组是数组的数组。
2)二维数组存储
二维数组在内存中占据一系列连续的存储单元,数组元素按行顺序存放,先放行下标是0 的元素,再放行下标是1 的元素,以此类推…
3)二维数组的引用
二维数组的引用(逐个引用数组的每一个元素)
引用二维数组元素时必须带有两个下
标,形式如下:
数组名[下标1][下标2]
引用时应该分别控制数组的两个下标的变化(使用循环的嵌套)
4)二维数组初始化
二维数组定义时也可以用花括号对全部或前面一部分数组元素初始化。
按行对二维数组初始化
int a[2][3]={{1,2,3},{4,5,6}};
按存储顺序对二维数组初始化
int a[2][3]={1,2,3,4,5,6};
说明:
全部元素初始化
float data[3][2]={{1.0,2.0},{3.0,4.0},{5.0,6.0}};
float data[3][2]={1.0,2.0,3.0,4.0,5.0,6.0};
可以省略第一维长度
float data[ ][2]={{1.0,2.0},{3.0,4.0},{5.0,6.0}};
float data[ ][2]={1.0,2.0,3.0,4.0,5.0,6.0};
部分元素初始化
必须按行赋值
int a[2][3]={1,2};
int a[2][3]={{1,2,3}, {4,5,6} };
int a[3][4]={{1,2}, {3}, {4,5},{6}}; 错误
int a[3][4]={{1,2},{3}};
int a[2][3]={1,2,3,4,5,6,7,8}; 错误
int a[][3]={ {1,2,3},{4,5},{6}}; 错误
int a[][3]={ 1,2,3,4,5,6,7};
指针是C语言的一个重要概念,也是C语言的一个重要特色。正确而灵活地运用它,可以有效地表示复杂的数据结构
能动态分配内存;
能方便地使用字符串;
有效而方便地使用数组;
在调用函数时能得到多于1个的返回值;
能直接处理内存地址等;
1.定义一个指向变量的指针变量
指针变量的定义包含三个方面的内容:
指针类型说明,即定义变量为一个指针变量
指针变量名
变量值(指针)所指向的变量的数据类型。
格式: 存储类型 *指针变量名;
2.指针变量的赋值
初始化:例:int x,*p=&x;
先定义,后赋值:例:
int x,*p;
p=&x;
用初始化了的指针变量给另一指针变量赋值
例:
int x, *p1=&x;
int *p2=p1;
注意:
指针变量中只能放地址值(指针)
指针变量中只能放指定类型的变量的地址
3.指向变量的指针变量的应用
与指针有关的运算符有两个:
& :取址运算符
功能:取变量地址;单目,右结合。
类型标识符 (*指针变量名)(形参表列);
类型标识符表示指针变量可以指向的函数返回值的类型
例:
long (*pf)(int),fac(int),m;
pf=fac;
m=(*pf)(10);
2)返回指针值的函数
函数的返回值是指针值
定义形式:
类型标识符 *函数名(形参表列)
{
函数体
}
5.多级指针
二级指针
指向指针的指针:即指向指针变量的指针变量
定义形式:
类型标识符 **指针变量名;
例:int a,*ap=&a;
int **app=≈
二级指针变量经常结合指针数组使用
多级指针定义形式:
类型说明符 **…*指针变量名;
类型说明符表示该指针变量所指向的最终目标变量的类型
1.结构体概述
“结构”是一种构造类型,它是由若干“成员”组成的。每一个成员可以是一个基本数据类型或者又是一个构造类型。
结构体是一种自定义数据类型。
用途:把不同类型的数据组合成一个整体----自定义数据类型
struct [结构体名]
{
类型标识符 成员名;
类型标识符 成员名;
…………….
};
注意 struct是关键字,不能省略
结构体类型定义描述结构的组织形式,不分配内存
2.结构体变量的定义
1.先定义结构体类型,再定义结构体变量
一般形式:
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
struct student stu1,stu2;
2.定义结构体类型的同时定义结构体变量
一般形式:
struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
}变量名表列;
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
3.直接定义结构体变量
一般形式:
struct
{
类型标识符 成员名;
类型标识符 成员名;
…………….
}变量名表列;
例 struct
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
结构体类型与结构体变量概念不同
类型:不分配内存; 变量:分配内存
类型:不能赋值、存取、运算; 变量:可以
结构体可嵌套
结构体成员名与程序中变量名可相同,不会混淆
结构体类型及变量的作用域与生存期
3.结构体变量的初始化
形式一
struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
};
struct 结构体名 结构体变量={初始数据};
形式二:
struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
}结构体变量={初始数据};
形式三:
struct
{
类型标识符 成员名;
类型标识符 成员名;
…………….
}结构体变量={初始数据};
4.共用体
构造数据类型,也叫联合体
用途:使几个不同类型的变量共占一段内存(相互覆盖)
共用体类型定义
定义形式:
union 共用体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
};
5.共用体变量的定义
形式一:
union data
{ int i;
char ch;
float f;
}a,b;
形式二:
union data
{ int i;
char ch;
float f;
};
union data a,b,c,*p,d[3];
形式三:
union
{int i;
char ch;
float f;
}a,b,c;
1.不带参数的宏定义
宏定义一般形式为:
#define 标识符 字符串
例如:#define PI 3.1415926
宏定义的作用是在本程序文件中用指定的标识符PI来代替“3.1415926”这个字符串,在编译预处理时,将程序中在该命令以后出现的所有的PI都用“3.1415926”代替。
这个标识符(名字)称为“宏名”
在预编译时将宏名替换成字符串的过程称为“宏展开”。#define是宏定义命令
说明:
(1) 宏名一般习惯用大写字母表示,以便与变量名相区别。但这并非规定,也可用小写字母。
(2)宏定义是用宏名代替一个字符串,只作简单置换,不作正确性检查。只有在编译已被宏展开后的源程序时才会发现语法错误并报错。
(3)宏定义不是C语句,不必在行末加分号。如果加了分号则会连分号一起进行置换。
(4)在进行宏定义时,可以引用已定义的宏名,可以层层置换。
(5)宏定义是专门用于预处理命令的一个专用名词,它与定义变量的含义不同,只作字符替换,不分配内存空间。
2.带参数的宏定义
作用:不仅进行简单的字符串替换,还要进行参数替换。
带参数的宏定义一般形式为:
#define 宏名(参数表) 字符串
字符串中包含在括弧中所指定的参数
带参数的宏和函数的区别:
(1) 函数调用时,先求出实参表达式的值,然后代入形参。而使用带参的宏只是进行简单的字符替换。
(2) 函数调用是在程序运行时处理的,为形参分配临时的内存单元。而宏展开则是在编译前进行的,在展开时并不分配内存单元,不进行值的传递处理,也没有“返回值”的概念。
(3) 对函数中的实参和形参类型要求一致。而宏名无类型,它的参数也无类型,宏定义时,字符串可以是任何类型的数据。
(5) 使用宏次数多时,宏展开后源程序变长,而函数调用不会使源程序变长。
(6) 宏替换不占运行时间,只占编译时间。而函数调用则占运行时间(分配单元、保留现场、值传递、返回)。