C语言——遗忘知识点回忆记录

25 篇文章 4 订阅

1. printf()   本身不换行

 

2. scanf("x=%lf", &x)

在输入数据是,需要原样输入字符:x=9.5

 

3. 关于函数声明(又叫“函数原型声明”)

在使用函数之前应该先声明,事先通知编译器该函数的类型:换句话说,一个声明即是描述一个函数的接口。声明至少应指明函数返回值的类型。

  • 函数直接定义在 main() 函数之前,不需要声明:
int sum(int a, int b) {
    return a + b;
}

int main()
{
    int c = sum(1, 2);
    return 0;
}
  • 函数定义在 main() 函数之后,在 main() 函数之前 或者 在 main() 函数里面 要先声明:
//函数声明
int sum(int a, int b);

int main()
{
    int c = sum(1, 2);
    return 0;
}

// 函数定义
int sum(int a, int b) {
    return a + b;
}

或者

int main()
{
    //函数声明
    int sum(int a, int b);

    int c = sum(1, 2);
    return 0;
}

// 函数定义
int sum(int a, int b) {
    return a + b;
}

 

 

4. #include <stdio.h>  &  #include "stdio.h"

#include <stdio.h>:如果使用<>,将使用C语言的标准头文件,有编译程序到C系统中设置好的include文件夹中把指定的文件包含进来。

#include "stdio.h":如果使用"",则编译程序首先到当前工作文件夹寻找被包含的文件,若找不到,再到系统include文件夹中查找文件,一般适用于编程者自己的包含文件,必要时可以在文件名前添加所在路径。

常用标准头文件

 

5. c语言标识符只能由 下划线"_",数字,字母 组成,且第一个字符必须是下划线"_"或字母

 

6. c语言本身没有输入输出语句,通过调用系统库函数中的有关函数实现的;printf()和scanf()都是stdio.h头文件里的

 

7. a=i++ & a=++i

a=i++ :1. a=i;     2. i=i+1;

a=++i :1. i=i+1;      2. a=i;

 

8. 编译过程

.cpp -->  .obj :生成二进制代码表示的目标程序

.obj -->  .exe :与编程环境提供的库函数进行链接

 

9. 单步调试时 step into  &  step over  &  step out

原文链接:https://blog.csdn.net/huangfei711/article/details/51220382

step into:单步执行,遇到子函数就进入并且继续单步执行(简而言之,进入子函数);

step over:在单步执行时,在函数内遇到子函数时不会进入子函数内单步执行,而是将子函数整个执行完再停止,也就是把子函数整个作为一步。有一点,经过我们简单的调试,在不存在子函数的情况下是和step into效果一样的(简而言之,越过子函数,但子函数会执行)。

step out:当单步执行到子函数内时,用step out就可以执行完子函数余下部分,并返回到上一层函数。

 

10. 运行时想让黑匣子保留,不要一运行完就关闭的方法:

  • 在头文件部分加上 #include "stdlib.h",main函数里最后写上system("pause");
  • main函数里最后写上getchar();

 

11. int 整除问题

  • h=10*t*t/2  运行正确
  • 1/2*10*t*t   始终为0        (1/2整除为0)

 

12. 在程序运行时,输入的多个数据之间必须有间隔,可以用一个或多个空格作为间隔,也可以用回车或者tab作为间隔。

 

13. printf("%d%6.1f", x, y)

6指的是输出x共占6位(包括空格,小数点),1表示一位小数:如x=30 ,y=-1.1输出为30  -1.1(-1.1前面有两个空格);

当总位数不够时,不会截断数字而是直接连接:如printf("%d%1.1f",x ,y),其中x=30 ,y=-3.1输出为30-3.1(-1.1前面有两个空格)

 

14. getchar() 获取一个字符,putchar() 输出一个字符

 

15. break只能跳出最近的一层的循环语句(for,while,do-while)和开关语句(switch),对if-else的条件语句不起作用。

 

16. switch case 表达式为什么不能是double?

原文转载自:https://blog.csdn.net/weixin_36340947/article/details/77920152

1. char、short、int、long、bool 基本类型都可以用于switch语句。

2. float、double都不能用于switch语句。

