首页 >> 大全

【在更】基础 | C 语言笔记(使用 Visual Studio 2019)

2023-10-13 大全 31 作者:考证青年

一、简介 学习资源

王道训练营-C语言教程

历史

语言:C 语言 ← B 语言 ← A 语言

开发环境:编辑器 + 编译器 + 调试器

系统:Linux ← UNIX

不同语言之间的区别

C/C++:可移植性强的语言, 和 Linux 的接口有差异,汇编语言。

Java/:跨平台语言,可从 平台移植到 Linux 平台使用

学习目标 理解程序的执行过程掌握程序调试能力 断点及调试窗口设置 内存的变化过程

在编译器行号左侧灰色部分点击出现红点(断点)。

当程序运行到断点时(上图出现黄色箭头),执行步骤截止至断点之前。此时 i 的地址内容未发生改变。

点击逐过程,程序运行下一步后,i 地址的内存发生改变,变为 i 的取值 10(十六进制表示为 0a。小端显示:低地址在前,高地址在后,实际存储内容为 00 00 00 0a)。

点击逐过程,程序执行输出 hello world

输出:

点击逐过程,程序运行 2019 版隐藏的 ("pause"),打印【按任意键关闭此窗口】。此时程序执行 C 语言内镶嵌语言的命令 pause。

C 语言也可嵌套其他语言,如微软的语言 BAT(微软处理脚本)、 等。

Debug 模式与 模式的区别

因此只有在 Debug 模式下才能对代码进行调试。

逐过程(F10)与逐语句(F11)的区别 声明子函数

格式:void 函数名(传递的参数) {函数内容};

注意:当传递数组时,参数部分表示为 数组名[] 即可。因为传递数组时,子函数并不知道数组长度,所以数组长度需要另外定义与传递,即 void 函数名(数组名[],数组长度的变量名) {函数内容};。

C/C++/Java 出错

编译错误:代码编写错误,无法编译生成

执行错误:打印结果不符合预期

编译原理解析 程序的编译过程

关于编译器解决方案与项目 编译与链接的区别:

报错时出现 error 为链接错误。双击报错可定位,可能是链接源的错误或链接位置的错误。

二、数据类型、运算符与表达式 学习目标 2.1 数据类型的分类

2.2 常量

程序运行过程中值不发生改变的量。

例:int i = 10 10 为常量 / 立即数

内存:

PC 指针:程序计数器,存储一个地址值,指向当前马上要给 CPU 译码器的指令。每执行一条则向下走一条指令(每条指令不一定等长)。

译码器读取 i = 10,在栈空间开辟 4 字节内存,将 10 复制到栈空间。

变量:在栈空间上有一个存储的位置,可改变。

常量:在编译后即被放入译码器的代码段,不可改变。

64位文件可用的虚拟地址空间大小: 2 32 × 4 G 2^{32}×4\ G 232×4G

2.3 变量 2.4 整型数据 2.4.1 符号常量

定义:# 变量名 常量(末尾不加分号)。

程序中用到的常量名位置直接替换为常量内容。

例:输出为 7

3+2*2=7

