C语言-基础
创始人
2024-01-31 15:52:58
0

C-基础

  • 参考
  • 变量/常量
    • 左值/右值???
    • 字面量/常量
    • 变量作用域
      • 全局变量与局部变量
      • 作用域扩展 python
  • 数据与地址
  • 存储类
    • auto
    • register
    • static
    • extern
  • 数据类型
    • 基本类型
      • 整数类型
        • 进制数
        • 原码/补码/反码
          • int 与 char
        • 数值溢出
      • 浮点类型
      • 字符型
        • 字符与整数
        • 字符与进制数/字符型进制数
        • putchar/getchar
        • 转义字符
        • 中文字符
        • 宽/窄字符(串)
      • 字符串型
        • puts/gets
      • sizeof
      • 数据类型转换
        • 整型与字符型运算
      • 基本运算
        • +-*/
        • / %
        • ++/- -
        • ++num/num++
        • 逻辑运算
        • 位运算
        • ? :
        • 关系运算符
        • 赋值运算
        • 运算优先级
    • void 类型
    • printf
      • %
      • 转义字符与特殊字符
      • prinf与缓冲区
      • printf 字符串
      • printf/puts
    • scanf
      • scanf 字符串
        • scanf/gets
    • 位运算
      • &
      • |
      • ^
      • ~
      • 大小端
      • <<
      • >>
  • 控制方法
    • if-else
    • switch-case
    • while
    • for
    • do-while
  • 文件操作
    • 文本和二进制
      • 换行符
      • 位置指针/EOF
    • `fopen`/`fclose`
      • fgetc/fputc
      • fgets/fputs
      • fread/fwrite
      • fprintf/fscanf -- 有问题
      • 文件复制
      • ftell
      • exit

参考

https://www.runoob.com/cprogramming/c-tutorial.html

变量/常量

对于不带初始化的定义:带有静态存储持续时间的变量会被隐式初始化为NULL(所有字节的值都是0),其他所有变量的初始值是未定义的
需要建立存储空间的变量变量在声明的时候就已经建立了存储空间
无需建立存储空间:通过extern关键字声明变量名,而不定义他,这种可以在别的文件中定义

变量定义就是告诉编译器在何处创建变量的存储,以及如何创建变量的存储
声明与定义???
extern int i 是声明,不是定义
int a 是声明,也是定义

左值/右值???

左值:指向内存位置的表达式, 叫做左值表达式
右值:内存中某些地址的数值

字面量/常量

字面量:常量 – 不允许进行修改
整型常量、浮点常量、字符常量、字符字面值、枚举常量、定义常量

定义常量

  • #define 预处理器
  • const 关键字
// #define
#define Variable value // 注意没有分号 可以定义字符型、字符串型的常量// const
const type variable=value; // 注意有分号,且必须直接赋值

变量作用域

main函数也是函数,main函数中定义的变量也是局部变量

  • 在函数或块内部的局部变量

在某个函数或块内部声明的变量称为局部变量,只能被函数或该代码块内部的语句使用

  • 在所有函数外部的全局变量

全局变量在整个声明周期内都是有效的,在任意的函数内部都能访问全局变量

  • 形参

被当做函数内的局部变量

命名冲突

局部作用域内,优先使用局部变量

全局变量与局部变量

全局变量:保存在内存的全局存储区中,占用静态的存储单元
局部变量:保存在栈中,只有在所在函数被调用时才动态的为变量分配存储单元

初始化局部变量和全局变量

局部变量被定义时,系统不会对其初始化(或随机初始化,根据编译器的不同策略不同),必须手动对其初始化
全局变量被定义时,系统会自动对其初始化,默认是0,(因为全局变量存储在内存分区中的全局数据区,这个区域中的数据在程序载入内存后会初始化为0)
在函数内部修改全局变量会影响其他函数,

int 0char-\0float 0double 0pointer NULL

未初始化的变量会导致一些在内存位置中已经可用的垃圾值

作用域扩展 python

a=1
b=2
c=4
def f():print(c)c=a+b
f()
print(c)
# c为局部变量,会报错!!!

数据与地址