3. enum类型,即枚举类型可以用于switch语句。

4. 所有类型的对象都不能用于switch语句。

5. 字符串也不能用于switch语句。

6.布尔类型是可以按整数形式转换的。


case标签必须是整型常量表达式

        请记住整型常量这四个字,不满足这个特性的不能作为case值,编译会报错。这也决定了switch的参数必须是整型的。

        整型,意味着浮点数是不合法的,如case 3.14:不可以;常量,意味着变量是不合法的,如case ival: ival不能是变量。

        (1)C++中的const int,注意仅限于C++中的const,C中的const是只读变量,不是常量;

        (2)单个字符,如case 'a': 是合法的,因为文字字符是常量,被转成ASCII码,为整型;

        (3)使用#define定义的整型,#define定义的一般为常量,比如#define pi 3.14,但是也必须是整型才可以;

        (4)使用enum定义的枚举成员。因为枚举成员是const的,且为整型。如果不手动指定枚举值,则默认枚举值为从0开始,依次加

 

17. case后面出现的应该是一个常量表达式,如 case '+' ,而不能是 case op=='+'

 

18. 判断m是否为素数,可直接判断 m是否能被[2, \sqrt{m}]的数整除

 

19. continue语句的作用是跳过循环体continue后面的语句,继续下一次循环。


20. %e 指的是 指数形式

 

21. 斐波那契数列(Fibonacci sequence),指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n - 1)+F(n - 2)(≥ 3,∈ N*)

 

22. 自动变量

函数被调用时,系统自动为其局部变量分配存储单元;一旦函数调用结束,所有分配给局部变量的单元由系统自动回收。

自动变量的定义形式:

auto 类型名 变量名;

eg. auto int x, y;

在自动变量定义时,auto可以省略,其形式与定义的普通变量完全相同。也就是说局部变量就是自动变量。

自动变量如果没有赋初值,其存储单元中将是随机值。

 

23. 变量存储的内存分配

C语言把保存所有变量的数据区分为动态存储区静态存储区

动态存储区: 使用堆栈来管理,适合函数动态分配与回收存储单元。

静态存储区:用于存放全局变量和静态变量。

 

24. 静态变量

在静态存储区中,除了全局变量,还有一种特殊的局部变量——静态局部变量。它不会像普通局部变量那样因为函数调用结束而被系统回收,它的生存周期会持续到程序结束。由于存储单元被保留,一旦含有该静态局部变量的函数被再次调用,则静态局部变量会被重新激活,上一次函数调用后值仍然保存着,可供本次调用继续使用。

定义格式:static 类型名 变量名

如果定义时,没有赋初值,系统自动赋 0。并且赋初值只在函数第一次调用时起作用,以后调用都按前一次调用保留的值使用。这是因为静态局部变量的生存周期始于函数的第一次调用,贯穿于整个程序。当函数第一次调用时,静态局部变量的内存单元得已分配,赋以初值,而函数再次调用时,此静态局部变量的单元已经存在,计算机不会再次为它分配单元,赋初值也不会再发生。但静态局部变量受变量作用范围限制,不能作用于其他函数(包括主函数)。

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    for (int i = 1; i < 6; i++)
    {
        printf("%d\n", factorial(i));
    }
    system("pause");
}


int factorial(int n)
{
    static int f = 1;
    f = f * n;
    return f;
}

结果如下:

 

25. C语言中的数据类型

 

26. 基本数据类型的长度及取值范围

 

27. C语言表示八进制首位数字必须为0,十六进制首位数字前必须有前缀 0x 或者 0X

 

28. 后缀 l 或者 L 表示 long 型常量,如:-12L。后缀 u 或者 U 表示 unsigned 型常量,如:12u。后缀 l 和 u 或者 L 和 U 表示 unsigned long 型常量,如:429LU。

 

29. C语言中的字符

C语言中的字符具有数值特征,不但可以写成字符常量的形式,还可以用相应的ASCII码表示,即可以用整数来表示字符。如:设ch是字符变量,则 ch = 'A' 和 ch = 65 等价。字符可以像整数一样参加运算,此时相当于对字符的ASCII码进行运算。

 

30. 转义字符