其中,查看预处理效果方法:右击项目 → 属性 → 配置属性 → C/C++ / 预处理文件 → 是。重新生成后在项目 → Debug 文件夹 → 打开 main.i 文件,前几万行为头文件(.c 文件中开头带 # 行)的展开,文件末尾为预处理结果即需要查看的部分 → 查看后将“是”改回为“否”,否则之后运行报错。

作用:提高程序可读性、便于修改。

2.4.2 整型常量的不同进制表示 2 / 4 / 8 / 16

进制转换:

1个字节(byte) = 8 位(bit)。

1 KB = 1024 byte;1 MB = 1024 KB;1 GB = 1024 MB。

CPU 寻址时最小访问单元为 1 字节。

数据总线每次从内存中取 8 字节。

内存为小端模式存储。

输出表示:

%d 表示十进制

%o 表示八进制

%x 表示十六进制

2.4.3 补码

CPU 中的处理单元:译码器、加法器、乘法器等,不存在减法器。进行减法运算需要使用加法器与补码。

例:2-5=2+(-5),存储 (-5) 时需要用补码表示,即需要将原码 5= 0005 取反后得 fffa,加 1 后得 -5= fffb。加 2(有进位)后得到计算结果 fffd。

当最高位为 1 时,要得到原码才能知道 fffd 的值,即堆其取反后加 1(也可减 1 后取反或取反后加 1,结果相同)得到 3,所以其值为 3。

注: 中先定义的地址较大,微软在两个变量间设置了 8 个字节的保护空间。

2.4.4 整型变量

整型变量包括 6 种类型,分别为:

注:括号表示其中的内容是可选的。

有符号基本整型与无符号基本整型的最高位所代表的意义如下:

不同整型变量表示的整型数范围如下表,超出范围会发生溢出导致计算出错。

只有整型数会产生溢出。

注:32 位的 long 长 4 字节,64 位的 long 长 8 字节。一般为 64 位(服务器)。

例:将 short 类型的 i=32767 加 1,得到 -32768。

输出:

32767 转换为二进制表示为 0 1111,加 1 后得到 1 0000,最高位为符号位,表示 -32768。

-32768 的原码与补码相同。

注:有符号类型输出时用%d(十进制)、%o(八进制)、%x(十六进制)==,无符号类型输出时用%u,具体如下:

2.5 浮点型数据(精度丢失) 2.5.1 浮点型常量

两种形式如下,常用的为指数形式:

注意:字母 e(或 E)表示 10 的幂次,e 前底数部分必须有数字,e 后的指数必须为整数。

注:形如 -.1e-3 为正确写法,表示 -0.0001。

2.5.2 浮点型变量

浮点数的数值范围与有效数字:

浮点型数据的组成(标准 4 字节浮点型 float):

指数部分表示 2 的幂次,小数部分表示输入数值的二进制表示中的小数部分。

浮点型数据按照指数形式存储:

IEEE-754 浮点型变量存储标准(以 4.5=0 0 0000 0000 为例):

S:符号位。S=1 时为负( ( − 1 ) 1 (-1)^{1} (−1)1),S=0 时为正( ( − 1 ) 0 (-1)^{0} (−1)0)。

E:指数部分。十进制数输入转为二进制数。存储前,指数部分都要加 127=0111 1111(IEEE-754 规定),因为需要表示负数。

M:小数部分。在二进制数小数点前保留一位(即小数点前有且只有一个 1)的前提下,小数点后的部分被存储在这里。

十进制数 4.5 分为整数部分 4 与小数部分 0.5,二进制表示为 100.1:

使用指数形式表示为 1.001 × 2 2 1.001×2^{2} 1.001×22,由于此处为二进制数,故指数为 2 的 2 次幂。

符号位 S=0,指数部分 E=2 存储为 2+127=129=1000 0001,小数部分 M 即 001。存入结果如上表。

精度丢失:

数值范围

以 float 类型为例。浮点型数据指数部分占 8 位。

由于特殊数(1111 1111)与非规格数(0000 0000)的存在,指数部分最大取到 1111 1110,最小取到 0000 0001。

指数的最大表示范围到 − = ( 2 9 − 2 ) − 127 = 254 − 127 = -0111 1111=(2^{9}-2)-127=254-127=−=(29−2)−127=254−127=127 比特。二进制浮点数的指数部分最大到 2 127 ≈ 1. e 38 2^{127}≈1. 2127≈1.,即数值范围最大到 1 0 38 10^{38} 1038;同理,计算 2 − 126 ≈ 1. e − 38 2^{-126}≈1.-38 2−126≈1.−38 可得到数值范围最小到 1 0 − 38 10^{-38} 10−38。有效数字

以 float 类型为例。小数部分 23 位,能够表示的有效数字 2 23 = 2^{23}= 223=,即最大到 0.。因此小数部分可表示 1~6 位的所有小数(如 0.)与 7 位小于 0. 的小数。

由于浮点型变量计算时为二进制指数部分 E 与小数部分 M 相乘(即进行移位),则有效数字在 6~7 位之间,达到逼近效果。

例 1:float f = 1. 加 20

输出:

f 仅在赋值存入时即产生精度丢失。

由于浮点型常量默认按 型运算,输出时 %f 格式为 型,占 8 个字节。具体参考【转】格式串中的%f的输出格式和内容。

例 2:float f == 1.456?

输出:

单步调试:

f 值精确到小数点后 7 位,不等于 1.456。

正确写法:判断两个浮点数是否相等,直接用减法。

两数相减的绝对值在精度范围内。

输出:

存在部分浮点数相乘(移位)相等(如 4.5),但为保证准确性仍需直接计算。

例 3: f =1.

输出:

由于 型浮点数有效数字为 15~16 位,输出结果正确。

2.6 字符型数据 2.6.1 字符型常量

用单引号括起来的一个字符。

正确示例:‘a’、‘A’、‘1’、’ '。

错误示例:‘abc’、“a”、“”。

ASCII 表:

ASCII 表的存储与输出:

单个字符:

例:字符 A

输出:

上述程序若赋值 65 则输出不变。

以带符号整数形式输出为 65 是因为,在 ASCII 表中,字符 A 对应的十进制数为 65。

注:ASCII 表中十进制为 0 对应的字符为空字符,十进制为 32 对应的字符为空格。

汉字:

注:汉字为 GBK 编码(其一),每个汉字占 2 个字节。

例:打印 0xCC

输出:

2.6.2 字符数据在内存中的存储形式及其使用方法

字母大小写转换:

大小写字母间的 ASCII 值差 32。

例:大写字母 ASCII 值 +32

输出:

转义字符:

“\n” 表示光标跳至新建的下一行行首。“\r” 表示跳至该行行首。“\b” 光标前退(向左)一个字符。“\t” 即 Tab 键,在黑窗口中输出 4 或 8 个空格(无标准规定)。“\” 输出每一个 “\” 前都需要加入转义字符 “\” 用于输出。“\0” 表示结束符,即NULL。使用时写作 ‘\0’。“\ddd” 表示转义字符后输入 1~3 位十进制数,输出对应八进制数的 ASCII 字符。“\xhh” 中 “\” 表示之后的 “hh” 从十六进制转换为十进制,输出为十进制数的 ASCII 字符。光标后(右侧)存在字符,再输入字符将会覆盖光标后原有字符(功能类似于键盘上的 )。

例:

输出:

注:注释中存在未加 " " 符号的 \ 将导致编译错误。 原因未知 \{}{原因未知} 原因未知​

2.7 字符串型常量

例:字符变量赋值

输出:

解析:

查看内存,c 与 *p 在内存中的状态如下:

显然,字符串 “A” 并未被存放至字符型变量 c 的地址上,反之被存放的是字符 “0”。 同时,顺着 *p 的地址网上爬,在

地址找到存入的字符串 “A”。

查表可知,字符 “0” 对应的十进制 ASCII 码为 48,转换为计算机的十六进制表示即为 30。 因此,当编译器执行 char c = "A"; 时,先将字符串 “A” 在内存中任意选择一个位置存入,随后将存入地址的最低位存入变量 c 的位置。

因此不可将字符串直接赋值给字符型变量,而应当将其赋值给字符型变量的指针。

注:若使用 cpp 文件编译则编译失败。

例如:“CHINA” 在内存中的存储结果,占用 16 字节

2.8 混合运算

“运算”包括数学运算与赋值运算。

不同类型的数据先要转换为同一类型再进行运算,不同类型的转换级别如下:

从短字节到长字节的类型转换是由系统自动进行的,编译时不会给出警告;若反向进行,则编译时编译器会给出警告。

注:在保证数据内容不会因长字节向短字节转换时产生截断而导致数据丢失时,可以使用强制转换,即在变量前插入 (数据类型),编译不会发出警告。

2.8.1 数值按 int 型(4 个字节)运算

例:两个较大整型常量相乘溢出

解析:

在 ("%lld\n", *) 中直接输出方法相同。

注:在 64位操作系统下,long 型占 8 字节,使用 long 型输出即可。 虽然但是我用x64编译没有成功过也不知道为啥 … … (挠头 \{}{虽然但是我用 x64 编译没有成功过也不知道为啥……(挠头} 虽然但是我用x64编译没有成功过也不知道为啥……(挠头​

2.8.2 浮点型常量默认按 型(8 个字节)运算

例:加法运算

输出:

解析:

例:除法运算

输出:

注:赋值给 float 型变量的常数需要带小数部分,否则编译器默认变量为 int 型运算。

2.9 常用的数据输入/输出函数

标准输入函数:scanf、。

标准输出函数:、。

2.9.1 scanf 函数的原理

当一个进程启动时,内存中的内核区域(详见 2.2 常量 → 内存)开放系统调用。键盘输入被写入标准输入缓冲区,scanf 函数从标准输入缓冲区中读取输入。

系统调用:内核在每个进程开启时为其维护三个缓冲区(即三块内存),由高地址向低地址分别为:标准输入缓冲区、标准输出缓冲区、标准错误输出缓冲区,大小分别为 4k。

当 scanf 读取的缓冲区中没有数据时会产生阻塞,scanf 进入睡眠(CPU 占用率为 0%),在完成输入并键入回车后 scanf 才继续运行。

缓冲区原理:

缓冲区是一段内存空间,分为读缓冲和写缓冲。C 语言缓冲的三种特性如下:

全缓冲:当填满标准 I/O 缓存后才进行实际 I/O 操作。

典型代表:对磁盘文件的读写操作。行缓冲:当在输入和输出中遇到换行符时,将执行真正的 I/O 操作。这时,我们输入的字符先存放到缓冲区中,等按下回车键换行时才进行实际的 I/O 操作。典型代表:标准输入缓冲区(stdin)和标准输出缓冲区()。不带缓冲:即不进行缓冲。

典型代表:标准出错情况(),这使得出错信息可以直接尽快地显示出来。

scanf 函数:

# include 
int scanf(const char *format, ...);
//scanf(字符型常量格式, 存储地址);
//scanf_s(字符型常量格式, 存储地址, 读取字符长度);

例:使用 scanf 时 %d 与 %c 的区别(& 为取址符,* 为指针)

输出(输入 123):

取消 8-9 行注释

输出(仅输入一串 123):

注:由于使用 scanf 编译失败,报错说明 C4996 提示将 scanf 更改为 。二者的不同点在于 scanf 函数不会进行边界检查,可能造成数据溢出,为已弃用的函数;

在调用时需提供一个数字表明最多读取多少位字符,因而能够进行边界检查。在使用 替代 scanf 后,第 10 行发出警告,只需将其更改为 ("%c", &c, (c)); 即可。

解析:

程序中有两行 scanf 函数,运行时只有 1 次输入的原因:

当 scanf 的格式为 %c 时,scanf 函数仅从标准输入缓冲区中读取一个单一的字符;而当 scanf 的格式为 %d 时,scanf 函数将读取输入的一整串十进制整数。

取消注释后,仅当程序运行至第 8 行时输入一串十进制数字,之后再无输入而直接结束程序。因为当输入 123 并键入回车后,第 8 行 scanf 函数以 %d 格式读取标准输入缓冲区中的串 123\n 并打印 123。当程序运行至第 10 行时,scanf 函数以 %c 格式直接读取标准输出缓冲区中的 \n ,由于已经获得行缓冲中执行 I/O 时需要的回车(\n),程序直接运行第 11 行进行打印;倘若第 10 行 scanf 函数以 %d 或 %f 格式读取标准输入缓冲区,由于 \n 不属于 1~9 之间的十进制数或小数点,标准输入缓冲区中的 \n 将被 scanf 函数忽略或删除(若缓冲区内存在空格同理)。此时程序暂停,需要再次将字符输入标准输入缓冲区才能继续运行。

可在 9-10 行之间插入 (stdin);(2017 与 2019 版本)或 (stdin);(更早的版本)清除缓冲区。scanf 函数参数中,第一个 “,” 后的参数为存储地址,必须使用取址符 &,否则会产生参数类型的报错。因为 scanf 函数是将数据存放在变量的存储地址上的,若未加入 &,编译器检测到的将会是一个未初始化的值。另外,在未加入 & 的前提下给变量赋值会产生访问冲突报错,相当于更改赋值数对应地址的内容。

注: 与 的区别:

性质

操作符

库函数

参数

数据的类型或变量

结尾为 \0 的字符串

计算结果

在编译时计算结果

在运行是计算结果

计算方式

计算数据类型占内存的大小

计算字符串实际长度

参考:和的区别 - 徒梦 - 博客园

2.9.2 scanf 函数的循环读取

例:使用 while 语句实现 scanf 函数的循环读取

输出:

数据类型输入输出

int

123

123

char

float

不断打印1

解析:

2.9.3 多种数据类型混合输入

例:混合输入整型、字符型与浮点型数据

输出(输入 100 a 1.1):

程序不断打印 i=100,c= ,f=-.。

解析:

当程序运行至第 11 行之前,各个变量内存状态如下:

此时 ret=2,意味着有两个参数成功获得返回值。对照各个参数的实际内容,获得返回值的为变量 i 与变量 c,变量 f 仍为初始化值。

查看内存,100 被成功赋值给变量 i(对应 ASCII 码为字符 d),而赋给变量 c 的是一个空格。

猜测是输入的 100 与 a 之间的空格被赋值给变量 c。更改 1 ^{1} 1代码第 9 行如下:

一般只需在 %c 前加入空格即可。

如果你使用的是 scanf 函数那么不出意外问题已经解决,但是使用 函数的朋友们会发现运行后发生程序异常:

同时,变量 f 内存中仍为初始化值,变量 c 的内存中成功出现字符 a。但之后出现一串内存的哀嚎,参考C语言()函数的用法,猜测是未定义 函数的字符读取长度而出现的函数越界读取。

更改 2 ^{2} 2代码第 9 行如下:

输出:

若需要限制浮点数输出位数,可在 % 与 f 之间输入限制的大小,如 %5.2f。

未解之谜: \{}{未解之谜:} 未解之谜:​

设定字符c读取长度之前,输入的浮点型数1.1去哪了? \{}{设定字符 c 读取长度之前,输入的浮点型数 1.1 去哪了?} 设定字符c读取长度之前,输入的浮点型数1.1去哪了?​定义变量时,int i; 的位置在 char c; 之前,而运行后发现变量 i 的位置在变量 c 之后的原因?

答:先定义的变量在高地址。

例:混合输入双精度浮点型数据

在上例基础上加入 型变量,改动第9、10、12行

输出:

数据类型输入输出

int

100

100

char

float

1.1

1.

1.1

-.

解析:

在第 12 行设断点,运行发现变量 f 与 d 地址上的数值相同,都是输入的 1.1(计算方式详见 2.5.2 节)

视频里这个例子没有解释的很详细,我找到的解释是基于 scanf 函数与 函数对 %f 格式的不同理解:关于scanf的%f和%lf,及的%f

由于变量 f 为长 4 字节的浮点数类型,变量 d 为长 8 字节的浮点数类型。

在为变量申请空间时,f 的内存范围为 -,d 的内存范围为 -。

根据小端模式的原则,两组输入 1.1 的十六进制表示为 3f 8c cc cd,在内存中存放形式为 cd cc 8c 3f。

当程序运行至 函数时, 函数根据 %f 格式将指针指向变量 f 的 与变量 d 的 将赋值传入。

当程序运行值 函数时, 函数仅将 %f 格式解释为 “打印浮点数”,由于浮点型常量默认按 型(8 个字节)运算,因此 函数按从地址 到地址 顺序打印内存,即 cc cc cc cc 3f 8c cc cd。

基于以上,更改代码第 10 行如下:

%lf 为双精度浮点型格式,占 8 个字节。

输出:

2.9.4 函数介绍

函数可以一次从标准输入缓冲区读取一个字符,等价于 char c; scanf("%c", &c);。

语法格式:

#include 
int getchar(void);

函数返回 int 型是为了方便起见。在函数出错时,函数返回值为 -1,-1 不在 ASCII 码范围内,使用 char 型表示不方便,而使用 int 型表示方便的同时变量的长度要求(4 字节)不影响 char 型变量(1 字节)本身。

2.9.5 函数介绍

输出字符型数据时使用 函数,其作用是向显示器设备输出一个字符。

语法格式:

#include 
int putchar(int ch);

函数输出时不会在末尾补充换行符号,但 2019 版本的 会在末尾自动生成换行。

例: +

输出:

2.9.6 函数介绍

函数可以输出各种类型的数据,包括整型、浮点型、字符型、字符串型等,实际原理是 函数将这些类型的数据格式化为字符串后,放入标准输出缓冲区,然后通过 \n 来刷新标准输出,并将结果显示到屏幕上。

语法格式:

#include 
int printf(const char *format, ...);

函数根据 给出的格式打印输出到 (标准输出)和其他参数中。

字符串格式()由两部分组成:显示到屏幕上的字符和定义 函数显示的其他参数。我们可以指定一个包含文本在内的 字符串,也可以是映射到 的其他参数的 “特殊” 字符,如下列代码所示:

int age = 21;
printf("Hello %s, you are %d years old\n", "Bob", age);

输出:

Hello Bob, you are 21 years old

例: 函数输出对齐

输出:

%3d 靠右对齐;%-3d 靠左对齐;s 默认靠右对齐,前面加入 5 个空格。

2.10 运算符与表达式 2.10.1 运算符分类

C 语言提供了 13 种类型的运算符,如下所示:

算术运算符(+ - * / %)关系运算符(> < == >= ~ | ^ &)赋值运算符(= 及其扩展赋值运算符)条件运算符(?:)逗号运算符(,)指针运算符(* 和 &)求字节数运算符()强制类型转换运算符((类型))分量运算符(. ->)下标运算符([])其他(如函数调用运算符 ())

运算符优先级可参考:C语言运算符优先级(超详细)

2.10.2 算术运算符及算术表达式

算术运算符优先级(由高到低):乘(*)、除(/)、取余(%) → \ → 加(+)、减(-)

适用数据类型:

例:逆序输出

输出:

2.10.3 关系运算符与关系表达式

例:判断年份

输出:

解析:

根据 if 语句的条件,编译器先判断 3,如果是则值为 1,否则为 0;无论关系表达式的值是真是假,编译器判断 关系表达式的值 是的结果都为真,打印 year is ok\n。

更改代码第 9 行如下:

输出:

例:判断闰年(替换上例 9-14 行)

2.10.4 逻辑运算符与逻辑表达式

例:短路运算(逻辑与)

输出:

当逻辑与(&&)运算符前的表达式成立,运算符后的表达式才执行。即使运算符后的表达式优先级高于逻辑与运算符。

短路运算(逻辑或)

输出:

2.10.5 位运算符

位运算符包括左移()、按位取反(~)、按位或(|)、按位异或(^)、按位与(&)。

例:左移

输出:

注:除赋值运算与算术运算以外,其余都不会改变变量值。

例:左移位运算符可能改变值的正负

输出:

解析(参考 2.8.1 示例):

由于整型数默认按 int 型计算,编译器计算 i j ? (i > k ? i : k) : (j > k ? j : k); 。

2.10.8 自增、自减运算符及求字节运算符

例:i++

输出:

解析:

当 ++ 在变量 i 之前时,程序第 7 行 j = i++ > -1; 等同于 j = i > -1; i++;。前一语句判断为假,即 j=0;后一语句 i=-1+1=0。

例:++i

输出:

解析:

当 ++ 在变量 i 之后时,程序按照正常的优先级计算。++i 计算 i=++i=0+1=1;j = !i 将 i=1 取反判断为假,即 j=0。

三、选择与循环 学习目标 3.1 选择结构程序设计 3.1.1 关系表达式与逻辑表达式

根据表达式最后运算步骤的类别确定该表达式的类型。

3.1.2 if 语句

流程图:

左侧为仅 if 语句,右侧为 if + else 语句。

多分支语句

if 语句的嵌套

例:

输出:

注意:if 判断后不能加 ;,即以下写法是错误的:

3.1.3 语句

例:打印每个月的天数

输出:

对程序进行优化:

3.2 循环结构程序设计 3.2.1 goto 语句

例:goto 向上跳转

输出:

例:goto 向下跳转

输出:

注意:标签与 goto 不能跨函数使用。

3.2.2 while 循环

注意:当使用多层嵌套循环语句时出现报错,调试时断点从外层循环向内层尝试设置。

例:

输出:

3.2.3 do while 循环

特点:先执行循环体,后判断循环条件是否成立。

与 while 循环的区别:do while 循环的第一次循环一定会执行。

例:

输出:

3.2.4 for 循环

使用场景:

一般形式:for(表达式 1; 表达式 2; 表达式 3) 语句;

先求解表达式 1。求解表达式 2,若其值为真(值为非 0),则先执行 for 语句中指定的内嵌语句,后执行第 3 步。若其值为假(值为 0),则结束循环,转到第 5 步。求解表达式 3。转回第 2 步继续执行。循环结束,执行 for 语句下面的语句。

注:三条表达式都可省略,; 不可省略。但不建议这样写。

例:

输出:

注:在 for 条件后加 ;,即for (i = 1, total = 0; i

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了