赞
踩
// 基本组成 = 头文件 + 声明 + main函数
#include<stdio.h>
int a = 8;
void main()
{
// 代码块
return 0;
}
#include<stdio.h>
#include<string.h>
#include <stdlib.h>
----先记着 每次都加这几个头文件
转义序列 | 含义 |
---|---|
\n | 换行 |
\r | 输出回车符【不换行】 |
\a | 响铃 |
\b | 退格 |
scanf("%d%d",&a,&b);
----将获取到的数值按照顺序分别赋值给a 和 b
----注意要使用取地址符&进行数值的赋值操作
----可以注意到printf和scanf都是使用的双引号
----& 是取地址符, &b其实就是b的内存地址
----输入的话不需要太考虑占位符之间是否需要空开,像scanf_s("%d%d", &a, &b);与 scanf_s("%d %d", &a, &b); 的输入方式其实是一样的,输入一个数值 回车 再输入一个数值再回车;也就是说 解释器会自动区分两次的输入
printf("a=%d,b=%d",a,b);
printf("i=%o\n",x.i);
printf("ch0=%o,ch1=%o\n
ch0= %c,ch1 =%c\n";
x.ch[0],x.ch[1],x.ch[0],x.ch[1]);
----输出的时候 可以在两端加上必要的字符,在不影响格式化的前提下进行输出内容上的调整
----输出的参数可以直接调用变量来实现输出内容的格式化的替换
----可以注意到printf和scanf都是使用的双引号
----需要通过换行符保证每次输出能不紧挨在一起
----注意,输出printf的时候,会根据格式化字符对输入数据产生对应的识别方式
----大量使用在输入与输出语句
----加粗描黑的为常用的占位符
----%m.nf m是输出数据的字符的个数,n是输出数据的精度
----一种抽象的对数据的特点归纳+对应的定义的可进行的操作
----数据类型的大小通过sizeof运算进行查询
----大小有限
----通常是4个字节的内存单元
----可进行算术运算,赋值运算,关系运算
----数据的一种存储方式
#define PI 3.1415926const double eps = 0.001; //误差精度
----数据的一种存储方式
----变量用来临时存放原始数据
----数据类型的具体对象,是内存中的某块区域,可进行存储与删除数据的操作
----编译器遇到变量声明语句会按照数据类型为变量分配指定的存储空间
----基本结构:变量类型 变量名(标识符)
----double percent2=1.00;–>这里的 等于号 不是赋值运算,是初始化,这条语句仍然是变量声明语句
----声明举例
double high;
double high,faHeight,moHeight;
double high,faHeight,moHeight,percent1=1.00,percent2=1.00;
#define pi 3.1415926
----该操作称为宏定义
----可以将符号当作变量放在代码里面
----是在预处理阶段执行的命令,该阶段会把代码中的pi逐个替换为3.1415926,所以不占用内存空间
隐式转换----在运算时,计算机会自动按照操作舍去低位精确数值或者补零来强制实现数据的操作–>计算机为了输入数据能进入操作函数进行处理,自动将输入数据的类型转化为指定格式进行处理
显式转换----程序员通过代码手动转换–>
–>eg.(类型名)表达式–>average = (float)(1+2)–>average的值为3.000000
运算符 | 含义 | 结合性 |
---|---|---|
() | 括号 | |
+ - | 单目运算,取正、负 | 从右向左 |
* / % | 双目运算,乘除,求余 | 从左向右 |
+ - | 双目运算,加减 | 从左向右 |
= | 双目运算,赋值 | 从右向左 |
----越靠上 优先级越高
----使用 = 的式子,通过等于号的是否成立得出逻辑真假
----逻辑真为1,逻辑假为0
----逻辑真假的0与1其实是int类型
if (a==b)
{
printf("a和b相等\n");
printf("a和b相等\n");
}
或
if (a==b)
{
printf("a和b相等\n");
printf("a和b相等\n");
}
else
{
printf("a和b不相等\n");
printf("a和b不相等\n");
}
或
if(i >= 'a' && i != 'q' && i<='z')
{
xiaoxie++;
}
else if(i >= 'A' && i != 'Q' && i<='Z')
{
daxie++;
}
else
{
qita++;
}
或
//嵌套if
if(grade>=60 )
if(grade<70)
if(grade%2==0)
printf ("Passed! \n") ;
----注意 if 和 else if 和 else 的分别的使用方法
char op;
double a,b,result;
scanf("%lf %c %lf",&a,&op,&b);
switch (op)
{
case '+':
printf("%.2lf",(double)a+b);
break;
case '-':
printf("%.2lf",(double)a-b);
break;
case '*':
printf("%.2lf",(double)a*b);
break;
case '/':
if(b==0)
{
printf("除数不能为0");
break;
}
printf("%.2lf",(double)a/(double)b);
break;
default:
printf("运算符有误");
}
----通过switch括号内部的变量的取值判断执行的是哪部分语句
----可以注意到,内部是通过直接case进行变量与条件的比较与判断,在该条判断执行语句结束时需要使用break跳出当前case的代码块;直接在引号后面敲代码即可
----default则是用来进行没有case匹配上的附加操作,不需要break,也是直接在引号后面敲代码即可
----switch其实就是多分支的if else 语句,判断输入变量的值与case的分支内容是否相等,可看作中间通过 == 连接
----大致格式–> 条件 ? 操作_0 : 操作_1
----? 与 : 称为条件运算符
----当条件成立则执行操作_0 ,否则执行操作_1
----字符类型实际上是使用二进制编码进行表示
----'A’如这种方式,是表示的字母A的二进制编码,单引号是用来将字符转换为二进制编码的工具----是逐个逐个字符地使用二进制代码进行表示
//对字符进行赋值
int main()
{
char c='a';
printf("%c",c);
return 0;
}
//----这样的返回值是a,得用单引号使用ASCI码进行表示,使用双引号会报错
a = getchar();
putchar(a);
----输出为a 等价于scanf与printf 是简化版的输入输出语句
----算数运算>关系运算>逻辑与运算>逻辑或运算
----逻辑运算的短路性:逻辑与运算的表达式,从左往右运算,遇到0就不用计算了;逻辑或的表达式,遇到1就不能继续向右计算了【与或门本身的属性】
----是使用的 && ||进行门的表示
#include "stdio.h"
int a = 1;
int main(){
printf("a = %d ", a++);
return a;
}
/*--------------------分割线--------------------*/
#include "stdio.h"
int a = 1;
int main() {
printf("a = %d ", ++a);
return a;
}
/*--------------------分割线--------------------*/
#include "stdio.h"
int a = 1;
int main() {
printf("a = %d ", a+=1);
return a;
}
----C语言自加自减运算符(++i / i++) Leon称之为自运算,方便概述与记忆
---- printf("a = %d ", a++);的含义为先对a进行a的输出操作,再进行+1操作,因为++在变量的后面,所以输出为1
---- printf("a = %d ", ++a);的含义为先进行+1操作,再对a进行a的输出操作,因为++在变量的前面,所以输出为2
----printf("a = %d ", a+=1);的含义为先进行+1操作,再对a进行a的输出操作,输出为2
----其他相似的运算符号同理
for(j=1;j<=i;j++)
{
printf("%d",j);
printf("%d",j);
}
/*--------------------分割线--------------------*/
for(;;num++)
{
scanf("%d",&a);
if(a<=0)
{
break;
}
sum+=a;
if(a<60)
{
failed++;
}
}
----第一个参数是进行变量的初始化
----第二个参数是判断是否需要进行迭代,是每个小循环体的起点
----第三个参数是用于for 循环的结束,起到避免无限循环的作用,只有当括号内程序运行结束时才会执行第三个参数的操作
----可以看到 for 循环语句的初始括号可以空着不填,只要代码合理即可
/*从1加到100*/
#include <stdio.h>
int main0
int i= 1,sum=0;
do
{
sum=sum+i;
i++;
}
while(i<= 100];
printf("sum=%d\n" ,sum);
return 0;
}
----与while的不同点在于,while先判断再执行,而do while是先执行再判断
void main()
{
int i=0;
while(i<10)
{
if(i<1)continue;
if(i==5)break;
i++;
}
}
----用于实现跳出循环体的此次循环,进入下一次循环;与break相对应
返回值的数据类型 函数名(参数_0,参数_1)
{
return ;
}
long fact(long a);
----用于避免函数之间顺序相对关系造成的函数无法正常读取
----函数名和参数都要写
----这样的函数形式称为函数原型,此时形参的名字其实可有可无,编译器关系的是参数的类型与数量
----程序执行的时候,调用函数其实是取找函数的定义,跳到函数定义的地方去执行代码
----驱动函数
----测试函数
----main函数
----局部变量是在函数里进行定义的,也只在函数运行的代码块里生效
----全局变量与局部变量同名时,在函数内部局部变量起作用而外部变量被忽视
----全局变量全过程中占用存储单元,降低内存利用率
----函数通用性降低,容易导致撞名–>相互影响性大
----对人为阅读造成困难
// 定义一个整型数组num 分别有5个元素num[0],num[1],num[2],num[3],num[4],也是从0开始计数
int num[5]
//数组 载入 数值
for(j=0;j<10,j++)
scanf("%d",&a[j]);
//数组 输出 数值
for(j=0;j<10,j++)
printf("%d",a[j]);
----数组定义时,方括号中的数意味着数组中含有的元素个数,而下标值则是从0开始数
----数组定义时,方括号中的数不能是变量,只能是常量
----系统不检查数组元素下标的越界问题
int num[5]
scanf("%d",&a[0])
//初始化方式 以下方式 全部等价
int a[5] = {6,2,4}
int a[5] = {6,2,4,0,0}
int a[ ] = {6,2,4,0,0}
a[0]=6,a[1]=2,a[2]=4,a[3]=0,a[4]=0
----定义一个整型数据num,其中包含五个元素分别是num[0],num[1],num[2],num[3],num[4]
----关注数组的使用方式–参考变量,和变量的使用方式差不多
----关注 初始化方式
// 逐一逐位置赋值
int a[3][4] = {{1,2,3,4},{1,2,3,4},{1,2,3,4}}
int a[3][4] = {1,2,3,4,1,2,3,4,1,2,3,4}
// 部分元素地赋值
int a[3][4] = {{1},{1,5},{1,2,3}}
----第一个数字所在区域对应第一层括号---第一维度
// 可省略第一维度而不可省略第二维度
int a[][4] = {1,2,3,4,5,6,7,8,9,0}
int a[][4] = {{0,0,3},{},{0,10}}
//初始化
char ch[5] = {'2','2','2','2','2'}
char ch[5] = {'2','2','2'} --存储结果-->{'2','2','2',\0,\0}
char ch[5] = {'Hi'} --存储结果-->{'H','i',\0,\0,\0}
char ch[][4] = {{'0','0','3'},{},{'0','10'}}-->与普通数组其实几乎同理
----字符数组最后一位总是\0 所以存储十个元素需要11个位,系统会自动补齐----创建时需要估计好位置数量预留位置给终止符
----scanf printf内部自动与字符串的终止符机制相匹配
//获取与输出字符串
puts(str); /* print(%os",str); */
gets(str); /* scanf("%s",str); */
//拼接字符串
{char a[20] =“Visual";
char b[]=“C++";
strcat(a ,b);
printf("%s\n", a);// Visual C++
//将b拷贝进a或c
char b[]= "C++",
c[] =“Visual";
strcpy(a, c);
strcat(a, b);
printf("%s\n", a);
//从左往右逐一比较ASCI码的大小
//若字符串1<字符串2, 返回负整数;若字符串1>字符串2,返回正整数;若字符串1==字符串2,返回零
char str1[] =“Hell0!", str2[] =“Hello!";
if(strcmp(strl, str2)>0)
printf(“Hell0!> Hello!");
else if(strcmp(strl, str2)==0)
printf("Hell0!= = Hello!");
else
printf("Hell0!< Hello!");
//获取字符长度
char str1[] = "Hello!"', str2[] = "How are you?";
int len1,len2,len3;
len1=strlen(str1) ;
len2=strlen(str2);
printf(len1=%d len2=%d",len 1,len2);
//大小写字母转换
//strlwr(str)函数:将字符串中大写字母转换成小写字母.
//strupr(str)函数:将字符串中小写字母转换成大写字母.
//字符串转化为浮点数
a = atof(strA);
//一维数组
void sort(int array[],int n);
//二维数组
void sort(int array[][10],int n);
----关注的是填入数组时候,作为参数时在描述属性上的差异
----可以看到 可以不要求输入数组长度大小,加强适用性
#include <stdio.h> //冒泡排序优化
#define N 6
void main ( )
{
int a[N], i, j, t,flag=1;//为1时表示有交换
//输入N个整数----获取数据
printf ("input %d numbers: \n", N);
for(i=0;i<N; i++)scanf ("%d", &a[i);
//排序
for(i=1;i< N; i++) //N-1趟冒泡排序
{
if(flag== =0) break; //表示上一-趟没有交换----
else {flag=0; //初始为无交换
for(j=0;j<N_i; j++)//一趟冒泡排序
{
if(a[j] > a[j+1]) //交换a[j]和a[j+1]
{t= a[j]; a[j] = a[j+1]; a[j+1]= t; flag=1;}
}
}
printf ("the sorted numbers:\n");
for(i=0;i<N; i++)printf ("%d ", a[i]);,
}
----其实就是诸葛==逐个查找
#include <stdio.h>
#define N 6
void main()
{
int i,X;
int array[N]={9,7,2,8,1,6};
printf("please input search x=");
scanf("%d" ,&x);
for(i=0;i<N;i++) //顺序查找
{
if(array[i]==x)
{
print("i=%d,x=%d\n",i,x);//查找成功
break;
}
}
if (i= =N) printf("not found\n");//查找失败
}
----使用前提是本身就有序
void main()
{
int x,low,high,mid;
int array[N]={1,2,6,7,8,9};
printf(" please input search x=");
scanf("%d",&x);
low=0;
high=N-1;
mid=(low+high)/2;
while(low< =high && array[mid]!=x) //继续折半查找
{
if(x<array[mid]) high=mid-1;
else low=mid+1;
mid=(low+high)/2;
if (low>high)
printf("not found\n";//查找失败
else
print("i=%d,x=%d\n",mid,x);//查找成功
}
…
…
----在程序中定义一个变量时,对程序进行编译时,系统会为这个变量分配内存单元,根据定义的数据类型大小为该变量创建一个空间域,这块空间与使用一个位置数字来表示,这就是地址
----通过地址可以寻找到所需的变量单元,可以说地址指向该变量单元,这样的地址称为指针
----地址的组成是对应的数据的内存编号和对应的数据的数据类型
----直接使用变量名访问称为直接访问形式,使用指针进行访问则称为直接访问
----指针变量中只能存储一个地址,是存储一个整数数值
----间接访问符:* ;*运算可以搜寻对应数值的位置下存储的数据
int num=3;
int * num_in ;//指向整数的指针num_in 指针的 名字是num_0
num_in = & num;//将变量的地址赋值给指针,指针对应的变量是num
//*num_in的值为3
int num=3;
int * num_in ;
num_in = & num;
//*num_in的值为3
num = 4;
printf("%d",*num_in);//输出为4
//理解,可以通过指针直接修改对应位置上的数值,也可以通过变量修改,本质上其实指针和变量都是查询和修改计算机某块存储区域上的一种方式,只是一种工具一种索引方式罢了
int a[4];
int *p = a;
//理解 是可以通过指针去记录数据的首位地址,然后通过指针读取信息时是可以通过数据类型的信息帮助计算机去读取指针后面指定的位数以及进行相关的操作
----一个是取地址符,一个是指针运算符,当两个同时出现的时候是互相抵消不产生作用的意思----互逆运算之间的抵消
----函数的调用只可以返回一个值,因此可以借助指针返回一个数值,通过这个数值等价于返回多个数值
#include <stdio.h>
void swap(int a, int b){
int temp; //临时变量
temp = a;
a = b;
b = temp;
}
int main(){
int a = 66, b = 99;
swap(a, b);
printf("a = %d, b = %d\n", a, b);
return 0;
}
//-->输出为66 99
//-----------------使用指针---------------------
#include <stdio.h>
void swap(int *p1, int *p2){
int temp; //临时变量
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
int main(){
int a = 66, b = 99;
swap(&a, &b);
printf("a = %d, b = %d\n", a, b);
return 0;
}
//-->输出为99 66
----一些理解,函数本身是将输入的参数传入函数专有的区域进行相关处理,不会影响到原先外界的变量,由第一段代码可以看出
----但是如果一开始告诉函数传入的是指针的话,就看也通过指针去索引对应的地址去改变外部函数的值
----函数在编译时被分配的入口地址就称为函数的指针,使用函数名进行表示
----这里之后需要看看
//指针指向函数
int man(int,int),(*p)();
c = (*p)(a,b) //--> c = max(a,b)
int *f(int x,int y)//就是简单地加一个 * 符号就可以了
char *string = "I love china";
//string被定义为一个指针变量,类型为字符型,上述的操作时将这整个字符串的首位字符传递给指针变量string 用于指向地址的作用
//使用的方式如图
string = "i am a student";
printf("%d",string);//-->i am a student
//系统会自动对字符串进行逐位输出
//-----------------分割线---------------------
#include <stdio.h>
int main()
{
char a[="I am a boy,",b[20].*p1,*p2;p1=a;p2=b;
//p1,p2分别指向a数组和b数组中的第一个元素
for(;*p1!='\0';p1++,p2++) //p1,p2每次自加1
*p2=*p1; .
//将p1所指向的元素的值赋给p2所指向的元素
*p2='\0';
//在复制完全部有效字符后加"\0'
printf("string a is:%s\n",a); //输 出a数组中的字符
print("string b is:%s\n",b); //输 出b数组中的字符内
return 0;
}
//这里强调的是使用指针本身存在的数值加法性质实现的一些功能
int array[10];
int *p;
//以下操作都是等效的,默认好了,都能通过如图的输出格式进行处理
p = &array[0];
int *p = &array[0];
int *p = &array;
----对于数组元素a[i]而言,a[i]其实指的就是a这个数组的第i个元素,是通过[]将地址i进行了寻址并获取数据,a[i]等价于*(a+i)、
----指向数组的指针也可以直接这么使用*(p+i)=p[i]=a[i]=*(a+i)
//字符串也可以使用指针直接表示
char * string;
string = "I am C"
printf("%s",string);
----可以对字符指针变量进行赋值,但是不能对数组名【数组首元素的地址】进行赋值
----指针变量的值可以改变,但是数组字符名不可以
----字符数组中的元素值可以改变,但是字符指针变量的不可以
----指针变量在printf中的巧用:代替格式化语句
char *format= "a=%d,b= %f\n";
printf(format,a,b);
含义 | 定义 |
---|---|
int i; | 定义整型变量i |
int *p; | p为指向整型数据的指针变量 |
int a[n]; | 定义含n个元素的整型数组a |
int *p[n]; | n个指向整型数据的指针变量组成的指针数组p |
int(*p)[n]; | p为指向含n个元素的一维整型数组的指针变量 |
int f(); | f为返回整型数的函数 |
int *p(); | p为返回指针的函数,该指针指向一个整型数据 |
int (*p)(); | p为指向函数的指针变量,该函数返回整型数 |
int **p; | p为指针变量,它指向一个指向整型数据的指针变量 |
----将不同类型的数据整合成为一个整体
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
struct student stu1 stu2;
//-----------------分割线---------------------
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1 ,stu2;
//-----------------分割线---------------------
struct
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1 ;
----以上三种都是结构体的定义方式,第一种属于分段定义,第二种属于定义的同时基于结构体名字,第三是定义结构体无名时只能赋予该无名结构体一个名字。
stu1.num = 10;
stu1.score = 99;
struct student
{ int num;
char name[20];
struct date
{ int month;
int day;
int year;
}birthday;
}stu1 ,stu2;
stu1.birthday.month = 12;
struct
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1 ;
struct student stu1={112,"Wang Lin",'M',19,"200 Beijing Road"};
//-----------------分割线---------------------
struct
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1 ={112,"Wang Lin",'M',19,"200 Beijing Road"};
struct student
{
int num;
char name[20];
char sex;
int age;
}stu[3];//使用数组索引来同时集成多个结构体
//-----------------分割线---------------------
struct student stu[]={{100,"Wang Lin",'M',20},{101,"Li Gang",'M',19},{110,"Liu Yan",'F',19}};
struct student
{ int num;
char name[20];
char sex;
int age;
}stu;
struct student *p=&stu;
//创建一个结构体的指针,他指向stu这个结构体
stu.num = 101 等效于 (*p).num=101
----用结构体变量的成员做参数
----用结构体变量做参数----值传递,效率低----其实没搞懂为什么认为使用变量的效率低一些
----指向结构体变量的指针做参数----地址传递
----经典格式
struct student
{
int num ;
char name[10];
struct student *next;
}
a = malloc(100);//开辟一块区域,100字节大小,返回值位第一个字节的地址;若返回值为空则说明内存空间不足无法成功创建
p=(int *)malloc(n*sizefint)//通常使用的举例
//malloc 不对申请的空间初始化
//calloc将申请的空间初始化为0
int *p
free(p)
//用来释放 指针对应的内存
//动态调整内存大小
realloc(void *p,int newsize);
//通过指针去调整对应的内存,将内存调整为newsize的大小
----使不同类型的变量共存一段内存,紧挨在一起
----一些规则:
--------不能直接引用共用体变量,但可以引用其成员
--------定义变量的时候需要通过索引对内部成员进行逐个定义
--------可以使用整个共用体变量对其他变量进行赋值–eg.a = union
//基本结构
union data
{
int i;
char ch;
float f;
};
union data
{
int i;
char ch;
float f;
};
union data a,b,c,*p,d[3];
//引用数组的方式
a.ch a.i a.f
p->i p->ch p->f
(*p).i (*p).ch (*p).f
d[0].i d[0].ch d[0].f //-->注意这里要使用的是索引0,从地址号开始
----结构体于共用体的存储方式不同,两者可互相嵌套
----共用体的变量地址和他的各成员的地址都是同一地址
----不能使用共用体的变量名获得一个值,也不能对共用体的变量名进行赋值
----一个变量只有集中的可能的值,则可以定义为枚举类型,所谓”枚举“就是指把可能的值一一列举出来
enum Weekday{sun,mon,tue,wed,thu,fri,sat};
//枚举类型使用enum进行开头,花括号中的元素称为枚举元素或者枚举常量
//也可以按照结构体类似的方式去进行定义
enum {sun,mon,tue,wed,thu,fri,sat}workday,weekend;
//默认是 sun=0,mon=1,tue=2,wed=3,thu=4,fri=5,sat=6----这种类型的出现主要是用来方便代码阅读----也可以硬性修改值-->
enum {sun=1,mon,tue,wed,thu,fri,sat}workday,weekend;
//现在是sun=1,mon=1,tue=2,wed=3,thu=4,fri=5,sat=6
----用于给变量类型起别名
----是对已存在的类型起一个别名,实际上没有创造新的类型
----简化编程难度
----#define实在预编译时进行简单的字符替换处理,而typedef是在编译阶段处理的 不是简单的字符替换
----可以在一个文件中声明多种数据类型 然后在其他文件中使用#include指令把他们包含到文件中,简化编程难度
typedef int int_Leon;
int_Leon a;
//声明了- -个新类型名Date,代表结构体类型.
typedef struct
{ int month;
int day;
int year;
}Date;
//定义结构体类型变量birthday,不要写成struct Date birthday;
Date birthday;
//定义结构体指针变量p,指向此结构体类型数据
Date*p;
typedef int Num[100]; // 声明Num为整型数组类型名
Num a;//定义a为整型数组名,它有100个元素
//声明String为字符指针类型
typedef char* String;
//定义p为字符指针变量,s为字符指针数组
String p,s[10];
// 声明Pointer为指向丽数的指针类型,该函数返回整型值
typedef int (* Pointer)();
Pointer p1,p2;// p1,p2为Pointer类型的指针变最
**程序文件:**包括源程序文件(后缀为c)、目标文件(后缀为.obj)、可执行文件(后缀为.exe)等。这种文件的内容是程序代码。
**数据文件:**文件的内容是供程序运行时处理的数据
----为了简化用户对输入输出设备的操作,操作系统把各种设备都统一作为文件来处理。从操作系统的角度看,每一个与主机相连的输入输出设备都看作一个文件。例如,终端键盘是输入文件,显示屏和打印机是输出文件。
----文件一般指的是存储在外部介质上数据的集合,操作系统是以文件为单位对数据进行管理的。
----输入输出是数据传送的过程,数据如流水一样从一处流向另一处,因此常将输入输出形象地称为流(stream),即数据流。流表示了信息从源到目的端的流动。
----在输入操作时,数据从文件流向计算机内存,在输出操作时,数据从计算机流向文件(如打印机、磁盘文件)。
----C语言把文件看作一个字符(或字节)的序列,即由一个一个字符(或字节)的数据顺序组成。
----输入输出数据流的开始和结束仅受程序控制而不受物理符号(如回车换行符)控制,这就增加了处理的灵活性。这种文件称为流式文件。
----一个文件要有一个唯一的文件标识,以便用户识别和引用
----文件标识包括3部分: (1)文件路径; (2)文件名主干; (3)文件后缀–>D:\CC\temp\file1.dat
----文件路径表示文件在外部存储设备中的位置。
----文件后缀用来表示文件的性质。
----为方便起见,文件标识常被称为文件名,但应了解此时所称的文件名,实际上包括以上3部分内容,而
不仅是文件名主干。
----数据文件可分为ASCII文件和二进制文件。
----数据在内存中是以二进制形式存储的,
----如果要求在外存则上以ASCII代码形式存储,需要在存储前进行转换。ASCII文件又称文本文件(textfile) ,每一个字节存放一个字符的ASCI代码。
----用ASCII码形式输出时字节与字符一一对应,一个字节代表一个字符,因而便于对字符进行逐个处理,也便于输出字符。但一般占存储空间较多,而且要花费转换时间(二进制形式与ASCII码间的转换)。用二进制形式输出数值,可以节省外存空间和转换时间,把内存中的存储单元中的内容原封不动地输出到磁盘(或其他外部介质)上,此时每一个字节并不一定代表一个字符。
----ANSIC标准采用“缓冲文件系统’处理数据文件,所谓缓冲文件系统是指系统自动地在内存区为程序中每一个正在使用的文件开辟一个文件缓冲区 。-- ----从内存向磁盘输出数据必须先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘去。
----如果从磁盘向计算机读入数据,则一次从磁盘文件将一批数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(给程序变量)。
----这样做是为了节省存取时间,提高效率,缓冲区的大小由各个具体的C编译系统确定。
被使用的文件会在内存中开辟一个相应的文件信息区,用来存放文件的相关信息,这些信息都是保存在一个结构体变量中。该结构体是由系统声明的,取名为File;
typedef struct
{
short level; //缓冲区“满"或“空"的程度
unsigned flags; //文件状态标志.
char fd; //文件描述符
unsigned char hold; //如缓冲区无内容不读取字符
short bsize; //缓冲区的大小
unsigned char*buffer; //数 据缓冲区的位置
unsigned char*curp; //文件位置标记指针当前的指向
unsigned istemp; //临时文件指示器
short token; //用于有效性检查
}FILE;
//-种C编译环境提供的stdio.h头文件中有以下的文件类型声明
FILE *fp//定义一个指向FILE类型数据的指针变量,是一个结构体变量通过改变量就能访问该文件,获取内部的信息;这种指针称为指向文件的指针变量;指向的是文件信息区的首指针而不是外部介质上数据文件的开头
----打开值得是为文件建立相应的文件信息区【用来存放有关文件的信息】和文件缓冲区【用来暂时存放输入输出的数据】
----使用一个指针和一个结构体完成相关的操作
----关闭是指撤销文件信息区和文件缓冲区,使文件指针变量不再指向该文件,显然就无法进行对文件的读写了
//fopen打开数据文件
FILE &fp;
a = fgetc(fp) //获取一个字符,返回值为一个字符
fp = fopen("a1","r");//返回值是指向a1文件信息区的指针
fgets(str,n,fp) //获取一串长度为n-1的字符存到str,返回的是str数组首元素的值
fputc(ch,fp)//向文件里写入一个ch字符,输出成功则返回输出的字符,失败则返回EOF即-1
fputs(str,fp)//将str的字符串写入文件指针变量fp的文件里;输出成功则返回0,否则返回-1
fprintf(fp,"%d %d",i,f);//按照指定格式输入到文件中
fscanf(fp,"%d %d",&i,&f);//按照指定格式从文件获取数值
//判断文件是否读到末尾
while((ch=fgetc(fp))!=EOF)//EOF=-1,读完则返回-1
while(!feof(fp))//文件结束则返回非0数值,未结束则返回0
文件处理方式 | 含义 | 指定文件不存在 |
---|---|---|
"r” (只读) | 为了输入数据,打开一个已存在的文本文件 | 报错 |
“W” (只写) | 为了输出数据,打开一个文本文件 | 为了输出数据,打开一个文本文件建立新文件 |
"a” (追加) | 向文本文件尾添加数据 | 出错 |
“rb" (只读) | 为了输入数据,打开一个二进制文件 | 出错 |
“wb” (只写) | 为了输出数据,打开一个二进制文件 | 建立新文件 |
“ab” (追加) | 向二进制文件尾添加数据 | 出错 |
“r+” (读写) | 为了读和写,打开一个文本文件 | 出错 |
"w+” (读写) | 为了读和写,建立一个新的文本文件 | 建立新文件 |
“a+” (读写) | 为了读和写,打开一个文本文件 | 出错 |
“rb+" (读写) | 为了读和写,打开一个二进制文件 | 出错 |
“wb+” (读写) | 为了读和写,建立一个新的二进制文件 | 建立新文件 |
“ab+” (读写) | 为读写打开一个二进制文件 | 出错 |
----fgets和fputs以指定文件为读写对象,而gets和puts以终端为读写对象
fprintf(fp, "%d.,6.2f",i,f); //将int型 变量i和float型变量f的值按%d和%6.2f的格式输出到fp指向的文件中
fscanf (fp,"%d,6f" ,&i,&f);//磁盘文件.上如果有字符“3,4.5",则从中读取整数3送给整型变量i,读取实数4.5送给float型变量f
//----C语言允许用fread函数从文件中读一个数据块,用fwrite函数向文件写一个数据块。
//----在读写时是以二进制形式进行的。
//----在向磁盘写数据时,直接将内存中一组数据原封不动、不加转换地复制//到磁盘文件上,在读入时也是将磁盘文件中若干字节的内容一批读入内存
//注:如果函数执行成功,则返回值为形参
fread(buffer, size, count, fp);
fwrite(buffer, size, count, fp);
buffer,是一个地址,存储文件读入数据区的起点地址;size要读写的字节数,count需要读写的数据项的项数,每个数据项长度为size fp:FILE类型指针
a = fread(f,4,10,fp);
----在任意位置上读写文件,效率提升
//rewind()使文件位置标记指向文件开头
//rewind(文件指针);
//rewind函数的作用是使文件位置标记重新返回文件的开头,此函数没有返回值。
//用fseek函数改变文件位置标记
//“起始点":用0, 1或2代替, 0代表"文件开始位置",1为“当前位置",2为"文件末尾位置",使用数值来标记初始定义的位置
//fseek(文件类型指针,位移量,起始点);
//“位移量":指以起始点”为基点,向前移动的字节数(长整型)
//fseek函数一般用于二进制文件。
fseek (fp,100L,0);//将文件位置标记向前移到离文件开头100个字节处
fseek (fp,5OL,1);//将文件位置标记向前移到离当前位置50个字节处
fseek (fp.-10L,2);//将 文件位置标记从文件末尾处向后退10个字节
//用ftell函数测定文件位置标记的当前位置
//ftell函数的作用是得到流式文件中文件位置标记的当前位置,用相对于文件开头的位移量来表示。如果调 用函数时出错(如不存在fp指向的文件),fell函数返 回值为-1L。
i=ftell(fp);//变量i存放文件当前位置
if(i==-1L) print(" error\n"); //如:果调用函数时出错,输出"error"
ferror(fp);
在调用各种函数处理时,可以使用ferror进行检查,返回值为0表示未出错,否则已经出错,此时应使用clearerr(fp)或者rewind进行error值清0以便下一次检测
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。