\\反斜杠
\'单引号
\''双引号
\ddd1-3位八进制整数所代表的字符
\xhh1-2位十六进制整数所代表的字符

 

31. 实型常量的科学计数法:

实数由正负号、数字、字母e或者E组成,e之前要有数据,e之后的指数只能是整数。如:6.02E-27

 

32. 整型数据的输入输出

 

33. 大小写字母转换

小写转大写:ch_upper = ch_lower - 'a' + 'A';

大写转小写:ch_lower = ch_upper - 'A' + 'a';

 

34. 数据类型自动转换规则

 

35. 强制类型转换是运算符,不是函数,故 (int)x 不能写成 int(x)。

 

36. 位运算符

 

37. 位逻辑运算符的运算规则

先将两个操作数划位二进制数,然后按位运算

 

38. 数组名是一个地址常量,不允许修改。且数组长度必须是常量,不能是变量。

 

39. C语言获取数组长度 sizeof()

int data[4];
int length;
length = sizeof(data)/sizeof(data[0]); 

 

40. 二维数组初始化时,如果对全部元素都赋了值,或分行赋初值时,在初值表中列出了全部行,就可以省略行长度

int a[][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};

等价于

int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};

但不建议省略行长度。

 

50. 二维矩阵副对角线下标规律:i + j = N-1

 

51. 指针

又名“指针变量”,专门用来存放变量地址的变量。如果一个指针变量的值是另一个变量的地址,则称该指针指向那个变量。&称为地址运算符,如:scanf("%d", &n); 把输入的值存储到变量n所在的内存单元里。&n 表示变量n的内存地址或存储位置。定义指针变量的一般形式:

类型名 *指针变量名;

注意指针变量的类型不是指针变量本身的类型,而是指它所指向的变量的数据类型。

*p 为指针申明符,但指针申明并不是指针的组成部分。如,定义int *p; 说明p是指针变量,而不是*p。

 

52. int *p 和 int* p

int *p:C语言的写法。这表示 *p是一个int ,这种风格强调的是语法。

int* p:C++的写法。表示 p是一个指向int的指针,p的类型是int*,这种风格强调的是类型。

 

53. 把特殊0和NULL赋值给指针

int *p;
p = 0;
p = NULL;

第二、三条语句等价,常量NULL在系统文件stdio.h中被定义,其值为0,将他赋值给指针时代表空指针。C语言的空指针不指向任何单元。

注意:不能用数值作为指针变量的初值。eg:int *p = 1000  (x)

 

54. 指针的基本运算

&:取地址运算符。&用于给出变量的地址

*:间接访问运算符。用于访问指针所指向的变量。

 

55. (*p)++ 和 p++

(*p)++、 *p = *p + 1、 ++*p:p 所指变量+1

p++:p所指的内存单元的下一个

*p++、*(p++):先取*p的值作为表达式的值,再将指针p的值+1,运算后,p不再指向变量a。

 

56. 在指针变量定义或者初始化时变量名前面的“ * ”之变时该变量是个指针变量,它既不是乘法运算符也不是间接访问符。

eg:

int a;
int *p = &a;

 

57. 引用调用

调用函数不能改变实参指针的值,但可以改变指针所指向变量的值。

 

58. 指针名&数组名

指针名和数组名都代表内存地址。

指针名是一个变量,而数组名是一个常量。

指针名所代表的地址是可以改变的,而数组一旦被定义后内存空间就被分配,也就是说数组名所代表的地址是不能改变的。

 

59. *(a+i) = a[i]

 

60. 若 p 是指针,则 p+1 代表访问该类型的下一个变量的内存地址。

 

61. 在函数定义中,数组的形参 a 实际上是一个指针。当进行参数传递时,主函数传递的是数组 a 的基地址,数组元素本身不被复制。作为一种表示习惯,编译器允许在作为参数声明的指针中使用数组方括号。

 

62. 字符串常量和字符指针

系统在存储一个字符串常量时先给定一个起始地址,该起始地址代表了存放字符串常量首字符的存储单元的地址,称为字符串常量的值。也就是说,字符串常量实质上就是一个指向该字符串首字符的指针常量。eg:字符串“hello”的值是一个地址,从它指定的存储单元开始连续存放该字符串的6个字符。