数据以二进制的形式保存在内存中,字节是最小的可操作单位
在内存管理中,为每个字节分配了一个编号,使用该字节时,只要知道编号就可以,这个编号,就是地址

获取地址

&data,(data可以是数值、字符)

存储类

存储类:定义c程序中变量/函数的范围(可见性)和声明周期
说明符,放在所修饰类型的类型之前

  • auto
  • register
  • static
  • extern

auto

所有局部变量的存储类,只修饰局部变量,只用在函数内

int func()
{// 下面两种写法都表示的是局部变量int mount;auto int month;
}

register

定义存储在寄存器中而不是RAM中的局部变量,意味着变量的最大只存等于寄存器的大小(一个字节),且不能也对它应用一元运算符???
寄存器只用于需要快速访问的变量,如计数器等(定义了register,并不意味着变量将被存储在寄存器中,只是意味着变量可能存储在寄存器中,这取决于硬件和实现的限制)

int func()
{register int miles;
}

static

https://www.runoob.com/w3cnote/cpp-static-usage.html – 还没看

指示 编译器 在 程序 的生命周期内 保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁,因此使用static修饰局部变量可以在函数调用之间保持局部变量的值
static也可以修饰全局变量,当修饰全局变量的时候,会是变量的作用域限制在声明它的文件中。全局声明的一个static变量或方法可以被任何函数或方法调用,只是必须与被修改的变量或方法在同一个文件中

static var 表示var的作用域为当前的文件,其他文件无效

int func()
{// num 是局部变量,但是只被初始化一次,每次调用函数func的时候,num不会被重置static int num=10num--;
}

extern

提供一个全局变量的引用,全局变量对所有程序文件都是可见的
使用extern无法初始化变量,会把变量名指向一个之前定义过的存储位置
其实就是 A文件中定义了一个可以在B文件中使用的全局变量或函数,那么在B文件中就可以使用extern来得到A文件中定义的变量或函数的引用(用在在另一个文件中声明一个全局变量或函数)
进阶:A/B文件可以存在相互的使用extern

// A.c
#include 
int count;
extern void write_extern();int main()
{count=5;write_extern();
}
// B.c
#include 
extern int count;
void write_extern(void)
{printf("count is %d\n",count)
}

数据类型

  • 基本类型
  • 枚举类型

只能被赋值一定的离散整数值变量

  • void类型

类型说明符,表明没有可用的值

  • 派生类型

指针类型、数组类型、结构类型、共用体类型和函数类型
其中:函数类型指的是函数返回值的类型

基本类型

整数类型

  • char

1个字节,[-128,127] 或[0,255]

  • unsigned char

1个字节,[0,255]

  • int

2或4字节,(win 4字节)

  • unsigned int

2或4字节

  • short/unsigned short

2字节

  • long/unsigned long

4字节

  • double

8字节

前缀:表示进制关系
后缀:表示有符号(默认)和无符号整型U、长整型L,大小写任意,顺序任意

有符号和无符号

当以有符号数的形式输出时,printf会读取数字所占用的内存,并把最高位作为符号位,把剩下的内存作为数值位,但是对于有符号的正数而言,最高位恰好是0,所以可以按照无符号数的形式读取,且不会有任何的数值影响
当以无符号的形式输出时,printf也会读取数字所占用的内存,并把所有的内存都作为数值位对待

进制数

0b 0B # 二进制数 
0x 0X # 十六进制数
0 #八进制

注意标准编译器不支持0b的二进制写法,只是某些编译器在扩展后支持
注意printf 输出形式

整型只控制字节长度,和数值范围
进制数才是实际数值的表现形式
一个数字不管以何种进制来表示,都可以 以任意进制的形式输出,因为数字在内存中始终以二进制的形式存储
其他进制的数字在存储前都必须转换成二进制形式,而在输出前也需要反转

原码/补码/反码

原码:数值的二进制数,包括符号位
反码:

正数的反码=原码
负数的犯法=符号位不动,其他位置取反

补码:

正数的补码=原码
负数的补码:是反码加1

-128的补码就是1000 0000
补码 1000 0000 就表示-128 记录就可以了
深究里边,是因为符号位会被数值的高位进行多次覆盖

