从解析一个C语言源文件开始
#include ;
int main(){
int max(int x,int y);
int a,b,c;
scanf("%d,%d",&a,&b);
c=max(a,b);
printf("max=%d\n",c);
return 0;
}
int max(int x,int y){
int z;
if(x>y) z=x;
else z=y;
return (z);
}
① 预处理命令:#include
② 函数定义:
编辑源程序:敲代码
使用预处理器对源程序进行编译:将头文件中的内容读入该源程序,检查有无语法错误,无语法错误则转换为二进制目标文件
进行连接处理:二进制目标文件不能供计算机执行,需要将编译得到的所有目标文件连接起来,生成一个可执行程序exe
运行可执行程序
对数据操作的步骤便是算法
程序 = 算法 + 数据结构
可分为两类:数值运算算法和非数值运算算法
设计结构化程序:自顶向下,逐步细化:即先搭建框架,再填充框架内容
① 常量:
整型常量:整数
实型常量:小数
字符常量:普通字符,如’A’;转义字符,如’\t’,’\n’,’\a’,’\b’,’\r’,’\o’,’\v’,’\f’,’"’
//转义字符,如
'\t':水平制表符,'\n':换行符,'\a':警告,'\b':退格,'\r':回车-光标移到本行开头,'\v':垂直制表符,'\f':换页,'\"':双引号,'\?':问号,'\'':单引号,'\xh[h...]':十六进制,'\o':八进制
字符串常量:如"sos"
符号常量:#define指令自己定义的常量
#define PI 3.1415926 //行末无分号
② 常变量:
用const关键字修饰的变量
#define float pi=3.1415926;
//常变量占用存储单位,有变量值。符号常量不分配存储单元
③ 变量:先定义使用
④ 标识符:即名字:由字母、数字、下划线组成,且第一个字符必须为字母或下划线
C语言数据类型的大小会根据操作系统的变化而变化,不必记忆
大小:一般为4个字节
存储方式:用整数的补码式存放,正数的补码是此数的二进制形式,负数的补码是此数绝对值的二进制形式,按位取反再加1。
大小:一般为2个字节
存储方式:同基本整型的存储方式
大小:一般为4个字节
大小:一般为8个字节
该属性只有整型和字符型有,且在java语言中无该表达形式
unsigned可修饰整型变量,表示为无符号,即正整数
整型变量默认被signed修饰,表示有符号
char c = 'x';
//c称为字符变量
//'x':在''中放置一个字符的数据类型称为字符型
所有的ASCII代码最多用7个二进制就可以表示
signed:-128~127
unsigned:0~255
大小:4个字节,得到6位有效数字
C编译系统把浮点型常量都按双精度处理
大小:8个字节,得到15位有效数字
大小:16个字节或者8个字节,15或者19位有效数字
在算术运算中,计算的数据有多个类型时,以精度最高者为准
当字符型与整型进行运算时,字符会自动转换为对应的整型:‘A’:65 ; ‘a’:97
进行强制类型转换时,得到一个所需的中间数据,对原变量无影响
(int)x + y;//该语句是先将x转换为整型再+y
类型一致直接赋值,可在声明变量时赋初值
类型不一致,由系统自动进行(在java语言中,从高精度到低精度需要强制转换,但在c语言中由系统自动完成)
当double型赋值给float型如果超出了其范围,则会报错;
要避免把占字节多的整型数据,向占字节少的整型变量赋值,因为赋值后可能失真,例如
int a = 32767;
short b;
b = a+1;
//理论上b应该为32768,但是输出为-32768
c语言不提供输入输出函数,所以需要#include"stdio.h"
scanf("%x",&a);
//变量a前需要使用地址符&,这样输入的数据会找到该存储单元,赋值给变量a
//输入时,如果有多个变量,在两个数之间用空格隔开,输入后会根据%后面的数据类型输入
输入时:
scanf("a=%f,b=%f,c=%f",&a,&b,&c);//a=1,b=3,c=2:当遇到除了格式声明以外还有其它字符时,则在输入数据时在对应的位置上应输入与这些字符相同的字符,其中的逗号是与前者中的逗号对应
scanf("%c%c%c",&a,&b,&c);//abc,不得有空格因为空格也算一个字符
scanf("%d%c%f",&a,&b,&c);//遇到非法字符结束当前输入
printf("%x",a);
//输出与出入不同,此处只需要传入变量,这样print函数只会输出其值,不会对a进行内容的修改
当输入变量时,必须使用该格式,不能直接输出
%d,i:用来输出有符号的十进制整数(包括char类型)
%u:用来输出无符号的十进制整数(包括char类型)
%o:用来输出无符号的八进制整数
%x,X:用来输出无符号的十六进制整数
%c:用来输出单个字符
%s:用来输出一个字符串
%f:用来输出小数形式的十进制浮点数(输入时小数形式和指数形式都可以识别)
%e,E:用来输出指数形式的十进制浮点数(输入时小数形式和指数形式都可以识别)
%g,G:用来输出指数形式和小数形式两者中较短的十进制浮点数(输入时小数形式和指数形式都可以识别)
① - :有-表示左对齐输出,如省略表示右对齐输出。
② 0 :有0表示指定空位填0,如省略表示指定空位不填。
③ m.n :m指域宽,若数据的位数小于m,则左端补空格,若大于m,则按实际位数输出。
n指精度,用于说明输出的实型数的小数位数。未指定n时,隐含的精度为n=6位。
④ l或h :l对整型指long型,对实型指double型。h用于将整型的格式字符修正为short型。可加在格式符d\o\x\u前
输出:putchar©;
输入:getchar();输入时,按先后顺序输入,再按下enter键,不要输入完一个字符就按下enter键,这样enter键也会作为一个字符进行输入。
//一维数组的定义:类型符 数组名[常量表达式]
int a[10];
//二维数组的定义:类型符 数组名[常量表达式][常量表达式]
int a[10][2];
C语言不允许对数组的大小作动态定义,即数组的大小不依赖程序允许过程中变量的值。即int a[n]不合法。
数组中的下标从0开始。
//一维数组的初始化
//全部赋予初始值
int a[5] = {1,1,1,1,1};
//给一部分赋值
int a[5] = {1,1};//自动给后面三个元素赋初值0
//全部赋初始值时:
int a[] = {1,1,1,1,1};//默认a的大小为5
//二维数组的初始化
//分行给二维数组赋值
int a[3][2] = {{1,2},{3,4},{5,6}}
//不分行给二维数组赋值
int a[3][2] = {1,2,3,4,5,6};//自动按顺序分行,结果同上
//给一部分赋值
int a[3][4] = {{1},{1},{1}}//相当于一维数组中放置一维数组
int a[3][4] = {{1},{},{1}}
//当赋初值时,可以通过给第一层数组赋值而省略其长度,第二维的长度不可省略
int a[][4] = {{1},{},{1}}
如果是字符型数组则初始化的默认初始值为’\0’,如果是指针型则初始化为NULL。
//引用形式 数组名[下标]
t = a[2];
a[2][1] = b[3][1];
数组元素的下标从0开始,定义数组时
定义数组时的 int a[3] [2] 与引用时的a[3] [2]不同,一个定义大小,一个指向具体的内存空间
char a[10];
//合法但浪费空间:因为字符型也是整数形式存放,因此可以用整型数组存放字符数据
int c[10];
c[0] = 'a';
//将字符依次赋值
char a[3] = {'i','l','u'};
//部分赋值
char a[3] = {'i'};//会自动将后面的元素默认为'\0'
//省略定义的大小
char a[] = {'i','l','u'};
//同一般数组,通过下标进行引用
for(i=0;i<3;i++)
printf("%c",a[i]);
在C语言中,将字符串作为字符数组来处理,并不像java中有String类可以定义字符串。
在实际工作中,字符串的有效长度往往与字符数组的有效长度不同,所以C语言规定了一个“字符串结束标志”——’\0’
例如
//1
char c[] = "cnm";
//这里使用字符串作为初始值,此时数组的长度为4而不是3,因为字符串常量的最后由系统默认增加'\0',相当于:
char c[] = {'c','n','m','\0'}
//2
char c[5] = {"cnm"};
//相当于:
char c[] = {'c','n','m','\0','\0'}
//3
char c[3] = {'c','n','m'}
//这样的表示完全合法,是否需要加'\0'根据需求而定
//4
char c[5] = {"cnm"};
c[0] = 'h';
c[1] = '\0';
//在输出字符串时,遇到'\0'就停止输出
//逐个输出
printf(%c,c[0]);
//整个字符串输出
printf("%s",c);
//执行实际:系统按字符数组名c找到该数组第一个元素的地址,然后逐个输出其中的字符,知道遇到'\0'
printf("%o",c);//可输出该数组的起始地址
输出的字符不包括’\0’
用%s输出字符串时,输出项必须是字符串数组名,而不是数组元素名,即c是字符串数组名与c[0]是数组元素名
当数组长度大于字符串实际长度时,遇到’\0’停止输出
如果字符数组包含多个’\0’,遇到第一个便停止输出
char c[6];
scanf("%s",c);
输入项为已定义的字符数组名,输入的字符应短于已定义的字符数组的长度,系统会自动在后面加’\0’,如果依次输入多个字符串时,输入时用空格分隔,数组中未被赋值的元素的值自动为’\0’。
当输入单个字符串时,空格会作为一次输入的结束标志,即针对上述代码,输入:c n m,只会存入c, n m不会存入。
数组输入输出,数组名前不加&,因为数组名在C语言中代表该数组第一个元素的地址。
//puts(一个字符数组):输出字符串
char str[]={"i love\nyou"}
//puts将结束标志转换为\n,即输出完自动换行
//gets(一个字符数组):输入字符串
gets(str);
//输入的字符个数:输入个数+1
//strcat(字符数组1,字符数组2):字符串连接
strcat(str1,str2);
//将str2拼接到str1中,所以str1要足够大到可以容纳str2,连接时str1的'\0'取消
//strcpy(字符数组1,字符串2):将字符串2赋值到字符数组1中,所以字符数组1要足够大
//strncpy(字符数组1,字符串2,n):将字符串2的前n个字符赋值到字符数组1中,所以字符数组1要足够大
//strcmp(字符串1,字符串2):比较两字符数组大小,逐个字符比较知道不相同或到'\0'
//相同返回0,前者大返回正整数,后者大返回负整数
//stelen(字符数组)
//返回字符串的实际长度,即不包含'\0'
//strlwr(字符串):转换并返回小写
//struor(字符串):转换并返回大写
if(表达式),表达式可以为关系表达式、逻辑表达式、还可以是数值表达式,最直观的为关系表达式,以下同理
#include<stdio.h>
int main(){
int a=0;
scanf("%d",&a);
if(a>10){
printf("%d",a);
}
printf("if 语句已经执行完毕");
}
#include<stdio.h>
int main(){
int a=0;
scanf("%d",&a);
if(a>10){
printf("条件成立,输入值是 %d",a);
}else{
printf("条件错误,输入值是 %d",a);
}
}
#include<stdio.h>
int main(){
int a=0;
scanf("%d",&a);
if(a==1){
printf("a是 %d",a);
}else if(a==2){
printf("a是 %d",a);
} else if(a==3){
printf("a是 %d",a);
} else if(a==4){
printf("a是 %d",a);
} else{
printf("条件都不对");
}
}
依次判断表达式的值,当出现某个值为真时,则执行对应代码块,否则执行else后的代码块。
注意:当某一条件为真的时候,则不会向下执行该分支结构的其他语句。
#include<stdio.h>
int main(){
int a=0;
while(a<10){
printf("重复\n");
a=a+1;
}
}
for可在表达式1中初始化循环变量,在表达式2中设立循环结束条件,在表达式三中使循环趋于结束
省略“表达式1(循环变量赋初值)”,表示不对循环变量赋初始值。
省略“表达式2(循环条件)”,不做其它处理,循环一直执行(死循环)。
省略“表达式3(循环变量增减量)”,不做其他处理,循环一直执行(死循环)。
表达式1可以是设置循环变量的初值的赋值表达式,也可以是其他表达式。
表达式1和表达式3可以是一个简单表达式也可以是多个表达式以逗号分割。
#include<stdio.h>
int main(){
int a=0;
for(a=0;a<10;a++){
printf("重复\n");
}
}
它的执行过程如下:
注意:for循环中的两个分号一定要写
while和dowhile中循环变量的初始化操作应该在其语句前完成,使用do-while
结构语句时,while括号后必须有分号。
#include "stdio.h"
void main()//求各
{
//定义变量并初始化
int i=1;
int sum=0;
do
{
sum+=i;
i+=1; //步长
} while(i<=100); //条件表达式
printf("和是%d",sum);
}
switch(表达式)中,表达式应该为整数类型(包括字符类型),在case后的各常量表达式的值不能相同,否则会出现错误。在case后,允许有多个语句,可以不用{}括起来。
若无break,会持续进行之后的语句
可以没有default语句(如果case一个都没执行,转向default语句),且default语句中可以不加入break语句,
#include
int main()
{
int num = 0;
printf("请输入1~7内整数:");
scanf_s("%d", &num);
switch (num)
{
case 1:printf("今天是星期一\n");
break;
case 2:printf("今天是星期二\n");
break;
case 3:printf("今天是星期三\n");
break;
case 4:printf("今天是星期四\n");
break;
case 5:printf("今天是星期五\n");
break;
case 6:printf("今天是星期六\n");
break;
case 7:printf("今天是星期天\n");
break;
default:printf("输入错误\n");
}
return 0;
}
只希望终止本次循环:continue
希望提前终止整个循环:break
终止只针对所在的循环体中,例如嵌套循环语句,如果break在内循环体中,则只对内循环有效。
类型名 函数名(void){
函数体();
}//无参数时,void可以省略,有参数可替换
在一个函数中调用另外一个函数需要:
//函数声明:不包含参数体,只有函数首部
类型名 函数名(形参类型1 参数名1,形参类型2 参数名2);
类型名 函数名(形参类型1,形参类型2);//声明时可省略参数名
//函数调用
函数名(实参);
虚实结合:实参与形参之间的数据传递
实参向形参的数据传递是“值传递”,单向传递。只能由实参传给形参,而不能由形参传给实参。
函数调用过程:在函数发生调用时,函数的形参临时分配内存>>>将实参的值拷贝传递给对应形参>>>通过return语句将函数值带到主调函数(void类型函数不执行),形参单元被释放。
函数类型决定返回值类型
数组元素可用作函数实参,不能作形参:因为形参在函数被调用时临时分配存储单元,不能为一个数组元素单独分配存储单元。在用数组元素作函数实参时,把实参的值传给形参,是值传递的方式。
用数组名作函数实参时,向形参传递的是数组首元素地址
用数组名声明形参时,不需要指定大小,因为C语言编译系统不检查形参数组的大小,只是将实参数组的首元素的地址传给形参数组名。所以形参数组可以不指定大小,在定义数组时在数组名后跟一个空的方括号。
用指针变量或者数组作为形参,二者等价。
在多维数组作函数参数时,可以省略第一维的大小说明,但是第二维以及更高维的大小声明不能省略。
因为在内存中,多维数组是按行存放,定义二维数组时必须指定列数,由于形参数组与实参数组类型相同,所以它们应是具有相同长度的一维数组组成。
在第二维大小相同的前提下,形参数组的第一维可以与实参数组不同。
局部变量:函数内部定义的变量,只在本函数范围内有效。所以不同函数中的变量同名也互不干扰,形参也是局部变量。
全局变量:函数外部定义的变量,有效范围从定义的范围到源文件结束为止。
用户使用的存储空间分为程序区、静态存储区、动态存储区
静态存储区:全局变量
动态存储区:形参、无static关键字的局部变量,即自动变量、函数调用时的现场保护和返回地址
存储类别 | ||
---|---|---|
自动变量(auto变量) | 动态存储类别—动态存储区 | 在函数被调用时分配存储空间,在调用结束时释放存储空间 |
静态局部变量(static局部变量) | 静态存储类别—静态存储区 | 整个运行期间都不释放,在编译时赋初值一次,每次被函数被调用不重新赋值,保留上一次函数调用结束时的值,不赋初值的话,编译时自动赋值0或’\0’。但是依旧属于局部变量,属于不允许其它函数引用它。 |
寄存器变量(register变量) | 存储在CPU的寄存器中 | 方便多次重复性调用该变量 |
对于全局变量来说,都是存储在静态存储区,但是其作用域有整个文件范围和文件部分范围之分。
在文件内扩展:
如果外部变量不在文件开头定义,其有效范围只限于其定义处到文件结束。如果在其定义前想使用该外部变量,则需要使用extern对该变量作外部变量声明,表示将该外部变量作用域扩展到此处。
int main(){
extern int A;
return A;
}
int A;
扩展到其它文件:
一个C程序可由多个源文件组成,如果两个文件中要用到同一个外部变量,不能分别定义
是在一个文件中定义一个外部变量,再在另外一个文件中使用extern对该外部变量进行重新声明,即作“外部变量声明”。这样可以将另外一个文件的外部变量的作用域扩展到本文件。
当编译遇到extern时,先在本文件找到外部变量的定义,找到就引用本文件的变量,找不到则在连接时从其它文件中找外部变量的定义。
将外部变量作用域限制在本文件
在定义外部变量时加一个static声明,这样就算再另外一个文件中使用是extern也不能扩展其作用域,这样只能用于本文件的外部变量称为静态外部变量。
static对外部变量产生的作用是作用域的限制(本文件),而对局部变量是存储类别的变化(变为静态存储,不释放)
结论注意:在函数中出现的对变量的声明(除了用extern声明的以外)都是定义。在函数中对其它函数的声明不是函数的定义。
内部函数:
static 类型名 函数名(形参){}
在定义函数时,再类型名前加static使之不能被其它文件引用,称为内部函数
外部函数:
extern 类型名 函数名(形参){}
在定义函数时,在函数首部最左端加上extern,则该函数可以为其它文件所调用。在需要调用此函数的其它文件中,依然需要对函数作声明。由于函数在本质上是外部的,所以可以省略extern
指针 = 变量的地址 >指针指向变量的内容
指针变量 = 存放地址的变量 >指针变量指向变量的地址
指针变量与其它变量一样,在定义时可以赋值,即初始化。也可以赋值“NULL”或“0”,如果赋值“0”,此时的“0”含义并不是数字“0”,而是 NULL 的字符码值。
//类型名 *指针变量
int *pointer = 0;
int a = 100;
int *pointer;
pointer = &a;
*pointer = 6;
指针变量是基本数据类型派生的类型,不能离开基本类型而独立存在,所以定义指针变量时必须指定其“基类型”
此处 pointer是指针变量的名字,int *pointer是表示定义了一个指针变量名为pointer, *pointer = 6表示指向该地址的内容更改为6,相当于把6赋值给a
指针变量只能存放地址,不能赋其它的值
当指针作为函数的参数时,它的作用是将一个变量的地址传送到另一个函数中,因为函数传值的机制是拷贝值,当拷贝的值为地址时,就能操作到“原件”。函数的调用至多能得到一个返回值,而使用指针变量作为参数,可以得到多个变化的值。
但是不能企图通过改变指针形参的值,而使指针的实参改变。
//错误
void swap(int *p1,int *p2){
int *p;
p=p1;
p1=p2;
p2=p;
}
//正确
void swap(int *p1,int *p2){
int p;
p = *p1;
*p1 = *p2;
*p2 = temp;
}
在指针变量作为形参时,应当给该参数传地址,这样通过*运算符,才能修改到具体的内存空间中的内容
* :指针运算符——间接访问运算符
& :取址符,&变量名 即可取到该变量的地址
“&”和“*”都是右结合的。假设有变量 x = 10,则&x 的含义是,先获取变量 x 的地址,再获取地址中的内容。因为“&”和“”互为逆运算,所以 x = &x。
数组元素的指针=数组元素的地址:数组名代表数组首元素的地址
所以数组名是一个指针型常量
int *p;
int a[3];
p = a;
//这是将a[0]的地址赋给p
//1、下标法
a[i];
//2、指针法
*(a+i);//a为数组名
*(p+i);//p为指向数组元素的指针变量,初值为p=a
注意:可以通过p++来实现对数组的遍历,而不能通过a++来实现,是因为a作为数组名实际是一个指针型常量,而不是变量,所以a++是无意义的。
如果定义数组int a[9];在数组中引用数组元素a[10],虽然不存在改元素,但是系统将按照*(a+10)处理
p为指向数组元素的指针变量时,p[i]表示*(p+i),所以要搞清楚p当前指向的元素是谁,是在此基础上加减。此处与作为指针型常量的a不同。
int a[10];
int *p = &a[6];
p[3] == *(p+3) == a[6+3]
奇怪写法:看自增自减运算符的位置
*p++ == *(p++);//先取*p的值,然后再使p+1
*(++p) ==*(p+1);//先使p加1,再取*p
++(*p);//先取*p,p指向的值加1
*(p--);//先进行*p取值,再使p自减
*(++p);//先使p自加,再进行*运算
*(--p);//先使p自减,再进行*运算
C编译器都是将形参数组名作为指针变量来处理,当形参含有数组名的函数被调用时,系统会再该函数中建立一个指针变量用来存放从主调函数传递过来的实参数组首元素的地址。
fun(int arr[],int n);
//与下列写法等价
fun(int * arr,int n);
注意:实参数组名代表一个固定的地址即指针常量,但是形参数组名不是固定地址,代表指针变量。
在C程序中,字符串是存放在字符数组中的,想引用字符串有两种方法:
void main(){
char * sring = "cnm";
printf("%s",string);
}
//等同于
void main(){
char * sring = "cnm";
sring = "cnm";//是将字符串的第一个元素的地址赋值给指针变量string
printf("%s",string);
}
区别:通过字符数组名可输出一个字符串,但是通过数值型数组,只能逐个输出。
void copy_string(char from[],char to[]){
int i = 0;
while(from[i]!='\0'){
to[i] = from[i];
i++;
}
to[i]='\0';
}
//指针作形参
void copy_string(char *from,char *to){
for(;*from!='\0';from++,to++)
*to = *from;
*to='\0';
}
用字符数组作为函数参数
char a[] = "bi";
char b[] = "lili";
copy_string(a,b);
用字符型指针变量作实参
char a[] = "bi";
char b[] = "lili";
char *from = a;
char *to = b;
copy_string(from,to);
//错误
char str[14];
str[] = "i love china";
struct 结构体名{
类型名 成员名;
};
//再定义类型后定义变量
结构体名 变量名;
//在声明类型的同时定义变量
struct 结构体名{
类型名 成员名;
}变量名1,变量名2;
//不指定类型名而直接定义结构体类型变量
struct{
类型名 成员名;
}变量名1,变量名2;//因为无名所以不能再去定义其它变量
注意:
当结构体类型中的成员名和程序中的变量名相同时,二者代表的是不同对象。
#include
void main(){
struct Student{
int no;
char[10] name;
}a={10086,"pp"};
printf("%d,%s",a.no,a.name);
}
//在声明时定义并初始化
struct Student{
int no;
char[10] name;
}students[2]={10086,"yd",10000,"lt"};
//在声明时定义不初始化
struct Student{
int no;
char[10] name;
}students[2];
//先声明后定义
struct Student{
int no;
char[10] name;
};
struct Student students[2];//在声明结构体变量时,要加struct
struct Student students[2] = {10086,"yd",10000,"lt"};//在声明结构体变量时,要加struct
struct Student{
int no;
char[10] name;
}students[2]={10086,"yd",10000,"lt"};//实际上这样写更好理解{{10086,"yd"},{10000,"lt"}};
struct Student student1;
student1 = students[1];
struct Student{
int no;
char[10] name;
}student1={10000,"lt"};
struct Student *p;
p = &student1;
printf("%d,%s",(*p).no,(*p).name);
printf("%d,%s",p->no,->name);
(*p).no与p->no等价,->代表p所指向的结构体变量的no成员,所以这两种表达方式与student1.no等价。
struct Student{
int no;
char[10] name;
}students[2]={10086,"yd",10000,"lt"};
struct Student *p;
p = students;
for(;p<stu+2;p++){
printf("%d,%s",p->no,p->name)
结构体数据类型和一般的数据类型本质上相同,其定义的变量数组名也代表了该数组的地址,但是不能直接给该类型的指针变量赋值给类型的成员变量里的数组的数目名,因为类型不同,需要强制转换。
p = (struct Student*)students[0].name;
此时p的值是students[0].name成员的起始地址,可以用printf("%s",p);输出students[0].name的值,p依旧是原来的类型,p+1代表的是students[1].name成员的起始地址。因为此时,p一次增量为struct Student的长度。
//方式一
enum 枚举名{枚举元素列表}枚举类型变量;
//方式二
enum 枚举名{枚举元素列表};
enum 枚举名 枚举变量名;
//方式三
enum {枚举元素列表}枚举类型变量;
C语言对枚举类型的枚举元素按常量处理,故称枚举常量,不能对其赋值。
每个枚举元素都代表一个整数,C语言编译按定义时的顺序默认它们的值为0,1,2,3…。
enum Weekday{mon,tue,wed,thu,fri,sat,sun};
enum Weekday workday;
workday = mon;//相当于赋值workday = 0;
//也可以在定义时给元素常量赋值
enum Weekday{mon=7,tue=1,wed,thu,fri,sat,sun};
//指定mon的值为7,tue为1,后面的常量顺次加1,则fri代表4。
enum Weekday{mon,tue,wed,thu,fri,sat,sun};
eunm Weekday workday;
for(workday=mon;workday<=fri;workday++){
switch(workday){
case mon:printf("%s","mon");break;
case tue:printf("%s","tue");break;
case wed:printf("%s","wed");break;
case thu:printf("%s","thu");break;
case fri:printf("%s","fri");break;
default:printf("%s","weekend")
}
}
可以用typedef指定新的类型名来代替已经有的类型名
typedef int INT007;
INT007 x;
为struct创建的新数据类型取别名,这样声明时就不用重复书写: struct 数据类型名
typedef struct 新数据结构名{
数据结构体;
}数据结构别名;
typedef struct DataType {
float coe;//系数
int exp;//指数
}X;
//这是声明了一个新的类型,别名为X,实际为struct DataType
//同理:
struct DataType {
float coe;//系数
int exp;//指数
};
typedef struct DataType X;
typedef struct DataType {
float coe;//系数
int exp;//指数
};
typedef struct Node {
DataType data;
struct Node* next;
struct Node* pre;
int size;
}DLList;
//构造一个空的一元n次多项式
void Initiate(DLList** P) {
*P = (DLList*)malloc(sizeof(DLList));
(*P)->pre = *P;
(*P)->next = *P;
(*P)->size = 0;
(*P)->data.coe = 0;
(*P)->data.exp = 0;
}
在一元n次多项式中插入新的一项item
void Insert(DLList* P, DataType item) {
DLList* q, * temp;
q = P;
while (q->next != P && q->next->data.exp <= item.exp)//q的下一项指数小于等于插入项
{
q = q->next;
}
temp = (DLList*)malloc(sizeof(DLList));
temp->data.coe = item.coe;
temp->data.exp = item.exp;
temp->pre = q;
temp->next = q->next;
q->next->pre = temp;
q->next = temp;
P->size++;
}
参考原文链接:https://blog.csdn.net/qq_38410730/article/details/80242624
来自
主要类型:程序文件、数据文件
数据流:文件输入与输出,表示信息从源到目的端的移动
数据文件的分类:ASCII文件、二进制文件
文件缓冲区:系统自动在内存区为程序中每一个正在使用的文件开辟一个文件缓冲区,便于节省存取时间
该类型的结构体定义在studio.h头文件中:
//文件类型的定义
typedof atruct
{
int _fd; /* 文件号 */
int _cleft; /* 缓冲区剩下的字符 */
int _mode; /* 文件操作模式 */
char* _nextc; /* 下一个字符的位置 */
char* _buff; /* 文件缓冲区位置 */
}FILE;
//声明变量:
FILe file1;
FILE *file_p;
fopen返回的是指向该文件的指针。文件的指针不是指向一段内存空间,而是指向描述有关这个文件的相关信息的一个文件信息结构体。
FILE *file_p;
file_p = fopen("a1","r");
FILE *file_p;
file_p = fopen("a1","r");
//关闭的方式很简单,只用给fclose传递文件的指针就行
fclose(file_p);
如果不关闭文件就结束结束程序运行将会导致数据丢失,因为执行fclose函数会将文件缓冲区的数据输出到磁盘文件,省略该步骤可能导致数据流失。
fgetc()函数的功能是从指定的文件中读取一个字符,其调用的形式为:
字符变量 = fgetc (文件指针);
如果在执行fgetc()函数时遇到文件结束符,函数会返回一个文件结束符标志EOF(-1)。
fputc()函数的功能是把一个字符写入指定的文件中,其一般调用的格式为:
fput(字符,文件指针);
#include
#include
int main()
{
FILE* fp1, *fp2;
errno_t err;
char c;
err = fopen_s(&fp1, "d:\\1.txt", "w");
if (err != 0) {
printf("文件打开失败!\n");
exit(0);
}
c = getchar();
while (c != '\n') {
fputc(c, fp1);
c = getchar();
}
fclose(fp1);
err = fopen_s(&fp2, "d:\\1.txt", "r");
if (err != 0) {
printf("文件打开失败!\n");
exit(0);
}
c = fgetc(fp2);
while (c != EOF) {
printf("%c", c);
c = fgetc(fp2);
}
printf("\n");
fclose(fp2);
return 0;
}
fgets()函数的功能是从指定的文件中读取一个字符串,其调用的形式为:
fgets(字符数组名,n,文件指针);
其中,n是一个正整数,表示从文件中读出的字符串不超过n-1个字符。在读入一个字符串后加上字符串结束标志’\0’。
如果在执行fgets()函数时如果文件内的字符串读取完毕,函数会返回0。
fputs()函数的功能是把一个字符串写入指定的文件中,其一般调用的格式为:
fputs(字符串,文件指针);
其中,字符串可以是字符串常量、字符数组、字符指针变量。
#include
#include
#include
int main()
{
FILE* fp1, *fp2;
errno_t err;
char s[30];
err = fopen_s(&fp1,"d:\\1.txt", "w");
if (err != 0) {
printf("文件打开失败!\n");
exit(0);
}
gets(s);
while (strlen(s) > 0) {
fputs(s, fp1);
gets(s);
}
fclose(fp1);
err = fopen_s(&fp2, "d:\\1.txt", "r");
if (err != 0) {
printf("文件打开失败!\n");
exit(0);
}
while (fgets(s, 11, fp2) != 0) {
printf("%s", s);
}
printf("\n");
fclose(fp2);
return 0;
}
格式化读/写函数fscanf()和fprintf()
格式化读/写函数与标准的格式输入/输出函数功能相同,只不过它们的读/写对象不是键盘和显示器,而是文件。
fprintf()函数只适用于ASCII码文件的读/写。
两个函数的格式如下:
fscanf(文件指针,格式字符串,输入列表);
fprintf(文件指针,格式字符串,输出列表);
fscanf()和fprintf()函数对文件进行读/写,使用方便,容易理解。但由于在输入时需要将ASCII码转换为二进制格式,在输出时又要将二进制格式转换为字符,花费时间较长,所以在内存与磁盘交换数据频繁的时候,最好不要用这两个函数。
数据块读/写函数fread()和fwrite():
读数据块函数fread(),其调用的一般形式为:
fread(buffer,size,n,文件指针);
fread()函数的功能是从文件中读取字节长度为size的n个数据,并存放到buffer指向的内存地址中去。
函数的返回值为实际读出的数据项个数。比如:
fread(fa,4,5,fp);
其意义是从fp所指向的文件中,每次读4个字节长度(int)送入到fa指向的内存地址中去,连续读5次。也就是说,读5个int类型的数据到fa指向的内存中。
写数据块函数fwrite(),其调用的一般形式为:
fwrite(buffer,size,n,文件指针);
fread()函数的功能是将buffer(是一个文件的地址)中存放的size*n个字节的数据输出到文件指针所指向的文件中去。
函数的返回值为实际写入的数据项个数。
fread()和fwrite()函数一般适用于二进制文件,它们是按数据块的大小来处理输入/输出的。
在C语言中,打开文件时,文件指针指向文件头,即文件的起始位置。在读写文件时,需要从文件头开始,每次读写完一个数据后,文件指针会自动指向下一个数据的位置。但有时不想从文件头开始读取文件,而是读取文件中某个位置的数据。这时,系统提供了定位到某个数据存储位置的函数。
文件头定位函数rewind()
rewind()函数用于把文件指针移动到文件首部,其调用的一般形式为:
rewind(文件指针);
当前读/写位置函数ftell()
ftell()函数用于确定文件指针的当前读/写位置,其调用的一般形式为:
ftell(文件指针);
此函数有返回值,若成功定位,则返回当前位置;否则返回-1。
随机定位函数fseek()
fseek()函数用于将文件指针移动到某个确定的位置,其调用的一般形式为:
fseek(文件指针,位移量,起始点);
此函数有返回值,若成功移动,则返回当前位置;否则返回-1。
其中:位移量指从起始点向前移动的字节数,大多数C版本要求该位移量为long型数据;起始点有三种选择,具体的含义见下表:
C语言还提供了一些检测函数,用于在文件打开、关闭以及读/写操作过程中对有可能会发生的一些情况进行检测。
文件结束检测函数feof()
feof()函数用于判断文件是否处于文件结束为止,其调用的一般格式为:
feof(文件指针);
该函数有返回值,如果文件结束,函数的返回值为1;否则返回值为0。
读/写文件出错检测函数ferror()
ferror()函数用于检查文件在使用各种读/写函数时是否出错,其调用的一般格式为:
ferror(文件指针);
该函数有返回值,如果没有错误,函数的返回值为0;否则返回值非0。
文件出错标志清除函数clearerr()
clearerr()函数用于清除出错标志,其调用的一般格式为:
clearerr(文件指针);
在ferror()函数值为非0时,在调用此函数后,ferror()函数的值变为0。
int main()
{
int i = 0; //定义一个i并且赋初值为0,i作为数组的下标
int j = 0; //定义j并且赋初值为0,j作为找到最大值时所对应的下标
int k; //定义一个k,用来保存此次循环中最大值的下标
int temp; //定义一个中间变量temp,供以后交换值的时候使用
int a[]={4,5,6,72,1,7,9,3,}; //定义了一个9个数的数组,并且初始化
int len = sizeof(a)/sizeof(a[0]); //len是数组的大小
for(i = 0;i<len;i++) //判断i是否小于len,执行下面的语句
{
k = i; //假设此次循环中的最大值就是当前的值
for(j = i+1;j<len;j++)
{
if(a[j]>a[k]) //将假设的当前最大值与后面的值比较
{
k = j; //若后面的值更大,则交换下标
}
},当前最大值
if(k != i) //比较之后如果此次循环中最大值并非当前值
{
temp = a[i]; //将此次循环中的最大值与a[k]交换
a[i] = a[k];
a[k] = temp;
}
}
for(i=0;i<len;i++) //利用for循环将结果依次输出
{
printf("%d ",a[i]);
}
return 0;
}
int main()
{
int i = 0;
int j = 0;
int temp;
int a[10] = {9,8,7,6,5,4,3,2,1,0};
int len = sizeof(a)/sizeof(a[0]);
for(i = 0;i<len-1;i++)
{
for(j = 0;j< len-1-i;j++)
{
if(a[j+1]>a[j])
{
temp = a[j+1];
a[j+1] = a[j];
a[j] = temp;
i++;
}
}
}
for(i = 0;i<len;i++)
{
printf("%d ",a[i]);
}
return 0;
}
#include
int BinSearch(int arr[],int len,int key) //折半查找法(二分法)
{
int low=0; //定义初始最小
int high=len-1; //定义初始最大
int mid; //定义中间值
while(low<=high)
{
//mid=(low+high)/2;//可能会溢出
mid=low+(high-low)/2; //找中间值
if(key==arr[mid]) //判断min与key是否相等
return mid;
else if(key>arr[mid]) //如果key>mid 则新区间为[mid+1,high]
low=mid+1;
else //如果key
high=mid-1;
}
return -1; //如果数组中无目标值key,则返回 -1 ;
}
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9,10,11}; //首先要对数组arr进行排序
printf("%d \n",BinSearch(arr,(sizeof(arr)/sizeof(arr[0])),7));
return 0;
}
#include
#define M 5
#define N 3
//归并排序
int main()
{
int a[M] = {2,3,5,7,9};
int b[N] = {2,4,6};
int c[M+N];
int x = 0,y = 0,t = 0;
while(x<M && y<N)
{
if(a[x] < b[y])
{
// c[t] = c[x];
// t++;
// x++;
// 等价于下面:
c[t++] = a[x++];
}
else
{
c[t++] = b[y++];
}
}
// if(x == M) //优化
// {
while(y<N)
{
c[t++] = b[y++];
}
// }
// if(y == N)
// {
while(x<M)
{
c[t++] = a[x++];
}
// }
for(int i=0;i<M+N;i++)
{
printf("c[%d] = %d\n",i,c[i]);
}
return 0;
}
#include
#include
int main()
{
int n,i,j,a[101][101];
scanf("%d",&n);
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
scanf("%d",&a[i][j]);
}
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{if(j==n-1)
printf("%d\n",a[j][i]);
else printf("%d ",a[j][i]);
}
}
return 0;
}
//高斯-赛德尔迭代法:
#include
#include
double fx1(double x2,double x3){
double x1=0.1*x2+0.2*x3+0.72;
return x1;
}
double fx2(double x1,double x3){
double x2=0.1*x1+0.2*x3+0.83;
return x2;
}
double fx3(double x1,double x2){
double x3=0.2*x1+0.2*x2+0.84;
return x3;
}
double max(double x1,double x2,double x3){
double max=0,m;
if(fabs(x1-fx1(x2,x3))>fabs(x2-fx2(x1,x3))){
m=fabs(x1-fx1(x2,x3));
} else m=fabs(x2-fx2(x1,x3));
if(m>fabs(x3-fx3(x1,x2))){
max=m;
}else max=fabs(x3-fx3(x1,x2));
return max;
}
int main(){
double x1,x2,x3,a,b,c;
int n=0;
printf("输入初值x1,x2,x3\n");
scanf("%f %f %f",&x1,&x2,&x3);
while(max(x1,x2,x3)>0.001){
x1=fx1(x2,x3);
x2=fx2(x1,x3);
x3=fx3(x1,x2);
n++;
printf("%f\t%f\t%f\t\n",x1,x2,x3);
}
printf("迭代次数:%d\n",n);
printf("结果为 x1=%f\t x2=%f\t x3=%f\t",x1,x2,x3);
}
//雅可比迭代法:
#include
#include
double fx1(double x2,double x3){
double x1=0.1*x2+0.2*x3+0.72;
return x1;
}
double fx2(double x1,double x3){
double x2=0.1*x1+0.2*x3+0.83;
return x2;
}
double fx3(double x1,double x2){
double x3=0.2*x1+0.2*x2+0.84;
return x3;
}
double max(double x1,double x2,double x3,double a,double b,double c){
double max=0,m;
if(fabs(a-fx1(x2,x3))>fabs(b-fx2(x1,x3))){
m=fabs(a-fx1(x2,x3));
} else m=fabs(b-fx2(x1,x3));
if(m>fabs(c-fx3(x1,x2))){
max=m;
}else max=fabs(c-fx3(x1,x2));
return max;
}
int main(){
double x1,x2,x3,a,b,c;
int n=0;
printf("输入初值x1,x2,x3\n");
scanf("%f %f %f",&x1,&x2,&x3);
a=x1;
b=x2;
c=x3;
while(max(x1,x2,x3,a,b,c)>0.001){
a=fx1(x2,x3);
b=fx2(x1,x3);
c=fx3(x1,x2);
x1=a;
x2=b;
x3=c;
n++;
printf("%f\t%f\t%f\t\n",x1,x2,x3);
}
printf("迭代次数:%d\n",n);
printf("结果为 x1=%f\t x2=%f\t x3=%f\t",x1,x2,x3);
}
#include
int main()
{
int num[5],num1[5];
int i, j,k=1;
int t,n;
printf("请输入5个数:");
for(i=0;i<5;i++)
{
scanf("%d",&num[i]); //将数读入数组num
}
printf("请输入循环次数:");
scanf("%d",&n);
for(j=0;j<n;j++) //控制转换次数
{
for(i=0;i<5;i++)
{
num1[k]=num[i];
k++;
if(k==5)k=0; //k=5时使数组重新从第一个元素开始读入
}
for(i=0;i<5;i++)
{
num[i]=num1[i]; //将交换过的新数组替换上一个数组
}
}
printf("转换后的数组为 :");
for(i=0;i<5;i++)
{
printf("%d ",num[i]);//输出转换后的数组
}
printf("\n");
return 0;
}
/*
枚举法
1. 设最大公约数ret为1
2.如果a和b都能被i整除 记录下i并令ret = i
3. i++后重复第2步 直到i等于a或b
4. ret即为最大公约数
*/
#include
int main()
{
int a,b;
scanf("%d %d",&a,&b);
int i;
int ret = 1; //记录最大公约数
for( i = 1; i <= a && i <= b; i++){
if(a % i == 0 && b % i == 0){
ret = i;
}
}
printf("%d和%d的最大公约数是%d",a,b,ret);
return 0;
}
/*
辗转相除法
1 如果b等于0 结束运算 a就是最大公约数
2 否则计算a除以b的余数 让a等于b b等于所求的余数
3 回到第一步
*/
#include
int main()
{
int a,b;
int t;
scanf("%d %d",&a,&b);
while( b != 0){
t = a % b;
a = b;
b = t;
}
printf("最大公约数是%d",a);
return 0;
}
//1.常规暴力求解法
#include
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int max = a > b ? a : b; //取得a,b中的最大值
while (max % a != 0 || max % b != 0) //如果不能同时整除a,b
{
max++;
}
printf("%d", max);
return 0;
}
//2.辗转相除法
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int c = a;//将a赋值给c
int d = b;//将b赋值给d
int tmp = 0;//tmp存放a和b的最大公约数
while (a % b)
{
tmp = a % b;
a = b;
b = tmp;
}
printf("%d",(c*d)/tmp );
return 0;
}
//3.迭乘法
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int i = 1;
while ((a * i) % b != 0)
{
i++;
}
printf("%d", i * a);
return 0;
}
#include "stdio.h"
int IsPrimeNumber()
{
for(int i=100;i<1000;i++)
{
for(int j=2;j<i;j++)
{
if(i%j==0)
break;
if(i==j+1)
printf("%d ",i);
}
}
}
int main()
{
IsPrimeNumber();
return 0;
}
#include
#include
int main()
{
int year;
printf("请输入年份:");
scanf_s("%d", &year);
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
printf("%d是闰年\n",year);
else
printf("%d不是闰年\n",year);
system("pause");
return 0;
}
#include
#include
int main(void)
{
int i, j, k, v, hang, lie;
double a[50][50], m;
double b[50][50]; //定义可中途放置的地址
double c[50][50] = { 0 }; //定义检查层的中途存放地址
int num1, num2, num3, num4;
//输入部分
printf("请输入你想计算的行的个数:");
scanf("%d", &hang);
printf("请输入你想计算的列的个数:");
scanf("%d", &lie);
for (i = 0; i < hang; ++i)
{
printf("请输入第%d行元素:", i + 1);
for (j = 0; j < lie; ++j)
scanf("%lf", &a[i][j]);
}
//对角化部分
for (k = 0; k < hang - 1; ++k)
{
for (i = k; i < hang - 1; ++i)
{
for (j = 0; j < lie; ++j)
{
//数组行交换
if (a[k][k] == 0)
{
for (num1 = k; num1 == k; ++num1)
{
for (num2 = 0; num2 < lie; ++num2)
{
c[num1][num2] = a[num1][num2];
a[num1][num2] = a[num1 + 1][num2];
a[num1 + 1][num2] = c[num1][num2];
for (v = 0; v < lie; ++v)
b[k][v] = a[k][v];
//这一步至关重要,少此步,改变的b数组全为0,没有刷新,输出为0
}
}
}
//矩阵换行结束
m = a[i + 1][k] / (1.0*a[k][k]);
b[i + 1][j] = a[i + 1][j] - (m)*a[k][j];
}
}
//将寄存在b中的数据转到a中
for (num3 = 1; num3 <= hang; ++num3)
for (num4 = 0; num4 < lie; ++num4)
{
a[num3][num4] = b[num3][num4];
}
}
//矩阵输出
for (i = 0; i < hang; ++i)
{
{
for (j = 0; j < lie; ++j)
printf("%.2lf ", a[i][j]);
}
printf("\n");
}
system("pause");
}
上三角判断
#include
#define N 10
int main()
{
int i,j,n,count=0;
int a[N][N];
printf("Input n:");
scanf_s("%d",&n);
printf("Input array:\n");
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
scanf_s("%d",&a[i][j]);
}
for (i = 0; i < n; i++)
{
for (j = 0; j < i; j++)
{
if (a[i][j] == 0)
count++;
}
}
if (count == n * (n - 1) / 2)
printf("YES");
else
printf("NO");
return 0;
}
#include
int main()
{
int n,i,j,a[30][30],sum=0;
scanf("%d",&n);
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
scanf("%d",&a[i][j]);
}
}
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(i>=j)
{
sum=sum+a[i][j];
}
}
}
printf("%d",sum);
return 0;
}
#include
#include
double fact(int n)
{
if (n == 0)
return 1;
return fact(n - 1)*n;//求1-(2*n-1)的阶层
}
double fact_2(int n)
{
long sum = 1;
while (n > 1)
{
sum *= n;
n--;
}
return sum;
} //第二种计算阶层的方法
int main()
{
int n = 1, j = 1;//n是项数,j是正负
double x, sinx = 0, order = 1;//x是项,sinx是结果,order是项值
scanf_s("%lf", &x);
while (order >= 1e-3) //精度
{
order = pow(x, 2 * n - 1) / fact(2 * n - 1);
sinx += j * order;
j = -j;
n++;
}
printf("sinx=%lf", sinx );
getchar();
getchar();
return 0;
}
void PascalTriangle()
{
#define ROW 10
int arr[ROW][ROW];
for(int i=0;i<ROW;i++)
{
for(int j=0;j<=i;j++)
{
if(j==0 || i==j)
{
arr[i][j] = 1; //定义第一列和对角线上的数字为1
}
else
{
arr[i][j] = arr[i-1][j-1] + arr[i-1][j];
}
}
}
for(int i=0;i<ROW;i++)
{
for(int j=0;j<=i;j++)
{
printf("%-4d",arr[i][j]);
}
printf("\n");
}
}
#include
int main(void)
{
int a[3][3];
int i,j;
int n = 0,m = 0; //n为主对角线元素之和,m为副对角线元素之和
for (i=0; i<3; ++i) {
for (j=0; j<3; j++) {
scanf("%d",&a[i][j]);
}
}
for (i=0; i<3; ++i) { //按 3x3 输出矩阵
for (j=0; j<3; ++j) {
printf("%4d",a[i][j]);
if (j == 2)
printf("\n");
}
}
for (i=0; i<3; ++i) { //对角线元素相加
for (j=0; j<3; ++j) {
if (i == j) //主对角线
n += a[i][j];
if (i + j == 2) //副对角线
m += a[i][j];
}
}
printf("主对角线元素之和:%d\n",n);
printf("副对角线元素之和:%d\n",m);
return 0;
}