如果定义一个字符指针接受字符串常量,该指针就指向字符串的首字母。这样,字符数组和字符指针都可以用来处理字符串。

eg:

char sa[] = "array";
char *p = "point";         //字符指针

printf("%s", sa);
printf("%s", p);

调用printf()函数,以%s的格式输出字符串,作为输出参数,数组名sa,指针p和字符串“string”的值都是地址,从该地址所指定的单元开始连续输出其中的内容,直至遇到‘\0'为止。

 

63. 数组名是常量不能对其赋值。

char sa[] = "Test";
sa = "Hello";            //错误!!!

 

64. 定义字符指针后,如果没有对它赋值,指针的值是不确定的,不能明确它指向的内存单元。因此,如果引用未赋值的指针,可能会出现难以预料的结果。

eg:

char *s;
scanf("%s", &s);        //错误!

为了避免引用未赋值的指针所造成的危害,在定义指针时,可先将它的初值置为NULL。

eg:char *s = NULL;

 

65. 字符串的输入输出

用 gets() 来输入字符,用 puts() 来输出字符。它们在系统文件 stdio.h 中定义。

scanf() 和 gets() 用于字符串的输入时,参数只能是字符型数组名。

scanf() 遇到回车或者空格输入结束;gets() 遇到回车输入结束,用 gets() 函数输入的字符允许带空格。

puts() 函数输出字符后会自动换行。

 

66. char * strcpy(char *s1, char *s2)

将字符串s2复制到s1,函数返回s1.

s1 必须是字符串数组基地址,s2 可以是字符串数组名或者字符串常量。

 

67. strcat(s1, s2):字符串连接函数

将字符串s2连接到s1后,函数返回s1.

s1 必须是字符串数组基地址,s2 可以是字符串数组名或者字符串常量。

注意:C语言不允许使用 “+” 直接将两个字符串数组连接。

 

68. strcmp(s1, s2):字符串比较函数

s1, s2 可以是字符串数组名或者字符串常量。

函数返回一个整数(s1==s2,0;s1<s2,负数;s1>s2,正数)

字符串比较规则:

1. 从两个字符串的首字符开始比较,依次比较相对应的字符(比较ASCII码),直到结束或遇到不相同的字符为止

2. 若两个字符不相同,则用第一个不同的字符相减,差为正,则s1 > s2;差为负,则s1 < s2

 

69. strlen(s1):求字符串长度

由于字符串并没有显示地给出有效字符的个数,所以可以通过strlen(s)函数给出有效字符的个数,或者用一下代码:

#include<stdio.h>
int main(void)
{
	char p[10] = "Happy";
	int i = 0;
	for (i = 0; p[i] != '\0'; i++);
	printf("%d", i);
}

注意上述函数使用前要引入string.h头文件

 

70. malloc() 和 calloc() 

eg:p = (int *)calloc(n, sizeof(int))         p = (int *)malloc(n * sizeof(int))

动态内存申请得到的是一个没有名字、只有首地址的连续存储空间,相当于一个无名的一维数组。

 

引用:https://zhidao.baidu.com/question/40468782.html

malloc和calloc函数在参数个数、初始化内存空间、函数返回值上有区别:

1、参数个数上的区别:

malloc函数:malloc(size_t size)函数有一个参数,即要分配的内存空间的大小。

calloc函数:calloc(size_t numElements,size_t sizeOfElement)有两个参数,分别为元素的数目和每个元素的大小,这两个参数的乘积就是要分配的内存空间的大小。

 

2、初始化内存空间上的区别:

malloc函数:不能初始化所分配的内存空间,在动态分配完内存后,里边数据是随机的垃圾数据。

calloc函数:能初始化所分配的内存空间,在动态分配完内存后,自动初始化该内存空间为零。

 

 

3、函数返回值上的区别:

malloc函数:函数返回值是一个对象。

calloc函数:函数返回值是一个数组。

 

71. free() 动态存储释放函数

void free(void *p)

 

72. realloc() 分配调整函数

void *realloc(void *p, unsigned size)