计算机内存中,整型一律采用补码的形式存储,因此读取整数时还要采取逆向的转换,也就是将补码转换为原码

int 与 char

https://blog.csdn.net/u012782268/article/details/40021887

数值溢出

浮点类型

  • float

4字节,32位

  • double

8字节,64位
对于小数默认是double类型

  • long double

16字节

float x=1.2 # 赋值的时候,会先从double类型转换为float类型# 后缀
float x=1.2f # 赋值的时候直接是默认的float类型

注意所有的浮点型都是以双精度double进行运算的,即使是float类型,也要先转换成double类型

定义了宏,可以在程序中使用这些值和其他有关实数二进制表示是的细节

#include FLT_MIN # 最大值
FLT_MAX # 最小值
FLT_DIG # 精度值

字符型

单引号
charunsigned char 是一个字符类型,用来存放字符,但是同时也是一个整数类型,也可以用来存放整数!!!,注意取值范围
char 1个字节,[-128,127]
unsigned char 1个字节,[0,255]
char 类型只能存储ASCII字符,不能存储其他字符根据上面的定义,也可以存放范围以内的进制数

字符与整数

由于char类型只能存储ASCII字符,字符集及其编码其实本质上就是二进制数,(本质上与整型没有区别)
定义一个char类型字符,会先转换成ASCII字符对应的编码再存储
而存储一个整型的时候,不需要任何转换直接存储
由于数据类型不同,所以需要的字节位数不同,因此在存储和读取的时候占用的内存不一样,所以在读取 字符型和整型 的时候并不会有冲突
字符和整型可以互相赋值

char a=10;
int b='a';

字符与进制数/字符型进制数

字符型与进制数

由于char可以存放整型,所以可以声明和定义取值范围内的进制数
下面的例子中,就可以把char想象成整型(但是要注意取值范围)

char a=0x32 // 这相当于将整型赋值给一个字符类型
printf("%c",a) // 2
printf("%d",a) // 50 这是因为由十六进制转换为的十进制 // 与python类别
// '2'.encode().hex() # 32
// int('32',16) # 50
// chr(50) # '2'

对于char类型的字符,(由于是窄字符,且只占一个字节,所以可以使用ASCII编码),(又由于ASCII编码的结果就是一个二进制数),可以利用转义的进制数进行表示
下面的例子,就可以把其当成字节对象(字节串对象),想当于python中的bytes对象,

char a='\x31' // a是字符数值1
char b='\x61' // b是字符achar *str1="\x31\x32\x33\x61\x62\x63" // 字符串"123abc"// 类别python
// '123abc'.encode().hex() # '313233616263'

putchar/getchar

putchar输出字符(只能输出单个字符)
getchar接收字符

char a=getchar();

转义字符

printf("\"string\'") // "string'

中文字符

对于中文字符应该使用宽字符的形式,并加上前缀,加上前缀后,所有的字符都变成了宽字符的存储形式
wchar_t类型,在不同的编译器下对不同的语言使用不同的长度

#include 
wchar_t a=L'中'

宽/窄字符(串)

多字节字符,也叫做窄字符变长字节存储方式
宽字符固定字节存储方式

char类型的窄字符,使用ASCII编码
char类型的窄字符串,通常来讲是UTF8编码,(其实不同的编译器在不同的平台上编码方式不同)
wchar_t类型的宽字符或宽字符串,使用UTF16或32编码

见文档

#include 
wchar_t a=L'a'; // 要加一个L进行标注// 下面两个用于输出宽字符
putwchar(a);
wprintf(a);

字符串型

双引号
在内存中占一块连续的内存
其实字符串数据,依靠的是数组和指针来简介的存储字符串

char s1[]="string1";
char *s2="string2"

char s1[]="string"

这种方法定义的字符串所在的内存既有读取权限又有写入权限(可变),可以用于输入与输出函数
[]可以指明字符串的长度,如果不致命则根据字符串自动推算
声明字符串的时候,如果没有初始化,(由于无法自动推算长度,只能手动指定)char s[10]

char *s1="string"

