目录
1. 常量、变量、数据类型
- 源程序有一个或者多个函数构成,每个函数完成相对独立的功能。
- 一个C语言程序中有且只有一个main函数,程序执行从main函数开始,从main函数结束。
- 函数体:函数后面用{}括起来的部分。
- 每个执行语句后面加上“;”,预处理、函数头、}后面不加“;”。
- 注释:/*......*/。
- 预处理:以#开头。
- 区分大小写。
- 运行过程
(1)标识符
- 只能有数字、字母、下划线组成,第一个字符必须使字母或下划线,区分大小写。
- 标识符分类:关键字(如for、while等)、预定义标识符、用户标识符。
(2)常量
- 在程序运行中其值不能被改变的量。
- 整型常量、字符型常量、实型常量、字符串常量、符号常量。
- 整型常量
十进制常量(123)、八进制常量(o15)、十六进制常量(ox2A),默认类型为int(有符号基本整型)、无符号整型常量其后加U或u(123u)、长整数其后加L或l。
- 实型常量
十进制小数形式:小数点两边必须都有数字。(13.23)
指数形式e:前必须有数字,后面必须为整数。(1.23e4)
默认类型:double。
后面加上F或f为float类型。
- 字符常量
用单撇号括住:‘a’、‘+’等。转义字符如下:
- 字符串常量
用双撇号括住:“123456”等。字符串常量占用内存字节数等于字符串中的字节数加1,最后一个字节存放‘\0’
- 符号常量
由预定义命令定义的常量。如:#define R 3
(3)变量
- 值可以改变的量,在使用前必须先定义。
- 如:int i,j;
- 整型变量
- 实型变量
- 字符变量
用来存放字符常量。
用关键字char定义。
定义形式:char cr;
赋值:cr=‘m’;
(4)类型的自动转换与强制转换
- 当表达式中类型不一致时,编译器会进行类型转换。
- 优先级:char<int<float<double
- 赋值运算时右别向左别进行转化。
- 强制类型转换:(类型)(表达式)
2. 运算符与表达式
(1)运算符
所有单目运算符、条件运算符、赋值运算符、拓展运算符都是从右向左结合,其余为从左向右结合。+(加)、-(减)、*(乘)、/(除)、%(余),其中%两端必须为整数。双目运算符两侧数值类型一致才能进行运算。如果不一致则系统会进行转换。
- 自增运算符++
++i、--i:在使用i之前,先进行加1或减一。
i++、i--:在使用i之后,使i的值加1或减1。
自左向右结合
- 位运算
3. 基本语句
(1)printf函数
提供的标准输出函数,形式printf(格式控制,输出列表)
printf("%d\n",sum);
(2)scanf函数
形式:scanf(格式控制,地址表列)
#include<stdio.h>
main()
{
int sum;
scanf("%d",&sum);
printf("%d\n",sum);
}
(3)字符输出函数和字符输入函数
- 字符输出函数:putchar()向终端输出一个字符
- 字符输入函数:getchar()向终端输入一个字符
4. 选择结构
- if语句
#include<stdio.h>
main()
{
int i=1,j=2;
if(i>=j)
printf("%d\n",i);
else
printf("%d\n",j);
}
- 条件表达式
表达式1?表达式2:表达式3;
#include<stdio.h>
main()
{
int sum;
sum=2>3?2:4;
printf("%d\n",sum);
}
- switch语句
switch(表达式){
case 常量表达式:语句1
case 常量表达式:语句2
case 常量表达式:语句n
default:语句n+1
}
5. 循环结构
- while循环语句
while(表达式)
循环体
先对表达式进行判断,后执行语句,知道表达式为0时,退出循环体。
- do...while循环
do{
循环体
}
while(表达式);
先执行循环体一次,然后判断循环条件是否成立。当表达式为假时,退出循环。
- for(语句1;语句2;语句3)
语句1:赋值;语句2:判断;语句3:运算
- break和continue语句
break:用于从循环体跳出,该语句只能出现在循环体内及switch语句内,不能用于其它语句。
continue:结束本次循环。
6. 数组
(1)一维数组
一维数组是指数组中的每个元素只带有一个下标的数组。
定义方式:类型说明符 数组名[常量表达式]
必须先定义后使用,数组名定名规则与变量名相同,常量表达式为数组长度。
- 一维数组的引用
例如:int tab[3]={0,1,2};
tab[0]=0
tab[1]=1
tab[2]=2
- 一维数组初始化
使数组中的元素都为0:
例如:int tab [3]={0,0,0};或int tab[3]={0};
对数组赋值:
例如:int tab[3]={1,2,3};也可以写成:int tab[]={1,2,3};
(2)二维数组
在C语言中,二维数组元素的排列顺序为按行排放。
一般形式:数据类型 数组名[常量表达式][常量表达式]
如:int a[3][3]
- 二维数组初始化
例如:int a[3][3]={{0,1,2,3},{2,3,4,5},{4,5,6,7}};
int a[2][3]={1,2,3,4,5,6};
(3)字符数组
初始化:
数组的输入输出:
%c:将字符逐个输入或输出
%s:将整个字符串输入或输出
(4)字符串处理函数
- puts():将一个字符串输出到终端(以‘\0’结束)
- gets(字符数组):从终端输入一个字符串到字符数组,并且得到一个函数值。
- strcpy函数
strcpy(字符数组1,字符串2):将字符串2复制到字符数组1中。
- strcat函数
strcat(字符数组1,字符数组2)
- strlen函数
strlen(字符数组):计算字符数组的长度。
- strcmp函数
strcmp(字符数组1,字符数组2)
7. 函数
(1)函数概述
一个C程序主要有一个主函数和其它若干函数组成的,并且只有一个主函数。
用户角度函数分为:标准函数、自定义函数。
函数形式看:无参函数、有参函数。
(2)函数定义形式
如:求出给定任意两个正整数的和。
#include<stdio.h>
int add(int m,int n);
main()
{
int sum,m,n;
printf("请输入两个整数为:");
scanf("%d%d",&m,&n);
sum=add(m,n);
printf("求和结果为:%d\n",sum);
}
int add(int m,int n){
int sum;
sum=m+n;
return sum;
}
请输入两个整数为:75 25
求和结果为:100
--------------------------------
Process exited after 4.032 seconds with return value 16
请按任意键继续. . .
(3)函数参数与返回值
- 形式参数与实际参数
在定义函数时,函数后面的括号中的变量称为形式参数。(形参)
在主调函数中,函数后面的括号中的变量称为实际参数。(实参)
形式参数与实际参数数目应该保持一致。
- 函数返回值
函数返回值是通过return语句获得的。
函数返回值应当属于确定的某一个值,在定义函数时指定返回类型。
对于不带回值的函数应当用void定义函数为无类型,此时函数体中不得出现return函数。
- 函数调用:函数语句、函数表达式、函数参数
(4)函数递归调用
#include<stdio.h>
int age (int n);
main(){
printf("最终年龄为:%d\n",age(5));
}
int age (int n){
int m;
if(n==1)
m=10;
else
m=age(n-1)+2;
return m;
}
最终年龄为:18
--------------------------------
Process exited after 0.08125 seconds with return value 15
请按任意键继续. . .
(4)数组作为函数参数
- 数组元素作为函数实参
- 数组名可以作为函数参数
(5)全局变量与局部变量
- 全局变量:在函数之外定义的变量,作用范围从定义变量开始到本文件结束。
- 局部变量:在函数内部定义的变量,只能在本函数内部使用。
(6)变量的存储类别
- auto变量
系统默认类型。
- register变量
寄存器变量也是自动变量,可以提高机器的运行效率。它是将变量编译保存到CPU内存中去。
- 静态存储的局部变量
用static进行声明。在整个运行过程中不释放存储单元。初值为0或空字符。在其它函数中不能调用。
- 外部变量extern
在一个文件中引用后面定义的外部变量则用extern进行声明。
- 用static声明外部变量
如果希望全局变量只能被本文件引用,则引用static来进行说明全局变量。
8. 指针
(1)地址与指针
- 在C语言中将地址可以称为指针,一个变量的地址称为变量的指针。一个专门存放另一个变量地址的指针称为指针变量。
- 取地址运算符&,返回操作数的地址。
- 数组的地址可以用数组名来表示。
- 函数名可以表示函数的地址。
- 指针变量
一般形式:类型说明符 *指针变量名
例如:int *p,m;
char *k;
double *t;
p=&m;表示用赋值语句使一个指针变量指向整型变量。
- 指针变量的引用
指针运算符 * :返回该地址中的变量值。
&和*互为逆运算。
- 指针变量作为函数参数
指针变量既可以作为形参,也可以作为实参。
指针变量作为实参时,也是值传递。
#include<stdio.h>
void sw1(int *p1,int *p2);
main(){
int a=5,b=10;
printf("输出:a=%d,b=%d\n",a,b);
sw1(&a,&b);
printf("输出:a=%d,b=%d\n",a,b);
}
void sw1(int *p1,int *p2){
int temp;
temp=*p1;
*p1=*p2;
*p2=temp;
}
输出:a=5,b=10
输出:a=10,b=5
--------------------------------
Process exited after 0.08376 seconds with return value 15
请按任意键继续. . .
(2)数组与指针
- 指向数组元素指针
C语言中数组名为数组的首地址,也就是数组中第0号元素的值,p=&a[0]等价于p=a
- 通过指针引用数组元素
如果有 int a[10],*p=a;
p+i和a+i都是数组元素a[i]的地址。
*(p+i)和*(a+i)都是数组元素a[i]的值。
p[i]=*(p+i)
例如:一个整型数组,输出其全部值?
#include<stdio.h>
main(){
int tab[5]={1,2,3,4,5},*p=tab,i;
printf("用数组输出值:");
for(i=0;i<5;i++){
printf("%d",tab[i]);
}
printf("\n用指针输出值:");
for(i=0;i<5;i++){
printf("%d",p[i]);
}
}
用数组输出值:12345
用指针输出值:12345
--------------------------------
Process exited after 0.1296 seconds with return value 1
请按任意键继续. . .
- 用数组名作为函数参数
- 形参与实参都用数组名。
- 实参用数组名,形参用指针变量。
- 实参与形参都用指针。
- 实参为指针,形参为数组名。
(3)字符串与指针
- 表示形式
例如:char str[]="hello";
用字符指针指向一个字符串:char *p="hello";
等价于:char *p;
p="hello";
- 字符指针变量和字符数组的区别
赋值方式不同:
- 字符数组可以在其定义时候进行整体赋值,但在赋值语句中不能完成整体赋值。
- 字符指针变量可以在定义的时候赋值,也可以在赋值语句中完成。
编译时不同:
- 在程序中指针变量的值可以改变,而数组名不可以改变。
(4)返回指针函数
返回指针函数定义的格式为:函数类型 *函数名([形参表])
例如:int *b(int m,int n)
- 指针数组
在一个数组中,其元素均为指针数组类型,这样的数组称为指针数组。
一维指针数组定义的形式:类型名 *数组名[数组长度]
例如:int *a[4]
表示数组共有四个元素,每个元素都指向整型数组。
9. 编译预处理和动态存储分配
(1)宏定义
- 不带参数的宏定义
定义形式:#define 宏名 替换文本
例如:#define PI 3.14
可以用#undef命令终止宏定义的作用域。
同一个宏名不能重复定义。
在进行宏定义时,可以引用已经定义好的宏。
- 带参数的宏定义
定义形式:#define 宏名(参数表)字符串
例如:#define m(y) y*y
(2)文件包含#include
文件包含命令行的一般形式为:#include“文件名”或#include<文件名>
(3)动态存储函数
函数原型:void *malloc(unsigned int size)
系统自动在内存动态存储区中,分配长度为size的一段连续空间。
若执行成功:函数返回值指向被分配域的起始地址指针。
若执行失败:函数返回值为空指针。
10. 结构体与共用体
(1)typedef
一般形式:typedef 类型名 标识符
类型名:已有定义的类型标识符。标识符:用户自己定义标识符。
例如:typedef int A
int a;等价于A a;
(2)结构体数据类型
一般形式:struct 结构体名{
成员列表
};
- 先声明结构体类型再定义变量名
如已经定义了结构体struct student,可以定义:
struct student student1,student2;
- 在声明类型的同时定义变量
struct student{
char name[20];
int age;
char sex;
}student1,student2;
- 直接定义结构体类型变量
struct{
成员列表
}变量名列表;
(3)结构体变量的引用
结构体变量不能作为一个整体而对其进行操作,只能对其中结构体变量中的各个成员分别进行输入与输出。
结构体变量名.成员名
如果结构体某个成员又是一个结构体类型,则可以使用若干个成员运算符,一级一级的找到最低的一级成员。
结构体变量成员可以和普通变量一样进行各种运算。
(4)结构体数组
struct student{
char name[20];
int num;
}stu[2]={{"song hong",123},{"li hang",124}};
(5)指向结构体类型数据的指针
结构体变量名.成员名==*(结构体指针变量名).成员名==结构体指针变量->成员名
在使用指针变量指向结构体数组时,只要把结构体数组中的每个元素当做普通变量即可。
(6)链表
- 链表是一种常见的数据结构,它可以动态的存储单元分配的一种结构。
- 链表最后一个结点的指针域置成'\0'值,标志着链表结束。
- 每个链表都用一个头指针变量来指向链表的开始,称为head指针。存放链表第一个结点的地址。
- 每个结点由两个域组成:数据域和指针域。
- 链表基本操作:创建、检索、插入、删除、修改。
- 顺序访问链表中各节点的数据域。
- 还有删除节点和插入节点。
(7)共用体
几个不同的变量共占同一段内存的结构。
定义形式:
union 共用体名{
成员变量
}变量列表;
11. 文件
C语言把文件分为:文件(文本文件)和二进制文件,文件是一个字节流或者二进制流。文件存取方式:顺序存取、直接存取。
FILE *fp
fp是指向FILE结构体类型的指针变量。
(1)fopen函数
格式:fopen(文件名,文件使用方式)
当出现错误时候,函数返回值为NULL。
(2)fclose函数
格式:fclose(文件指针)
当执行关闭操作时候,成功返回为0,失败为非0。
(3)fread和fwrite函数
格式:
fread(buffer,size,count,fp);
fwrite(buffer,size,count,fp);
- buttfer:指针变量。
- size:读写的字节数。
- count:用来指定每读写一次,输入或者输出数据块数。
- fp:文件数据类型指针。
(4)格式化读写函数
格式:
fscanf(文件指针,格式字符串,输入列表);
fprintf(文件指针,格式字符串,输出列表);
作用在磁盘文件上的数据。
(5)fputs函数
把字符串输入到文件中去。
fputs(str,fp);
- str:输出字符。
- fp:文件指针。
(6)rewind函数
rewind(fp);
使文件的位置指针重新返回到文件的开头。
(7)fseek函数
fseek(文件指针类型,位移量,起始点);
起始点:
文件开头:0
文件当前位置:1
文件结尾:2
12. 综合运用 — 学生成绩管理系统设计
实现过程:https://blog.csdn.net/fanjufei123456/article/details/104003332
要求:
1、成绩录入:输入学生的学号、姓名及三门课的成绩;
2、成绩查询:(至少一种查询方式)。按学号查询学生记录,或查询不及格学生的记录;
3、成绩统计:计算学生的平均分;根据学生的平均分高低,对学生的数据进行排序后输出;对学生单科成绩排序,输出学生姓名与该科成绩;
4、退出系统:退出整个系统(即主菜单);
#include <stdio.h>
#include<stdlib.h>
typedef struct student
{
int num;
char name[13];
int score[3];
double aver;
}STU;
void ave(STU s[],int n)
{ double a[1000];
int i;
for(i=0;i<n;i++)
a[i]=(s[i].score[0]+s[i].score[1]+s[i].score[2])/3.0;
printf("学号\t姓名\t\t分数1\t分数2\t分数3\t平均分\n");
for(i=0;i<n;i++)
printf("%d\t%s\t\t%d\t%d\t%d\t%.1f\n",s[i].num,s[i].name,s[i].score[0],s[i].score[1],s[i].score[2],a[i]);
}
void search(STU s[],int n, int a)
{
int i,k=0;
for(i=0;i<n;i++)
{
if(s[i].num==a)
{ printf("学号\t姓名\t分数1\t分数2\t分数3\t\n");
printf("%d\t%s\t%d\t%d\t%d\n",s[i].num,s[i].name,s[i].score[0],s[i].score[1],s[i].score[2]);
k=k+1;
break;
}
}
if(k==0)
printf("\t没有查询到相关信息");
}
void average(STU s[],int n)
{ int i,j;
STU ss[10000];
STU *p=ss;
for(i=0;i<n;i++)
s[i].aver=(s[i].score[0]+s[i].score[1]+s[i].score[2])/3.0;
for(i=0;i<n;i++)
ss[i]=s[i];
for(i=0;i<n-1;i++)
{
for(j=i+1;j<n;j++)
{
if(ss[i].aver<ss[j].aver)
{
STU temp=*(p+i);
*(p+i)=*(p+j);
*(p+j)=temp;
}
}
}
printf("学号\t姓名\t平均分\n");
for(i=0;i<n;i++)
printf("%d\t%s\t%.1f\n",(p+i)->num,(p+i)->name,(p+i)->aver);
}
void grade(STU s[],int n)
{int i,j,k;
STU ss[10000];
STU *p=ss;
for(i=0;i<n;i++)
ss[i]=s[i];
printf("请输入k的值查询,k=0时按分数1,k=1时按分数2,k=2时按分数3:");
scanf("%d",&k);
for(i=0;i<n-1;i++)
{
for(j=i+1;j<n;j++)
{
if(ss[i].score[k]<ss[j].score[k])
{
STU temp=*(p+i);
*(p+i)=*(p+j);
*(p+j)=temp;
}
}
}
printf("姓名\t分数\n");
for(i=0;i<n;i++)
printf("%s\t%d\n",(p+i)->name,(p+i)->score[k]);
}
main()
{ int N,i;
STU s[10000];
int num1;
int menu;
printf("请输入学生个数:");
scanf("%d",&N);
for(i=0;i<N;i++)
{
printf("请输入学号 姓名 分数1 分数2 分数3\n");
scanf("%d%s%d%d%d",&s[i].num,s[i].name,&s[i].score[0],&s[i].score[1],&s[i].score[2]);
}
printf("\n\n");
printf("*************学生成绩管理系统*************\n\n");
printf("1--------输出平均分\n");
printf("2--------按学号查询成绩\n");
printf("3--------按平均分排序后输出\n");
printf("4--------对学生单科成绩排序后输出\n");
printf("5--------退出程序\n");
printf("\n\n");
while(1)
{
printf("\n请输入菜单号:");
scanf("%d",&menu);
switch(menu)
{
case 1: ave(s,N);break;
case 2: printf("请输入要查询的学号:");
scanf("%d",&num1);
search(s,N,num1);
break;
case 3: average(s,N);break;
case 4: grade(s,N);break;
case 5: exit(0);
default:
printf("菜单号输入错误\n");
break;
}
}
}