更改以前的存储分配,并保证原来p指向的存储块内容不变,若分配失败,返回NULL。如果新分配的 size 比原来的小,则内容为原块前size范围内的数据。如果分配成功,原存储块的内容就可能改变了,因此不允许再通过p去使用它。

因为使用realloc(),数据发生了移动,那么所记录的原来的内存地址p所指向的内存空间实际上已经放回到堆上了,这样就会产生p指针的指针悬挂,即指针指向了一块没有分配给用户使用的内存,如果再用p指针进行操作就可能发生意想不到的问题。

可以这样避免:p = (char *)realloc(p, 256);

 

73. 关键字 struct 和结构名一起组成一个新的数据类型名

 

74. 结构变量的混合定义

struct point{
    double x;
    double y;
}s1, s2;

其中s1,s2是结构变量,该段代码的定义方式相当于

struct point{
    double x;
    double y;
};

struct point s1;
struct point s2;

 

75. 结构变量的无类型名定义

指的是在定义结构变量时省略结构名。

struct{
    double x;
    double y;
}s1, s2;

由于没有给出结构名,在此定义语句后面无法再定义这个类型的其他结构变量。也就是说除了s1,s2,不能再定义别的变量了,除非把定义过程重新再写一遍。

 

76. 如果两个结构变量具有相同的类型,则允许将一个结构变量直接赋值给另一个结构变量。

eg: s1 = s2;

赋值时,相当于将赋值符号右边结构变量的每一个成员的值都赋值给了左边结构变量中相应的成员。

 

77. 结构指针:指向结构变量的指针

结构指针的值实际上是结构变量的首地址,即第一个成员的地址。

可通过结构指针变量p间接访问它所指向的结构变量中的各个成员。

struct point{
    double x;
    double y;
};

struct point s1 = {100, 100};

struct point *p;

p = &s1;

//两种通过结构指针访问结构变量成员的方式
(*p).x = 120;
p->x = 120;

->指向运算符:访问指针指向的结构成员。

若函数参数为结构变量时,在参数传递时,实际上是把实参结构中的每一个成员值传递给形参结构的成员。而当构成员数量众多(如结构数组形式)时,使用结构指针作为函数参数只要传递一个地址值,因此能够极大的提高参数传递的效率。

 

78. 宏定义 #define

又称宏替换,格式:#define 宏名 宏定义字符串

eg:#define PI 3.14

  • 用宏来定义一些符号常量,可以方便程序的编制。
  • define 前面以 # 开始,表示它在编译预处理中起作用,而不是真正的C语句,行尾不需要跟分号。如果跟了分号,编译预处理时会把分号也作为替换内容。
  • 宏名常采用大写字母串作为宏名。
  • 宏定义字符串可以是任意字符,中间可以有空格,以回车符作为结束。
  • #define 最后跟的 “\” 表示该行未结束,与下一行结合起来成为完整的一行。
  • 宏还可以实现简单的函数功能。eg:#define MAX(a, b)  a>b?a:b     宏引用形式与函数调用非常相似,但两者实现过程完全不同。宏替换在程序编译预处理时完成,对于MAX(a, b) 的编译预处理,首先用变量名x, y分别替换a、b,然后再用包含x、y的条件表达式替换MAX(x, y) 。编译结束后,程序中MAX(x, y) 便消失,变为x>y?x:y

 

79. 编译预处理

C程序的编译处理用于把每一条C语句用若干机器指令来实现,生成目标程序。由于#define等编译预处理指令不是C语句,不能被编译程序翻译,需要在真正编译之前做一个预处理,解释完编译预处理指令,从而把预处理指令转换成相应的C程序段,最终成为由纯粹的C语句构成的程序,经编译最后的得到目标代码。

 

80. 文件模块间的通讯

  • 外部变量

如果程序中包含多个程序文件模块,既可以通过外部变量的声明,是全局变量的作用范围扩展到其他文件模块;也可以通过定义静态全局变量,将其作用范围仅限制在一个文件模块中。

全局变量只能在某个模块中定义一次,如果其他模块要使用该全局变量,需要通过外部变量的声明,当程序连接时会统一指向全局变量定义的模块。

外部变量的声明格式:extern 变量名;