这种方法定义的字符串所在的内存只有读取权限,没有写入权限(不可变),只能用于输出函数

puts/gets

puts输出字符串
gets接收字符串,与scanf的区别见下

char s[10];
gets(s)

sizeof

获得当前平台上的对象或类型的存储字节大小

printf("%lu",sizeof(int))
printf("%d",sizeof(instance))

数据类型转换

数据类型存在强制转换
原则

浮点数赋给整型:浮点数小数部分会被舍去(注意不是四舍五入)
整数赋值给浮点数,数值不变,但是会被存储到相应的浮点型变量中

在这里插入图片描述

强制转换

注意,强制转换是临时性的,并不会影响数值本身的数据类型和值

(类型说明符)(表达式)
(int)(x+y)

整型与字符型运算

int a=10;
char b='a';
printf("%c\n",b+a); // 'k'
printf("%d\n",b+a); // 107

基本运算

±*/

下面的例子中 由于都是int类型,所以即使是算出了float值,也会变成int类型,只不过在printf变成了对应的格式
因此必须在先前就想好结果类型

int a=1;
int b=2;
float c;
c=a/b;
printf("%f",c); // 0.000000

/ %

%取余运算,只能作用于整型,不能作用于浮点型

注意:正负数,只根据%左边的数值符号决定!!!

++/- -

  • ++ 自增
  • -- 自减
num++; // 先运算后+1
num--; // 先运算后+1//例子
v=num++; // v=num;num+=1

++num/num++

num++; // 先运算后+1
++num; // 先+1后运算

逻辑运算

逻辑运算符的结果 是 0 1
并不是bool类型

  • &&and
  • ||or
  • !not

注:与python并不一样,python在逻辑运算上,对数值和bool类型的计算结果不一样

位运算

  • &
  • |
  • ^ 异或
  • ~ 取反
  • << 左移
  • >> 右移

? :

如果条件为真?则值为x:否则值为y
优先级:算术运算符>关系运算符>?:
结合性:从右到左

关系运算符

关系运算符的结果 是 0 1
并不是bool类型

赋值运算

注意,连续赋值应保证等号左边的变量、右边为赋值,并且变量已经了存储空间
定义时,连续赋值违反规定

// 下面是错误的!!!
// 赋值具有右结合性,这里1赋值给c,c赋值给b,b再赋值给a
// 但是这里相当于 b,c没有定义就赋值了,所以是错误的!!!
int a=b=c=1;// 下面是正确的
int a,b,c;
a=b=c=1;

运算优先级

注意结合性
同级别具有左结合性
具有右结合性的运算:单目运算符、赋值运算符(单目赋值和双目赋值)、三目运算符
! 大于 算数运算符 大于 关系运算符 大于 逻辑运算符中的&& 和 || 大于 赋值运算符

void 类型

函数返回为空
函数参数为空,不接受任何参数,int main(void)
指针指向void:类型为void*的指针 代表对象的地址,而不是类型

printf

https://www.runoob.com/cprogramming/c-function-printf.html – 没看完
http://c.biancheng.net/view/1793.html?from=pdf_website_1_0 – 没看

%

输出格式
%[flag][width][.percision]type
width 控制输出宽度,数值不足宽度,空格补齐;数值或字符超过宽度,width不再起作用,按照数据本身宽度来输出;(例如%12f默认保留6位小数,要输出12个字符宽度);width可以用于数值、字符、字符串
.precision 控制输出精度,小数位数大于precision,按照四舍五入输出;当小数位数不足precision后面补0
.precsion 与width不同,作用于整型的时候,不足宽度在左侧补0(作用于浮点数只控制小数位数);对于控制字符串输出,字符串长度大于.precision则被截断
总结,width要么补齐空格,要么不起作用;.precision对整型左侧补0或不起作用,对于浮点小数位补0或四舍五入,对于字符串被截断或不起作用

%d //十进制有符号整数
%u //十进制无符号整数
%f //float浮点数,默认保留六位小数,不足六位以0补齐,超过六位按四舍五入截断
%lf //double
%c //字符
%s //字符串
%p //指针的值
%e //指数形式的值
%x //十六进制 无符号%lu //32位无符号整数
...// printf的高级写法,用于区分不同的进制数字
print("a=%#hx",0x1d)

