Files
BlogPosts/Collection/YoudaoyunNotes/02C语言/03-数据类型及IO流.md

715 lines
23 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 一、基本数据类型
1. **字符型**
数据类型关键字char
类型长度1Byte(字节) = 8bit(位)
Byte --> KB --> MB --> GB-->Tb --> PB 进制换算满1024进一
取值范围
无符号只有自然数unsigned char 取值范围 0~2^8-1 0~255
有符号(负数和自然数):(signed) char 取值范围 -2^7 ~ 2^7-1 -128~127
![](images/WEBRESOURCE38bf818da8bb069ed9eb989de0bff6eaimage.png)
使用方法
```c
char a = 'a'; // 字符在内存中以ASCII码值的形式存在,因此char a='a'等价于 char a=97
// 单字节整数类型
```
![](images/WEBRESOURCE73773b4065a244cce2bf36de18615e0cimage.png)
记忆方法:**'A' -> 65 'a'->97 '0'->48**
1. **整型**
1. 短整型
类型关键字short
类型长度2 字节32位与64位
取值范围
无符号只有自然数unsigned short 取值范围 0~2^16-1 0~65535
有符号(负数和自然数):(signed) short 取值范围 -2^15 ~ 2^15-1 -32768~32767
1. 整型
类型关键字int
类型长度4 字节32位与64位
取值范围
无符号只有自然数unsigned int 取值范围 0~2^32-1 0~4294967295
有符号(负数和自然数):(signed) short 取值范围 -2^31 ~ 2^31-1 -2147483648~2147483647
1. 长整型
类型关键字long32位与64位
类型长度4 / 8字节根据系统的位数决定32位4字节 64位8字节
取值范围
无符号只有自然数unsigned int 取值范围 0~2^32-1 / 0~2^64-1
有符号(负数和自然数):(signed) short 取值范围 -2^31 ~ 2^31-1 / -2^63~2^63-1
1. 长长整型
类型关键字long long
类型长度8 字节
取值范围
无符号只有自然数unsigned int 取值范围 0~2^64-1
有符号(负数和自然数):(signed) short 取值范围 -2^63~2^63-1
1. **浮点型(小数)**
1. 单精度浮点型
类型关键字float
类型长度4 字节6位有效位
取值范围1.2E-38 到 3.4E+38
![](images/WEBRESOURCE9056ea5007d1d9231711d63d2bbf867eimage.png)
![](images/WEBRESOURCEd429a77169c21de412bd8ee7b02e5313image.png)
1. 双精度浮点型
类型关键字double
类型长度8 字节15位有效位
取值范围2.3E-308 到 1.7E+308
![](images/WEBRESOURCE0e7ea7d0398d9e54868b0d0d16713384image.png)
1. 长双精度浮点型
类型关键字long double
类型长度16 字节19位有效位
取值范围3.4E-4932 到 1.1E+4932
![](images/WEBRESOURCE4bd255fbf9260ad534192cb1d5185cf0image.png)
注意:
比较两个int类型的变量是否相等时
```c
int a,b;
if(a == b)
...
```
比较两个float类型的变量进行比较时
```c
float a,b;
a=1.1;
b=2.2;
if(b-1.1 == a) // × 因为在C语言中浮点数是存在精度损失的有可能比原来的数大也有可能小
// 浮点数不能直接用 == 号比较。要使用精度进行判断,精度可以理解为引发一个浮点数发生改变的最小值。
// 当一个浮点数加上精度或者减去精度,都不等于该数本身。
// 精度可以是自己定义的也可以用C语言自带的
if(fabs(b-1.1-a) < 0.000001) // √ if(fabs(b-1.1-a) < 0.000001)  // b-1.1==a   b-1.1-a == 0
// fabs是数学可函数用于取绝对值的需要添加math.h头文件 #include <math.h>
```
1. **布尔型**
该类型使用时需要添加"#include <stdbool.h>"
类型关键字bool
类型长度1 字节
取值范围:真或假(true or false)
> 非0或非NULL即真负数为真常用1表示真
> 0或NULL
> int --> 非0 char -->非'\0' float --> 非'0.0' bool --> 非false 指针-->非NULL
1. **空类型**
注意该类型只能用于定义指针、函数或修饰函数的参数列表,不能定义普通变量
类型关键字void --> 空
类型长度1 字节
## 数据类型溢出
![](images/WEBRESOURCE2416db6773bc1892a970d22688b28c02image.png)
![](images/WEBRESOURCE9a3ffeea27bb5e725aff994cb67d133cimage.png)
# 二、变量
## 概念
在内存中,数据可以被修改的空间,在程序执行过程中数据的值可发生修改,
常见形式:数据类型 用户标识符;
变量声明声明定义:
```c
char a; // 声明定义一个char类型的变量a
int b; // 声明定义一个int类型的变量b
float c; // 声明定义一个float类型的变量c
```
变量的初始化
```c
char a = 'a'; // =在C语言中属于赋值操作即将某个数据放入谋片内存空间声明定义一个char类型的变量a并进行初始化赋值
```
![](images/WEBRESOURCE241c9ea7af5f38a2d179fd848e37cfa9image.png)
## 局部变量
声明定义在函数内部,在当前的{}中有效,函数的参数是局部变量
## 全局变量
声明定义在函数的外部,在本文件中有效,所有函数都可访问。
**注意:**
```c
#include <stdio.h>
float pi = 3.14; // 不在函数内不在{}中的变量——全局变量(可用范围是当前这个文件内)
int main(int argc, char const *argv[])
{
    char a = 'A';  // 变量的声明定义放在一对{}内的变量——局部变量(可用范围局限于这一对{}
    {
        int  b;   // 花括号{}包含的区域称为 —— 局部作用域
    }
    // b = 50;  // ❌超出作用域范围
    // pi = 6.28;  // ✔ 全局作用域包含局部作用域
    // pi ?  3.14
    float pi=1.32; // ✔ 变量在同一个作用域中不能重名,但在不同的作用域中可以重复
    // pi ?  1.32
    {
        // pi ?  1.32
        float pi=33.32; // ✔ 当不同作用域中的变量名字相同,使用时采用就近原则
       //  pi ? 33.32
    }
    // pi ?  1.32
    printf("a = %c\n", a);
    return 0;
}
```
# 三、常量
在内存中,数据不能被改变空间,在程序执行过程中数值不能被修改,保持固定的值也称
```c
10 3.14 5.20 66 88 'a'
```
1. **整型常量(二进制、八进制、十进制、十六进制)**
1. 二进制
表示范围0和1满2进一1 + 1 ==> 0B10B B1 + 1 10
1. 八进制
表示范围0~7满8进一7 +1 ==> 0o10O 07 +1 010
1. 十进制
表示范围0~9满10进一9 +1==> 10D 9+1 10
1. 十六进制
表示范围0~9 A~F(10~15)满16进一F + 1 ==> 0x10H 0xF+1 0x10
### 进制间支持相互转换
**二进制转N进制**
二进制01001101
转为八进制三位二进制等于一位八进制从右往左不足3位左补0421码进行转换0115
转为十进制使用从右往左逐位乘2的位数-1次幂求和$0*2^7+1*2^6+0*2^5+0*2^4+1*2^3+1*2^2+0*2^1+1*2^0 = 0+64+0+0+8+4+0+1 = 77$
转为十六进制四位二进制等于一位十六进制从右往左不足4位往左补08421码进行转换0x4D
**十进制转N进制**
十进制123
除N取余倒记法短除法
![](images/WEBRESOURCE01494a5ca65c3e8f09d6221377f879c2image.png)
**八进制转N进制**
转二进制一个八进制等于三位二进制42105 ==》 101
转十进制使用从右往左逐位乘8的0+位的位置-1次幂求和
转十六进制:转二进制后转十六进制
**十六进制转N进制**
转二进制一个十六进制等于四位二进制84210x7 ==》 0111
转十进制使用从右往左逐位乘16的0+位的位置-1次幂求和
转八进制:转二进制后转八进制
```c
223 // ✔️
215u // ✔️ unsign int
0xFEEL // ✔️ 十六进制常量 L long int
078 // ❌ 0表示数据类型为八进制但八进制数据没8
032UU // ❌ U不能重复
88 // ✔️
0233 // ✔️
30 // ✔️
30l // ✔️
0x4b // ✔️
312UL // ✔️ unsigned long int
0xFEUL // ✔️ 十六进制无符号成整型常量
```
有符号整型常量存储方法 —— 存储补码
原码:数据绝对值的二进制编码,无符号数在内存中以原码形式保存
反码:对原码逐位取反
补码反码加1有符号数的二进制码的最高位为符号位(1负 0正),在内存中用其绝对值原码的补码(符号位保持不变)进行存储,
![](images/WEBRESOURCE9923ec431e7de4a5464765a1739d32ccimage.png)
1. **浮点常量**
浮点型常量由符号位、整数部分、小数点、小数部分和E指数部分组成
```c
3.14159 // 合法
3.14159E5L // 合法 3.14159*10^5
510E // 非法 不完整的指数
110E // 非法 没有小数或指数
.e55 // 非法 缺少整数或分数
+1.2e+5 // 合法 +1.2*10^5
1.5e-9 // 合法 1.5*10^-9
-5.0e10 // 合法 -5.0*10^10
```
1. **字符常量**
字符常量用单引号包含,例如:'x' 可以存储在 
字符常量可以是一个普通的字符(例如 'x')、一个转义序列(例如 '\t'),或一个通用的字符(例如 '\u02C0')。
在 C 语言中,有一些特定的字符,当它们前面有反斜杠(转义字符 \ )时,它们就具有特殊的含义,被用来表示如换行符(\n或制表符\t等。
| 转义序列 | 含义 | |
| ------------ | ------------- | --- |
| `\\` | \ 字符 | |
| `\'` | ' 字符 | |
| `\"` | " 字符 | |
| `\?` | ? 字符 | |
| `\a` | 警报铃声 | |
| `\b` | 退格键 | |
| `\f` | 换页符 | |
| `\n` | 换行符 | |
| `\r` | 行首符 | |
| `\t` | 水平制表符 | |
| `\v` | 垂直制表符 | |
| `\ooo` | 一到三位的八进制数 | |
| `\xhh . . .` | 一个或多个数字的十六进制数 | |
\开头的表示八进制数对应的字符,如:'\43' --> 043 --> 100011 --> '#'
```c
char a = '\43'; // char a = 043; char a = '#'; // 没有分别
char *s = "\61\62"; // char *s = "12" //没有区别
char *s = "061062"; // 表示就是字符串"061062"不等价于char *s = "12";
```
\x开头表示十六进制数对应的字符'\x31' --> 0x31 --> '1'
```c
char c = '\x31'; // 等价于 char c = 0x31; 或 char c='1';
char *s = "\x31\x32"; // 等价于 char *s = "12";
char *s = "0x310x32"; // 表示就是字符串"0x310x32"不等同于char *s = "12";
```
字符常量中内存中存放时是存放其对应的ASCII码值实际上字符常量在内存中是单字节的整型常量数据
![](images/WEBRESOURCEda3558d0f467fb2e8b63e0e13cc8213dstickPicture.png)
**记忆ASCII'A' --> 65 'a' --> 97 '0'-->48**
![](images/WEBRESOURCE4f76333942e38a6ebe5008d9491852a9stickPicture.png)
**总结:整型常量、字符常量、浮点常量都可通过对应的类型的变量进行表示。**
1. **字符串常量**
字符串常量用双引号包含,例如:"xyz",字符串量使用指针或数组表示,具体细节如下
- 字符串在内存中实际是一个连续的字符常量组合
- 任何字符串都以一个字符'\0'作为结束标记,如"funny story"在内存中的存储细节如下
![](images/WEBRESOURCE1a26d5b47439bd40860c97725e4110c5image.png)
![](images/WEBRESOURCE999e2e4cb93fdf4ec8adf3a8df201afcimage.png)
- **注意**""表示一个字符串虽然是空的字符串但其内存不空拥有内存1字节保存的是'\0'字符。
1. **常量的定义**
在C语言中常量的表示方法有两种方式
1. 使用`#define`宏定义预处理指令表示
```c
#define PI 3.14 // PI表示浮点常量3.14在预处理时使用了PI的代码会被3.14自动替换
// 这样使用的目的时将字面量在源码中进行隐藏使用更容易理解的单词进行表示可以提高代码的易读性
```
1. 使用const关键字, const关键字用于声明一个只读变量即变量的值不能再发生修改使用const关键声明常量时必须初始化赋值。
```c
const int a = 5; // a是一个只读变量即a是一个常量其值为5
a = 10; // 错误,不允许被修改
```
![](images/WEBRESOURCE51b11638af5912a048a35324caaea19cimage.png)
在C/C++中存在两种类型的表达式
1. 左值lvalue表示的是一个对象的标识符如变量名它可以出现在赋值语句的左侧
```c
int a = 10; // a既是左值也可以作为其他表达的右值
```
1. 右值rvalue表示一个临时对象或表达式如常量、函数返回值等它不可以出现在赋值语句的左侧
```c
int a = 10; // 10是右值不能作为左值
```
# 四、作业
[数据类型测试题.docx](attachments/WEBRESOURCE1ebc5cddf8773c3fb139b21db91946c8数据类型测试题.docx)
在作业文档的前面添加日期提交到 文件浏览器 作业文件夹下的自己名字文件夹中 然后在在线表格中登记
[【腾讯文档】CQ2605-作业统计表](https://docs.qq.com/sheet/DVHhFTkdQUXF6RWRP?tab=BB08J2)
# 五、输入输出格式化控制符
![](images/WEBRESOURCE31a9952598334421c011d9f722ff3cceimage.png)
![](images/WEBRESOURCEa4614147cc011d922c72d84cca2528f3image.png)
![](images/WEBRESOURCE3c5663641a0b8dbf76f912751edbc3a3image.png)
输入scanf(); // 默认从键盘输入,只需求取数据
```c
#include <stdio.h>
int main(int argc, char *argv[])
{
    int years,month,day;
    /* scanf格式化输入输入过程必须按照scanf中要求的符号进行输入否则无法正确的进行输入数据 */
    // &表示取址  *表示取值
    scanf("%d%d%d",&years, &month, &day);  // 两个数据间可用空格或回车隔开scanf不能接收空格和回车
                                           // 若输入空格或回车则判定为本次输入的结束,不要加\n否则回车将失效                                      
    printf("%d/%d/%d\n", years, month, day);
    scanf("%d-%d-%d",&years, &month, &day);  // 输入数据间必须添加-  2025-7-10                        
    printf("%d/%d/%d\n", years, month, day);
    scanf("%da%da%d",&years, &month, &day);  // 输入数据间必须添加a     2025a7a10                    
    printf("%d/%d/%d\n", years, month, day);
    char  str[10];
    scanf("%s", str); // 数组的名字就是数组的地址, 输入过程中的空格或回车视为输入终止
    printf("%s\n", str);
    float f;
    scanf("%f", &f);
    printf("%f\n", f);
    char ch;
    scanf("%c", &ch);
    printf("%c\n", ch);
    return 0;
}
```
输出printf(); // 默认输出到终端屏幕
```c
#include <stdio.h>
int main(int argc, char *argv[])
{
    int a = 1;
    int b = 100;
    /* \n 表示换到下一行 */
    printf("%5d\n", a); // 输出有符号十进制数右对齐不足5位在左添空格
    printf("%5d\n", b); // 输出有符号十进制数右对齐不足5位在左添空格
    printf("%-5d\n", a);// 输出有符号十进制数左对齐不足5位在右添空格
    printf("%-5d\n", b);// 输出有符号十进制数左对齐不足5位在右添空格
    char c = 12;
    short d = 10;
    printf("d = %hd\n", d); // 输出半个有符号十进制数
    printf("c = %hhd\n", c); // 输出半半个有符号十进制数
    int a1 = 10;
    printf("%d\n", a1); // 输出有符号的十进制数
    unsigned int a2=20;
    printf("%u\n", a2); // 输出无符号的十进制数
    int a3 = 10;
    printf("%o\n", a3);  // 输出无符号八进制数,不带前缀
    printf("%#o\n", a3);  // 输出无符号八进制数,带前缀
    printf("%x\n", a3);  // 输出无符号十六进制数,不带前缀,字母部分小写
    printf("%#x\n", a3);  // 输出无符号十六进制数,带前缀,字母部分小写
    printf("%X\n", a3);  // 输出无符号十六进制数,不带前缀,字母部分大写
    printf("%#X\n", a3);  // 输出无符号十六进制数,带前缀,字母部分大写
    char a4 = 'a';
    printf("%c\n", a4); // 输出字符
    char *s = "abcd";
    printf("%s\n", s); // 输出字符串,%s遇到'\0'自动结束
    float a5 = 3.145592;
    printf("%f\n", a5); // 输出单精度浮点数小数形式默认6位精度
    float a6 = 3141592.6;
    printf("%e\n", a6); // 输出单精度浮点数(指数形式)
    printf("%.2f\n", a5); // 输出单精度浮点数小数形式2位精度
    printf("%.1f\n", a5); // 输出单精度浮点数小数形式1位精度
    printf("%.3e\n", a6); // 输出单精度浮点数(指数形式),3位精度
    int *p = &a;
    printf("%p\n", p); // 输出指针的值(地址)
    printf("%.3s\n", s); //只输出前3个字符
    long a7 = 10;
    printf("%ld\n", a7); // 输出有符号长整型十进制数
    long long a8 = 10;
    printf("%lld\n", a8); // 输出有符号长长整型十进制数
    char *s1 = "zhangsan";
    char *s2 = "lisi";
    char *s3 = "wangwu";
    int n1 = 10, n2 = 20, n3 = 30;
    printf("%-12s%-12s%-12s\n", s1,s2,s3);  // 左对齐,不足添空格
    printf("%-12d%-12d%-12d\n", n1,n2,n3);
    printf("%12s%12s%12s\n", s1,s2,s3);// 右对齐,不足添空格
    printf("%12d%12d%12d\n", n1,n2,n3);
    printf("%s\t%s\t%s\n", s1,s2,s3);// \t水平制表符
    printf("%d\t%d\t%d\n", n1,n2,n3);
    return 0;
}
```
## 练习
编写代码在终端输出如下内容
![](images/WEBRESOURCEd5ac80a4126ac71c2086d85336dbf99dimage.png)
# 六、IO流
1. **概念**
键盘是系统的标准输入设备从键盘输入数据称为标准输入stdin屏幕终端是系统的标准输出设备在屏幕上输出数据称为标准输出stdout在屏幕上输出出错信息称为标准出错stderr这些输入输出称为IO流。
在计算机系统中当需要使用一种或多种IO流设备时计算机系统就会自动的形成三种缓冲机制stdin、stdout、stderr用于在程序执行期间存储IO的数据这样的缓冲机制称为缓冲区临时存放数据数据是无价的
![](images/WEBRESOURCEe80dc3d48db078411a57b515668d8e57image.png)
```c
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    int a = 0;
    char c = 0;
    // scanf("%d", &a);
    // getchar();// 清除stdin中上一次输入的残留
    // scanf("%c", &c);
    // printf("a=%d c=%c\n", a, c);
    // printf("明日复明日,明日何其多。"); // 默认存在于stdout ,程序正常结束会自动冲刷
    // printf("明日复明日,明日何其多。\n"); // \n stdout遇到换行会自动冲刷
    /* while (1)
    {
        printf("明日复明日,明日何其多。");   // 当stdout满时自动冲刷
        usleep(100*1000);
    } */
   
    /* printf("明日复明日,明日何其多。");  //缓冲区切换时会自动冲刷
    scanf("%d", &a); */
    printf("明日复明日,明日何其多。");
    fflush(stdout);  // 手动的冲刷stdout缓冲区
    pause(); // 暂停向下执行
    return 0;
}
```
**注意:**
1. scanf函数中的控制串不能随便乱写尤其是结尾的'\n'因为用户必须按照scanf函数中描述的控制串中的内容进行输入数据否则将输入失败scanf()函数是无法从键盘获得空格(' ')和回车('\n')若需要获得空格和回车则建议使用fgets函数。
1. scanf函数是有返回值的并且返回的值是正确输入的个数。
## 练习
编程实现如下功能:
- 如果用户输入大小写字母则输出字母对应的ASCII码值。
- 如果用户输入ASCII码值则输出对应的大小写字母。
# 七、类型转换
- 概念:不一致但相兼容的数据类型,在同一表达式中将发生类型转换
- 转换模式:
- 隐式转换:系统按照隐式规则自动进行转换
- 显示转换:也称强制转换,用户显式的自定义进行转换
- 隐式规则:从小类型到大类型转换,目的表达式中的数据精度不丢失
![](images/WEBRESOURCEf9401753ae5405e97b73dbc1662bfc9001416f17412c415232ef6faf014cdff5.png)
```c
char a = 'a';
int b = 12;
float c = 3.14;
float x = a + b - c; // 在该表达式中将会发生隐式类型转换所有的操作数都会被提升为float
```
- 显示转换:用户强行将一个类型转换为另一个类型,此过程可能会发生精度缺失
```c
char a = 'a';
int b = 12;
float c = 3.84;
float x = a + b - (int)c;// 在该表达式中a将隐士的转换为int类型
// c将被强制的转换为int类型同时丢失精度
// 运算结果将隐式转换为float类型
```
- 总结:不管是隐式转换还是强制转换,变换的都是操作数在运算过程中的类型,是临时发生的,操作数本身的数据类型不会发生修改,也无法修改。
- 数据类型转换的本质:各种不同的数据类型实际上在内存中都一样的都是二进制数,数据的类型描述相当于是用户于系统的一种约定,在用户能够接收后果的情况下这个约定可以被临时打破,但数据的本身不会发生改变。
# 八、可移植整型
- 概念:同一种整型数据在不同的编译系统下数据内存尺寸会发生变化,相同的程序在位数不同系统下运行得到的结果可能发生变化,因此可移植数据类型讨论的是相同的代码不关放到什么系统中,尺寸都保持不变的整型数据。
- 整型数据的尺寸C语言的标准并未规定整型数据的具体大小只规定了相互间的大小"相对大小"short不可比int长long不可比int短长整型数据的长度等于系统的字长。
- 系统字长CPU一次处理数据的长度称为字长。如32位系统CPU一次处理数据以32bit为单位64位系统CPU一次处理数据以64bit为单位。
- 数据类型的典型大小:
| 数据类型 | 16 位平台(字节) | 32 位平台(字节) | 64 位平台(字节) | 说明 | |
| --------- | ---------- | ---------- | ---------- | ------------------------------------------------ | --- |
| char | 1 | 1 | 1 | 始终为 1 字节8 位),用于存储字符或小整数 | |
| short | 2 | 2 | 2 | 至少 2 字节,通常固定为 2 字节16 位) | |
| int | 2 | 4 | 4 | 与平台 “字长” 相关16 位平台为 2 字节32/64 位平台通常为 4 字节(但不绝对) | |
| long | 4 | 4 | 8 | 32 位平台与 | |
| long long | 8 | 8 | 8 | C99 标准引入,固定为 8 字节64 位),用于表示更大范围的整数 | |
- 可移植整型关键typedef
```c
typedef int int32_t; // 给类型int取个别名为int32_t
typedef long long int64_t; // 给类型long long取个别名为int64_t
```
思路为所有系统提供一组固定的、能反映数据尺寸的、统一的可移植整型名称然后在不同的系统中为这些可移植整型提供对应的typedef语句即可例如Linux中"/usr/include/stdint.h"。
```c
int8_t // typedef char int8_t
int16_t
int32_t
int64_t
uint8_t // typedef unsigned char uint8_t
uint16_t
uint32_t
uint64_t
pid_t
time_t
size_t
...
```