它只起说明作用,不分配存储单元,对应的存储单元在全局变量定义时分配。

 

  • 静态全局变量

如果整个程序只有一个文件模块,静态全局变量与一般的全局变量作用完全相同。当程序由多个文件模块构成时,静态全局变量有特殊作用,用于限制全局变量域的扩展。

C语言的静态全局变量可以把变量的作用仅限于当前文件模块,即使其他文件模块使用外部变量声明,也不能使用该变量。

 

  • 函数与程序文件模块

如果一个程序包含多个文件模块,要实现在一个模块中调用另一个模块中的函数时,就需要对函数进行外部声明。

格式:extern 函数类型 函数名(参数);

一般情况下,关键字extern可以省略。编译程序如果在当前模块文件中找不到函数定义体,自动认为该函数是外部函数。

 

为了避免个文件模块间函数的互相干扰,C语言也允许把函数定义成静态的,以便把函数的适用范围限制在文件模块内,即使其他文件模块有同名的函数定义,相互之间也没有任何关联,增加了模块的独立性。

定义格式:static 函数类型 函数名(参数);

 

81. 指针数组

指针数组的各个元素都是指针类型,用于存放内存地址。

格式:类型名 *数组名[数组长度]

eg: char *color[5];

其中color[i]中存放的是字符串的首地址

printf("%s", color[i]);    //输出color[i]所指向的字符串

printf("%x", color[i]);    //输出color[i]所指向的字符串的首地址

 

82. 二级指针——指向指针的指针

定义格式:类型名 **变量名;

int a = 10;
int *p = &a;
int **p = &p;

char *color[] = {"red", "yello", "blue"};

数组名color的类型就是二级指针(char**),它代表了数组首元素color[0]的地址。

*(color+k)和color[k]等价。

注意color[0]和*(color[0])是不一样的。color[0]是字符指针,指向字符串"red"。*(color[0])代表该字符串的首字母,即'r'。

 

83. 命令行参数

C语言主函数main()可以有两个参数用于接收命令行参数。

//test.c

int main(int argc, char *argv[])
{
    int k;
    for(k = 1; k < argc; k++)
    {
        printf("%s\n", argv[k]);
    }
}

第一个参数是指命令行参数的个数(包括命令);第二个参数用于接收命令行参数。

eg: 一个test.c编译好后的文件为test,用于输出键入的命令行参数

test Hello World

argc = 3  (包括test命令),argv[0]指向命令test,argv[1]指向第一个命令行参数Hello。

结果输出:Hello World

 

84. 函数指针

接收函数的入口地址的指针,指向函数。

定义格式:类型名 (*变量名)( 参数类型表 )

int (*funptr)(int,int);
funptr = fun;       //fun(x, y)已定义好,将函数fun()的入口地址赋给funptr,funptr就指向函数fun()

fun(3, 5);
(*funptr)(3, 5);

在使用函数指针前,要先对它赋值。赋值时,将一个函数名赋值给函数指针,但该函数必须已定义或声明,且函数返回类型和函数指针的类型要一致。

函数调用中, 函数名或已复制的函数指针也能作为实参,此时,形参就是函数指针,它指向实参所代表函数的入口地址。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

int main(void)
{
	double calc(double (*funptr)(double), double a, double b);
	double f1(double x);
	double f2(double x);


	double result;
	double (*funptr)(double);

	result = calc(f1, 0, 1);
	printf("f1 result = %f\n", result);

	funptr = f2;
	result = calc(funptr, 0, 2);
	printf("f2 result = %f\n", result);

	return 0;
}

double f1(double x)
{
	return x * x;
}

double f2(double x)
{
	return x * x * x;
}

double calc(double (*funptr)(double), double x1, double x2)
{
	return funptr(x2) - funptr(x1);
}

 

85. 缓冲文件系统工作原理

 

86. 自定义类型 typedef

自定义类型不是用来定义一些新的数据类型,而是将C语言中的已有类型(包括一定义过的自定义类型)重新命名,用新的名称代替已有数据类型。

一般形式:typedef 已有类型名 新类型名;

eg:typedef int INTEGER;

则 int i; 等价于 INTEGER i;

一般要求重新定i的类型名用大写。

 

87. 文件指针