整型、短整型、长整型,分别有对应的printf输出形式
printf中不能输出二进制数
需要某些转换函数

一个数字不管以何种进制来表示,都可以 以任意进制的形式输出,因为数字在内存中始终以二进制的形式存储
其他进制的数字在存储前都必须转换成二进制形式,而在输出前也需要反转

在这里插入图片描述

注意事项

有符号和无符号
当以有符号数的形式输出时,printf会读取数字所占用的内存,并把最高位作为符号位,把剩下的内存作为数值位,但是对于有符号的正数而言,最高位恰好是0,所以可以按照无符号数的形式读取,且不会有任何的数值影响
当以无符号的形式输出时,printf也会读取数字所占用的内存,并把所有的内存都作为数值位对待
因为通过格式控制符进行数值输出的时候,其实并不会检查定义的数值是有符号还是无符号数,只会按照格式控制符对数值进行特定的解释

转义字符与特殊字符

"\\"%%

prinf与缓冲区

通常来说,printf执行结束后数据并没有直接输出到显示器上,而是放入了缓冲区,**注意:**不同的操作系统,对于printf和缓存机制是不同的

printf 字符串

字符串类型,有两种定义方式,对应在内存中有两种 读取与写入权限
在输出时,要求字符串只需要有读取权限

printf/puts

puts自动换行,printf不是自动换行

scanf

从控制台读取数据
根据下面的例子,scanf会根据地址把读取到的数据写入内存
注意:多输出时的结果,除了空格外,必须严格输入
注意:超额输入的时候,不会出错,相当于位置参数(这是因为缓冲区的存在
从键盘输入的数据并没有直接交给scanf,而是放入了缓冲区中,直到回车,scanf才到缓冲区中读取数据
输入可以不是指定的类型,但是会存在数值转换的风险

int a;
scanf("输入图像",&a)// 多输入
int a,b;
scanf("%d sb %d",&a,&b) // 输入的时候,必须是'1 sb 2',不然会出错// 超额输入
int a,b;
scanf("%d %d",&a,&b) // 输入的时候,必须是'1 2 3',不会出错,只会使用之前的内容// 连续多输入
int a,b;
int c,d;
scanf("%d %d",&a,&b);
printf("%d sb, %d\n",a,b);
scanf("%d %d",&c,&d);
printf("%d sb, %d",c,d);
// 输入的时候,可以是 1 2 3 4 ,也能正确输出 <-- 这是因为缓存区的存在

继续读取或读取失败

int main(){int a,b;int c,d;scanf("%d %d",&a,&b);printf("%d sb, %d\n",a,b);scanf("%d %d",&c,&d);printf("%d sb, %d",c,d);return 0;
}
// 输入 1 2 回车
// prinf()... 然后等待输入
// 输入 3 4 回车
// printf()... 结束//输入 1 2 a10 (第三个是一个不符合要求的数据)
// 直接结束,上下的 c,d 显示的系统默认的初始值int a=1;
int b=2;
scanf("%d %d",&a,&b);
printf("%d sb, %d\n",a,b);
// 输入 1 a10
// 不会出错,b输出的是初始值(和上面的例子一样)

scanf 字符串

字符串类型,有两种定义方式,对应在内存中有两种 读取与写入权限
在读取时,要求字符串有写入权限,因此只能用char s[]="string"这种形式
scanf在读取字符串的时候,在输入时,以空格当做输入结束标志

char s[30];scanf("%s",s) // 这里不需要取地址符&

scanf/gets

getsscanf同样具有缓冲区,区别在于gets以回车作为字符串结束响应,而不是空格。scanf是以空格作为结束响应,所以不能读取包含空格的字符串

位运算

位运算 是根据 内存中的二进制位进行运算的,而不是数据的二进制形式,

&

按位与运算,通常用来对某些位清0,或保留某些位

|

按位或运算可以用来将某些位置1,或保留某些位

^

按位异或可以用来将某些二进制位反转

~

单目运算符,具有右结合性

大小端

数据低位

1234中34就是低位

大端

数据的低位放在内存的高地址上

小端

数据的低位放在内存的低地址上

<<

把各个二进制位全部左移若干位,高位丢弃,低位补0(小端模式下)(这里的高位和低位说的是数据高位和低位)

>>

把各个二进制位全部右移若干位,低位丢弃,高位补0或1小端模式下)(这里的高位和低位说的是数据高位和低位)
如果数据的最高位是0,就补0,;高位是1,就补1

