概述
C语言基础
一、简介
C 语言是一种通用的、面向过程的计算机程序设计的高级语言。
特点:结构化语言,高效率,可处理底层活动,可移植性,表达方式灵活能力强,语言简洁
二、变量与常量
(一)变量
-
变量定义
<类型名称><变量名称>
-
变量命名(标识符):
(1) 标识符有它自己的构造规则,只能由字母、数字和下划线"_"组成
(2) 数字不能出现在第一个位置
(3) 关键字(保留字)不能作为标识符
关键字(保留字):auto,break,case,char,const,continue,default,do,double,else,enum,extern,float,for,goto,if,int,long,register,return,short,signed,
sizeof,static,struct,switch,typedef,union,unsigned,void,volatile,while,inline,restrict
-
变量类型
基本类型:int , char , float , double , void
-
赋值与初始化
例:price=0;将0值赋给变量price,对于变量一定要初始化
(二)常量
-
整数常量
85 – 十进制,025 – 八进制,0x4a – 十六进制
10l – 长整数,30u – 无符号整数
-
浮点常量
3.14f – float型,2.5 – double型,1.23L – long double型
-
字符常量
常用 :f – 换页符,n – 换行符, r – 回车 ,b – 退格
-
定义
const修饰符 : const int a = 10;
#define预处理器 :#define WIDTH 3
三、运算符和表达式
(一)运算符
-
算术运算符
运算符 描述 举例 + 两个操作数相加 1 + 1 =2 - 两个操作数相减 1 - 1 = 0 * 两个操作数相乘 1 * 1= 1 / 两个操作数相除 5 / 2 = 2 % 两个操作数相除取余数 5 % 2 = 1 ++ 自增,一个操作数 1++ 得到2 – 自减,一个操作数 1-- 得到0 -
关系运算符
运算符 描述 举例 != 判断两个操作数是否相等,不相等为真 (1!=2)为真 == 判断两个操作数是否相等,相等为真 (1==1)为真 > 判断左操作数是否大于右操作数,是为真 (1>2)为假 < 判断左操作数是否小于右操作数,是为真 (1<2)为真 >= 判断左操作数是否大于等于右操作数,是为真 (2>=1)为真 <= 判断左操作数是否小于等于右操作数,是为真 (1<=2)为真 -
逻辑运算符
运算符 描述 举例 && 逻辑与,两个操作数为真,返回真 true && false为假 || 逻辑或,两个操作数至少一个为真,返回真 true || false为真 ! 逻辑非,如果条件为真则返回假 !true为假 -
位运算符
运算符 描述 举例 & 按位与,按二进制位进行“与”运算 0 & 1 = 0 | 按位或,按二进制位进行“或”运算 0 | 1 = 1 ^ 异或,按二进制位进行“异或”运算 0 ^ 1 = 1,0 ^ 0 = 0 ~ 取反,按二进制位进行“取反”运算,二进制0变1,1变0 ~ 1 = -2 << 二进制左移运算符,左移若干位,右边补0 7 << 2 为28 >> 二进制右移运算符,正数左补0,负数左补1 7 >> 2 为1 一般情况下,左移n位就是原数乘以2的n次方,右移n位就是原数除以2的n次方
-
赋值运算符
运算符 描述 举例 = 右操作数赋值给左操作数 A = B += 右操作数加上左操作数结果赋值给左操作数 A +=B <=> A = A + B -= 右操作数减去左操作数结果赋值给左操作数 A -=B <=> A = A - B *= 右操作数加乘以操作数结果赋值给左操作数 A *=B <=> A = A * B /= 右操作数除以左操作数结果赋值给左操作数 A /=B <=> A = A / B %= 右操作数除以左操作数取余结果赋值给左操作数 A %=B <=> A = A % B <<= 左移且赋值 A <<=1 <=> A = A << 1 >>= 右移且赋值 A >>=1 <=> A = A >> 1 &= 按位与且赋值 A &=1 <=> A = A & 1 |= 按位或且赋值 A |=1 <=> A = A | 1 ^= 按位异或且赋值 A ^=1 <=> A = A ^ 1 -
其他运算符
运算符 | 描述 | 举例 |
---|---|---|
& | 返回变量地址 | &a,返回a的地址 |
?: | x>y? y : x,判断条件x>y,为真值为y,否则值为x | 1>2 ? true : false 值为false |
* | 指向一个变量 | *p,p指针 |
[] | 下标运算符 | a[1] ,数组a中下标为1的数 |
sizeof | 返回变量字节大小 | int a; sizeof(a) ,a=4 |
(类型) | 强制转换类型 | a为字符串,(int) a,a强制转换为整型 |
-
运算符的优先级
(1) 单目运算符 > 双目运算符 > 三目运算符
(2) {[],(),.,->} > {-,(类型),++,–,*(指针),!,&(地址),~,sizeof} > 算术运算符 > {<< , >>} > 关系运算符 > {&,|,^} > { &&,||} > ? > 赋值运算符 > ,
(二)表达式
表达式包含运算符和操作数
.
例如:a + b, 5-- ,"Hello World"等等
四、数据类型
(一)基本类型
1. 整型类型
int - 整型 , short int - 短整型 ,long int -长整型,
char - 字符型,bool - 布尔型(C99标准后新增)
2. 浮点类型
double - 双精度浮点类型 ,float - 单精度浮点类型
(二)派生类型
* -- 指针类型 , [] -- 数组类型 ,
struct - 结构体类型 , union - 共用体类型,
函数类型
(三)其他
enum - 枚举类型 , void - 空类型
五、数据的输入与输出
(一) 输入输出概念
1.所谓的输入输出是以计算机主机为主体而言的,从输入设备(如键盘、光盘等)向计算机输入数据称为输入,从计算机向输出设备(如显示屏、打印机等)输出数据称为输出。
2.对于C语言而言,它本身并不提供输入与输出语句,均是由C标准函数库中的函数来实现的,例如printf函数和scanf函数。printf和scanf并不是语言的关键字,而只是库函数的名字。
3.C程序中需在程序文件开头用预处理命令#include <stdio.h> (#include “stdio.h”),目的是把相关头文件放在C程序中。如果C程序需要调用标准输入输出函数,就需要在程序的开头就需要使用该预处理命令。
(二) 用printf函数输出数据
1.一般格式
printf(格式控制,输出表列),例如:printf("%dn",a);
(1) 格式控制即格式字符串,由格式声明和普通字符组成。
格式声明由"%“和格式字符组成,例如”%d","%f"等,作用是将输出数据转换为指定的格式后输出。
普通字符即在输出时原样输出的字符,例如printf函数中" "中的空格,逗号等。
(2) 输出表列是程序需要输出的数据,可以是变量,表达式或者常量。
2.格式字符
在输出时,不同类型的数据需要指定不同的输出格式声明,格式声明中最重要的就是格式字符。
(1) d格式字符
指定输出数据所占的列数(域宽),如"%3d",指定输出数据占3列。
若输出long类型,则在格式字符"d"前加字母"l",即"%ld"。
int a = 5;
printf("%3d",a);
(2) c格式字符
用于输出字符和域宽,若整数在0~127范围中,也可以用该格式按字符形式输出,系统会将该整数作为ASCII码转换成相应的字符。
int a = 100;
printf("%c",a);
(3) s格式字符
用于输出一个字符串。
printf("%s","Hello C");
(4) f格式字符
用来输出实数,以小数形式输出。
-
%f,不指定输出数据长度,系统根据数据大小决定列数,整数部分全部输出,小数点后6位
-
%m.nf,指定输出数据列数和小数位数,其中m表示输出数组所占列数m列,小数占n位
double a = 5;
printf("%8.7f",a/3);
(5) e格式字符
指定以指数形式输出实数,同f格式字符一样,也可指定数据列数和小数位数。
printf("%8.7e",123.456);
(6) 其他格式字符
“%i”:以十进制形式输出
“%o”:以八进制形式输出
“%x”:以十六进制输出
(三) 用scanf函数输入数据
1.一般形式
scanf(格式控制,地址表列),例如:scanf("%d",&a);
(1) 格式控制含义同上printf函数。
(2) 地址表列是由若干个地址组成的表列,可以是变量的地址、字符串的首地址。
2.格式声明
scanf中的格式声明与printf函数中的格式声明相似,以%开始,一个格式字符结束,中间可插入附件的字符。
格式字符的用法也和printf函数中的差不多,可以直接参考printf函数的格式字符用法。
注意:在输入数据时,需输入与格式控制中相应的字符,即在对应的位置输入同样的字符,否则会报错
int a,b;
scanf("a=%d,b=%d",&a,&b);
(四) 字符输入输出函数
1.putchar函数输入字符
putchar函数的一般形式putchar(c),例如:putchar(a);
2.getchar函数输入字符
getchar函数的一般形式getchar(),getchar函数没有参数,例如:a=getchar();
六、判断结构
判断结构的一般形式:
(一) if语句
1.一般形式
(1) if (表达式) 语句 1;(无else语句)
(2) if (表达式) 语句 1 ;else 语句 2;
(3) if (表达式) 语句 1;else if 语句 2;… … … ;else if 语句 n; else 语句 n+1;
以(3)为例,代码如下,
int a;
int number = 0;
scanf("%dn",&a);
if(a>1000){
number = 1;
}
else if(a>500){
number = 2;
}
else if(a>250){
number = 4;
}
else{
number = 8;
}
printf("%dn",number);
2. 内嵌if
一般形式,"{}"限定了内嵌语句的范围
if (表达式)
{
if( ) 语句 1 ;
else 语句 2;
}
else
{
if( ) 语句 1 ;
else 语句 2;
}
int a ;
scanf("%d",&a);
int number = 0;
if(a>=0){
if(a == 0){
number = 1;
}
else{
number = 2;
}
}
else{
number = 4;
}
printf("%dn",number);
(二) switch语句
1.一般形式
switch语句是多分支判断语句,当一个问题分支比较多时,可使用该语句,避免if语句的多层嵌套,提高程序的可读性。
switch(表达式)
{
case 常量1 :语句1;
case 常量2 :语句2;
case 常量3 :语句3;
… …
case 常量n :语句n;
default : 语句 n+1
}
char grade;
scanf("%c",&grade);
switch(grade)
{
case 'A':printf("90~100");break;
case 'B':printf("80~89");break;
case 'C':printf("70~79");break;
case 'D':printf("60~69");break;
default :printf("error");
}
七、循环结构
循环结构的一般形式
(一) while语句实现循环
一般形式:while(表达式) 语句
当循环条件为真时,就执行循环体语句,直至为假
int i = 1,sum = 0;
while(i < 10)
{
sum = sum + i;
i++;
}
printf("%d",sum);
(二)do…while实现循环
一般形式:do 语句 while(表达式);
先执行一次指定的循环体语句,然后判别表达式,当表达式为真时,返回循环体重新执行语句,直至为假
int i = 1,sum = 0;
do
{
sum = sum + i;
i++;
} while(i < 10);
printf("%d",sum);
(三) for语句实现循环
一般形式:for(表达式1;表达式2;表达式3) 语句
表达式1:设置初始条件,只执行一次,可为零至多个变量设置初值
表达式2:循环条件表达式
表达式3:循环的调整,循环体语句每次执行后再进行
int sum = 0;
for(int i = 1;i < 10;i++)
{
sum += i;
}
printf("%d",sum);
return 0;
若for语句中三个表达式留空,将会无限循环。
(四) 循环执行状态的改变
1.break语句
break语句可以使流程从循环体内跳出循环体,提前结束循环
while(a >= 0)
{
if(a == 15)
{
break;
}
printf("%d",a)
}
2.continue语句
continue语句可提前结束本次循环,而接着执行下次循环
int n;
for(n = 1;n <= 100;n++)
{
if(n%3 == 0)
{
continue;
}
printf("%d",n)
}
3.区别
break语句直接结束整个循环过程,不再去判断执行前循环条件是否成立;而continue语句只结束本次循环,而不是终止整个循环的执行。
如果是双重循环,在内循环体内有个break语句,则将提前终止内循环。
八、函数
(一) 函数的定义
1.无参函数
类型名 函数名( ) /函数名( void )
{
函数体
}
void message()
{
printd("Hello Cn");
}
2.有参函数
类型名 函数名( 形式参数表列)
{
函数体
}
int max(int x,int y)
{
int z;
z = x > y ? x > y;
return z;
}
3.空函数
类型名 函数名()
{
}
void x()
{
}
(二) 函数的声明与调用
1.函数声明
函数声明会告诉编译器函数名称以及如何调用函数
用户在一个函数中调用另一个自己定义的函数时需要在该主函数中对被调用的函数作声明
用自己定义的函数首部‘(函数原型)来作为函数声明即可
int main()
{
int add(int x,int y);
... ...
return 0;
}
2.函数调用
(1) 形参与实参
实际参数(实参):在一个函数中调用一个函数时函数名后括号内的参数
形式参数(形参):定义函数时函数名后括号内的参数
在调用函数的过程中,系统会把实参的值传递给被调用函数的形参。
(2) 调用过程
在定义函数时指定形参,在未出现函数调用的情况下,形参不占用内存;
发送函数调用时,系统临时为被调用函数分配内存;
将实参的值传给形参后,函数开始执行,由于形参已有值,则利用形参进行有关运算;
然后通过return语句将函数值带回主函数;
调用结束以后,形参分配的内存被释放。
(3) 函数的返回值
函数的返回值通过return语句带回主函数,如果不需要从被调函数带回函数值则可不要return;
在定义函数时需要指定函数值的类型,并且指定类型应当与return语句中的表达式类型一致,即函数类型决定返回值得类型;
对于不带回值的函数应当定义为void类型
(4)调用类型
- 传值调用
把参数实际值传递给形参
- 引用调用
通过指针传递方式,形参是指向实参地址的指针,
(三) 函数的递归调用
在调用一个函数的过程又出现直接或间接调用函数本身,则称之为函数的递归调用
int f(int x)
{
int y,z;
z = f(y);
return (2*z);
}
(四) 局部变量与全局变量
从变量的作用域可分为局部变量和全局变量
1.局部变量
在函数内部或块内部定义的变量为局部变量,函数的形式参数也被作为是函数内的局部变量。
2.全局变量
在所有函数外定义的变量为全局变量,它的有效范围是从定义到源文件结束。
3.在内存中的区别
- 全局变量保存在内存的全局存储区中,占用静态的存储单元;
- 局部变量保存在栈中,只有在所在函数被调用时才动态地为变量分配存储单元。
(五) 变量的存储方式
从变量的生存期可分为静态存储方式和动态存储方式
用户区(内存中供用户使用的存储情况) |
---|
程序区 |
静态存储区 |
动态存储区 |
1.动态存储方式
动态存储方式指在程序运行期间根据需求进行动态的分配存储空间的方式
2.静态存储方式
静态存储方式指在程序运行期间由系统分配固定的存储空间的方式
3.数据存放
全局变量全部存储在静态存储区中,程序执行完就释放
动态存储区:
- 形参
- 函数中定义的无关键字static声明的变量(自动变量)
- 函数调用时的现场保护和返回地址等
以上在调用函数时分配存储空间,函数结束时释放
4.局部变量的存储类别
C语言中每个变量和函数都有两个属性:数据类型和数据的存储类别
(1) 自动变量(auto)
函数的局部变量若无static存储类别声明,都是动态的分配在存储空间的,这类就为自动变量
自动变量关键字auto可以省略,在函数定义中没有声明的默认为auto
(1) 静态局部变量(static)
函数中的局部变量的值在调用后继续保留原值,函数调用结束后不释放所分配的存储空间,下次调用时,该变量的值为上次函数调用结束时的值。
属于静态存储类别,在静态存储区分配单元
int main()
{
int f(int a);
int a = 1;
for(int i = 0;i < 3;i++)
{
printf("%dn",f(a));
}
return 0;
}
int f(int a)
{
int b = 0; //自动变量
static c = 2; //静态局部变量
b++;
c++;
return (a+b+c);
}
调用次数 | 调用时初值b | 调用时初值c | 调用结束时b | 调用结束时c | 调用结束时a+b+c |
---|---|---|---|---|---|
1 | 0 | 2 | 1 | 3 | 5 |
2 | 0 | 3 | 1 | 4 | 6 |
3 | 0 | 4 | 1 | 5 | 7 |
(3) 寄存器变量(register)
当程序中用到变量的值时,由控制器发出指令将内存中该变量的值送到运算器中
寄存器只用于需要快速访问的变量,寄存器的存储速度远高于对内存的存储速度,可以提高执行效率
5.全局变量的存储类别
用extern声明外部变量
- 可扩展外部变量在程序文件中的作用域
- 将外部变量的作用域扩展到其他文件
- 将外部变量的作用域限制在本文件中(需在文件中对全局变量声明static,另一文件声明extern)(静态外部变量)
(六) 内部函数和外部函数
1.内部函数(静态函数)
若一个函数只能被本文件中的其他函数调用则为内部函数,定义函数时前面加上static
static 类型名 函数名(形参表列)
2.外部函数
在定义函数时,在函数首部的最左边加上关键字extern则为外部函数,可以被其他文件调用
extern 类型名 函数名(形参表列)
extern int hello(int x, int y)
此时hello函数可为其他文件调用,若定义是省略extern ,则默认为外部函数
九、数组
(一) 一维数组
1.定义
类型符 数组名[ 常量表达式]
C语言中不允许对数组大小作动态定义
2.引用
数组名 [下标],下标从0开始
3.初始化
-
在定义数组时对全部数组元素赋予初值
int a[10] = {0,1,2,3,4,5,6,7,8,9};
-
可只给部分数组元素赋值,剩余自动赋值为0
int a[10] = {0,1,2,3,4};
-
可使一个数组中元素全为0
int a[10] = {0,0,0,0,0,0,0,0,0,0};
-
若数组个数确定,可不指定数组长度,系统会根据括号内数据个数确定长度
int a[] = {1,2,3,4,5}
4.冒泡法
每次比较相邻的两个数,将小的排在前面
int a[10] = {2,3,25,14,78,54,34,42,16,30};
int i,j,t;
for(j = 0;j < 9;j++)
{
for(i = 0;i < 9 - j;i++)
{
if(a[i] > a[i+1])
{
t = a[i];
a[i] = a[i+1];
a[i+1] = t;
}
}
}
printf("结果为:n");
for(i = 0;i < 10;i++)
{
printf("%d ",a[i]);
}
(二) 二维数组
1.定义
可把二维数组写成行和列的排列方式,按行存放
类型符 数组名[常量表达式] [常量表达式];
逻辑上可用矩阵形式表示二维数组;在内存中,各元素是连续存放的,不是二维的,是线性的
2.引用
数组名[下标] [下标]
3.初始化
- 分行给二维数组赋值
int a[2][3] = {{1,2,3},{4,5,6}};
- 所有元素写在一块,按数组元素在内存中的排列顺序对各元素赋值
int a[2][3] = {1,2,3,4,5,6};
- 可对部分元素赋值
int a[2][3] = {{1},{2,3}};
(三) 字符数组
1.定义和初始化
与数值型数组类似
//举例
char c[9];
char c[9] ={'I','','L','o','v','e','','C','