文件指针是特殊指针,指向的是文件类型结构,他是多项信息的综合体。FILE结构中有一个curp成员,通过 fp->curp 可以指示文件缓冲区中数据存取的位置。C程序只使用文件指针fp,用fp代表文件整体。

文件指针不像以前普通指针那样能进行 fp++ 或 *fp等操作,fp++将意味着指向下一个FILE结构(如果存在的话)。

文件操作具有顺序性的特点,前一个数据取出后,下一次将顺序取出后一个数据,fp->curp会发生变化,但改变是隐含在文件读写操作中的,而不需要在编程时写上 fp->curp++ ,类似这样的操作酱油操作系统在文件读写时自动完成。

 

88. 文件控制块FCB、文件指针和文件结构的关系

 

89. 打开文件

fopen("文件名", "打开方式")

注意:定位子目录时,用的“\”需要用"\\"去表示。

打开文件时,即是请求系统分配文件缓冲区。

执行fopen()操作,系统完成以下工作:

  • 在磁盘中找到文件
  • 在内存中分配保存一个FILE类型结构的单元(16B)
  • 在内存中分配文件缓冲区单元(512B)
  • 返回FILE结构地址(回送给 fp)

文件打开的实质是把磁盘文件与文件缓冲区对应起来,这样后面操作至于要用到文件指针即可。

exit(0)是系统标准函数,作用是关闭所有打开的文件,并终止程序的执行。

 

90. 文件关闭

fclose(文件指针);

该函数返回一个整数,若为0,则代表正常关闭文件。

关闭文件操作处理强制把缓冲区中的数据写入磁盘外,还将释放文件缓冲区单元和FILE结构,使文件指针与具体文件脱钩。

 

91. 文件的读写操作

  • 字符方式文件读写 fgetc() 和 fputc()

        存取数据均为ASCII码字符文本,使用这两个函数读写文件时,逐个字符地进行文件读写。

        ch = fget(fp);             //每次调用成功,fp会自动后移一个位置,方便读取下一个字符。用 feof() 判断fp 是否指到了文件末尾

        fputc(ch,fp);              //函数返回值若写成功为ch,若写文件失败为EOF(符号常量,表示为-1)

while(!feof(fp1))
{
    ch = fgetc(fp1);
    if(ch!=EOF) fputc(ch, fp2);
}

 

  • 字符串方式文件读写 fgets() 和 fputs()

        fputs(s, fp);                //s是要写入的字符串,可以是字符数组名,字符型指针变量或字符串常量。若执行成功,返回最后一个字符,若不成功,返回EOF。

        fgets(s,n,fp);             //s可以是字符数组名或字符指针。n是指定读入的字符个数,最多读入n-1个字符,在读取字符后自动添加一个'\0'

 

  • 格式化方式文件读写 fscanf() 和 fprintf()

        fscanf(fp, "%d%f", &n, &x);

        fprintf(fp, "%d%f", n, x);

 

  • 数据块方式文件读写 fread() 和 fwrite()

        多用于读写数据块(指定字节数),多用于二进制文件。

        fread(buffer, size, count, fp);

        fwrite(buffer, size, count, fp);

        buffer是一个指针,指的是存放输入/输出数据的首地址,size指的是数据块的字节数,count表示要读写的数据块数。

        eg:fread(fa, 4, 5, fp);         //从fp所指的文件中,每次读4个字节,连续读5次,送入数组fa中。

 

92. 其他文件操作函数

  • rewind() 重定位文件首函数,使其指向文件首地址。rewind(fp);
  • fseek() 指针移动控制函数。fseek(fp, offset, from);    //offset表示移动偏移量,应是long型数据,使用常量时,应加上后缀“L”;offset可为负值,表示向前偏移。from可取3种值:0(文件首部),1(当前位置),2(文件尾部)
  • ftell() 获取文件当前位置函数,即相对于文件开头的位移量(字节数)
  • feof() 文件末尾检测函数。
  • ferror() 读写错误检查函数。用来检查文件在用各种输入输出函数进行读写时是否出错,若返回0,表示未出错。
  • clearerr() 出错标记清除函数。用来清除出错标志和文件结束标志,使它们值为0.
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值