控制方法

if-else

注意,else总是与其前面位置最近的if配对
判断语句中,可以是数值、表达式、赋值表达式、变量等,只要是非0都可以

if (condition)
{...
}
else if (condition)
{...
}
else ()
{...
}//例子
if (a=b) // 把b的值赋值a,如果b为非0,则执行
{//TODO
}

switch-case

switch-expression 必须是一个常量表达式,一个整型(整型表达式)或一个枚举类型,(其实字符常量也可以,因为字符和整型可以相互转换),(也就是说不能包含任何变量,浮点型也不行
expression1/2 必须是与expression类型相同的数据,且必须是常量或字面量(字符也行,可以与整型相互转换
expression 总结

switch后面接的expression 可以是变量表达式(可以包括运算公式),但是必须是整型变量表达式
case 后面接的expression 必须是常量表达式(表达式的结果必须是整型就可以,但不能是变量)(可以包括运算公式)(不能是变量),必须与switch后的expression具有相同的类型
两种表达式不能是浮点型,但是可以是字符型

如果case不加break,控制流会继续后面的case,直到遇到break
当所有的case都不匹配的时候,有一个可选语句default(default不是必须的),default语句中的break不是必须的

swtich(expression)
{case expression1:...break;case expression2:...break;default:...
}

while

while(condition)
{...
}

for

int会首先被执行一次,且只会被执行一次;这一步可以声明并初始化任何循环控制变量,也可以不写任何语句,只有一个分号即可
然后会判断condition,如果为真则执行循环主体,如果为假,则不执行循环主体,且控制流会跳转到紧接着for循环的下一条语句
执行完for循环主体后,控制流会跳回increment,该语句可以留空,只要在条件后有一个分号出现即
条件再次被判断,如果为真,则执行循环,条件变为假的时候,for循环终止

for(int;condition;increment)
{...;
}

do-while

函数体至少会被执行一次

do
{...;
}while(codition);

文件操作

C语言中硬件设备可以看做文件
打开文件–保存到一个FILE类型的结构体变量中;关闭文件就是释放结构体变量

文本和二进制

都是二进制存储的,不过是采用特定的编码方式能够进行读取

换行符

linux : \n程序中的数据会原封不动的写入文本文件
windows: \r\n作为文本文件的换行符

如果以文本方式打开文件,当读取文件时,程序会将文件中所有\r\n转换成一个字符\n(如果文本文件中有连续的两个字符\r\n,则程序会丢弃前面的\r,只读\n
当写入文件时,程序会将\n转换成\r\n写入

位置指针/EOF

文件位置指针,指向当前读写到的位置,也就是读写到第几个字节

  • rewind(fp)

将文件中的位置指针重新定位到文件开头

部分函数再读取出错时也会返回EOF,有些情况下无法判断文件读取结束和是读取出错,feof() ferror()

  • fseek

移动文件指针到任意位置
fseek一般用于二进制文件,在文本文件中由于要进行转换,计算的位置有时会出错
一般搭配fread\fwrite使用

int fseek(FILE* fp,long offset,int origin)
// offset 移动的字节数,offser 为正,向后移动;offset为负时,向前移动
// origin 为起始位置,表示从何处开始计算偏移量
// // 文件开头 0;当前位置 1;文件末尾 2 
  • feof

判断文件内部指针是否指向了文件末尾 feof(FILE *fp)

  • ferror

判断文件操作是否出错 ferror(FILE *fp)

if (ferror(fp))
{puts("出错")
}
else
{puts("读取完毕")
}

fopen/fclose

#include 
FILE *fp=fopen("filename","openmode");// 打开错误就返回一个空指针NULL
FILE *fp;
if (fp=fopen("filename","openmode")==NULL) "ERROR..."// 正常关闭的时候返回值为0,非0表示有错误发生
fclose(fp); 

fgetc/fputc

int fgetc(FILE *fp) // 读取成功时返回读取到的字符,读取到文件末尾或读取失败时返回EOF(EOF在stdio.h中定义的宏,通常是一个负值)
int fputc(FILE *fp)

char ch;
FILE *fp=fopen("filename","filemode");
ch=fgetc(fp)
FILE *fp=NULL;
char ch;if ((fp=fopen("F:\\c-learning\\file.txt","rt"))==NULL)
{puts("failed to open file");exit(0);
}
while ((ch=fgetc(fp))!=EOF)
{putchar(ch);
}
putchar('\n');if (ferror(fp))
{puts("出错")
}
else
{puts("读取完毕")
}fclose(fp);
char ch='a';
fputc(ch,fp);// 知道遇到回车结束
while ((ch=getchar())!='\n')
{fputc(ch,fp);
}

fgets/fputs

读写一个字符串或一个数据块
char* fgets*(char *str,int n,FILE *fp) str为字符数组,读取成功时返回字符数组首地址
int fputs(char *str,FILE *fp) 向指定的文件写入字符串,写入成功返回非负数,失败返回EOF

读取到的字符串会在末尾自动添加\0,n个字符也包括\0。实际值读取到了n-1个字符
在读取n-1个字符之前如果出现了 换行 或者读到了文件末尾,则读取结束。即不管n的值多大,fgets()最多只能读取一行数据,不能跨行
C语言中没有按行读取文件的函数,只能将n设置的足够大,每次读取到一行数据
fgets() 遇到换行符时 会将换行符一起存入到当前字符串 !!!

// 读取100个字符
#define N 101
char str[N];
FILE *fp=fopen("filename","filemode");
fgets(str,N,fp);//例子
int main()
{FILE *fplchar str[N+1];if ((fp=fopen("filename","openmode"))==NULL){puts("failed to open file");exit(0);}while (fgets(str,N,fp)!=NULL){printf("%s\n",str);}fclose(fp);return 0;
}
if ((fp=fopen("F:\\c-learning\\file.txt","at+"))==NULL)
{puts("failed to open file");exit(0);
}
char *str2="hello\nqt\n";
fputs(str2,fp);fclose(fp);

fread/fwrite

以数据块的形式读写文件,
注意,使用fread/fwrite时应该以 二进制 的形式打开
其实就是多个字节数据:一个字节、一个字符串、多行数据等

// 读写成功,返回读写成功的块数count
size_t fread(void* ptr,size_t size,size_t count,FILE *fp) // 读取文件
size_t fwrite(void* ptr,size_t,size,size_t couont FILE *fp) // 写入文件
// ptr 内存区块的指针,可以是数组、变量、结构体等,用于存放读取到的数据
// fwrite 的ptr 用于存放写入的数据
// size 表示 *每个数据块* 的字节数
// count 表示要读写的 *数据块的块数*
// fp 表示文件指针
// 每次读写size*count个字节的数据// 读写成功,返回读写成功的块数count,如果返回值小于count
// fwrite 发生了写入错误,可以用ferror()函数检测
// fread 可能读到了文件末尾或发生错误,用ferror() 或feof()检测
int main()
{int N=5;int a[5]={1,2,3};int b[5];int i,size=sizeof(int);FILE *fp;if ((fp=fopen("F:\\c-learning\\file2.txt","rb+"))==NULL){puts("file to open");exit(0);}// size 每个块的字节数; N 为块数fwrite(a,size,N,fp); // 把a写入到fprewind(fp);fread(b,size,N,fp); // 把fp读到bfor (int i=0;iprintf("%d\t",b[i]);}printf("\n");fclose(fp);return 0;
}

进阶-读写结构体

#include 
#include 
#include #define N 2struct stu
{char name[10];int num;int age;float score;
}boya[N],boyb[N],*pa,*pb;int main()
{FILE *fp;int i;pa=boya;pb=boyb;strcpy(pa[0].name,"zhangsan");strcpy(pa[1].name,"lisi");for (int i=0;ipa[i].num=10;pa[i].age=20;pa[i].score=60.0;}if ((fp=fopen("./file.txt","wb+"))==NULL){puts("fail to open file\n");exit(0);}fwrite(boya,sizeof(struct stu),N,fp); // 写入fprewind(fp);fread(boyb,sizeof(struct stu),N,fp); // 从fp读入结构// fread(&someCertainStructInstance,sizeof()...)for (int i=0;iprintf("%d\n",pa[i].num);printf("%d\n",pa[i].age);printf("%f\n",pa[i].score);}fclose(fp);return 0;
}

fprintf/fscanf – 有问题

scanf\printf字符串输出到标准输入输出设备上(显示器)
fscanf把格式化字符串输出到执行文件
``fprintf` 把文件的内容输出到指定的数据

int fscanf(FILE *fp,char *format); // 返回参数列表中被成功赋值的参数个数
int fprintf(FILE *fp,char *format); // 返回成功写入的字符的个数,失败则返回负数FILE *fp;
int i,j;
char *str,ch;
fscanf(fp,"%d,%s",&i,str); // 读取文件
fprintf(fp,"%d %c",j,ch); // 写入文件

文件复制

注意:除非对于文本格式,否则fopen一定要以二进制的形式打开

开辟一个缓冲区,不断从源文件中读取内容到缓冲区,每读取完一次就将缓冲区中的内容写入到新建的文件,直到把原文件的内容读取完
通常来讲,缓冲区的数据时没有结束标志的,如果缓冲区填充不满,–> 一般借助的就是fread 记录每次读取到的字节数

size_t fread(void* ptr,size_t size,size_t count,FILE *fp)
// 如果 size =1 ,则返回的就是读取的字节数,
int copyFile(char *fileRead,char *fileWrite);
int main()
{char fileRead[100]; // 要复制的文件名char fileWrite[100]; // 复制后的文件名strcpy(fileRead,"file1.wmv");strcpy(fileWrite,"file2.mp4");if (copyFile(fileRead,fileWrite)){printf("copy done ...");}else{printf("copy failed...");}return 0;
}int copyFile(char *fileRead,char *fileWrite)
{FILE *fpRead;FILE *fpWrite;// 设置缓冲区大小int bufferLen=1024*4;// 开辟缓冲区char *buff=(char*)malloc(bufferLen);// 实际读取的字节数int readCount;if ((fpRead=fopen(fileRead,"rb"))==NULL || (fpWrite=fopen(fileWrite,"wb"))==NULL){printf("connot open file");exit(1);}// 不断从fileRead读取内容,放在缓冲区,再将缓冲区的内容写入filewrite// readcount 表示实际是多少个字节while ((readCount=fread(buff,1,bufferLen,fpRead))>0){// 下面两种写法都可以 !!!fwrite(buff,readCount,1,fpWrite); // fwrite(buff,1,readCount,fpWrite);}free(buff); //手动释放动态内存fclose(fpRead);fclose(fpWrite);return 1;
}

ftell

long int ftell(FILE* fp); //获得文件内部指针(位置指针)距离文件开头的字节数
long fsize(FILE *fp);int main()
{long size=0;FILE *fp=NULL;char filename[30]="file1.wmv";if ((fp=fopen(filename,"rb"))==NULL){printf("failed open...");exit(1);}printf("%ld\n",fsize(fp));return 0;
}long fsize(FILE *fp)
{long n;// 当前位置// fpos_t 保存文件的内部指针fpos_t fpos; // typedef long long fpos_t// 获取当前位置// fgetpos 获得文件内部指针,fsetpos 设置文件内部指针fgetpos(fp,&fpos); // 设置到文件末尾fseek(fp,0,SEEK_END);// 获得文件内部指针(位置指针)距离文件开头的字节数n=ftell(fp);// 恢复之前的位置fsetpos(fp,&fpos);return n;
}

exit

#include
exit(1); // 异常退出,返回给操作系统
exit(0); // 正常退出 

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...