数据类型
1、常量与变量
1.1、关键字
C关键字共有32个
1)数据类型关键字12个:
char、short、int、long(long long)、float、double、unsigned、signed、struct、union、enum、void
2)控制语句关键字12个:
if、else、switch、case、default、break、for、do,while、continue、goto、return
3)存储类关键字5个:
auto、extern、register、static、const
4)其他关键字3个:
sizeof、typedef、volatile(防止编译器优化)
1.2、数据类型
数据类型的作用:编译器预算对象(变量)分配的内存空间大小
- 数据类型:
- 基本类型
- 整型:int、short、long
- 字符型:char
- 实型(浮点型):float(单精度实型)、double(双精度实型)
- 构造类型
- 数组类型
- 结构体:struct
- 联合类型:union
- 枚举类型:enum
- 指针类型: (char *、 int *、int **等)
- 基本类型
1.3、常量
- 在程序运行过程中,其值不能被改变的量
- 常量一般出现在表达式或赋值语句中
定义常量的方式:
const 数据类型 常量名=值; (在C语言中不安全,建议使用宏,在C++中安全)
#define 常量名 值
1.4、变量
-
在程序运行过程中,其值可以被改变的量
-
占位符,%f 表示输出一个浮点型float,默认保留6位小数 占位符,%lf 表示输出一个浮点型double 占位符,%.2f 表示输出一个浮点型float,保留两位小数,在C中会四舍五入,在C++中不会四舍五入
占位符,%.2lf 表示输出一个浮点型float,保留两位小数,在C中会四舍五入,在C++中不会四舍五入
变量定义格式:
数据类型 变量名=值;
#include<stdio.h>
//宏定义
#define PI 3.14159
int main()
{
//const double pi = 3.14159265354;
float r = 2;
double s = PI * r * r;
double l = 2 * PI * r;
//占位符,%f 表示输出一个浮点型float,默认保留6位小数
//占位符,%lf 表示输出一个浮点型double
//占位符,%.2f 表示输出一个浮点型float,保留两位小数,在C中会四舍五入,在C++中不会四舍五入
printf("圆的周长:%lf\n圆的面积:%.2lf\n", l, s);
return 0;
}
注:在定义局部变量可以在数据类型前面加修饰 auto, 也可以不加
1.5、标识符
1)命名规则:
- 不能使用关键字
- 允许使用字母、数字和下划线的组合
- 不允许以数字开头
- 标识符字母区分大小写
- 见名知意
2、整型:int
2.1、整型变量的定义和输出
打印格式 | 含义 |
---|---|
%d | 输出一个有符号的十进制 int 类型 |
%o | 八进制 int 类型 |
%x | 十六进制 int 类型,字母以小写形式输出 |
%X | 十六进制 int 类型,字母以大写形式输出 |
%u | 输出一个无符号的十进制 int 类型 |
#include<stdio.h>
int main0301()
{
//无符号 unsigned;有符号 signed(可以省略,默认都是有符号的)
//int a = -10;
unsigned int b = -10;
//%u 占位符,输出一个无符号的十进制 int 类型
printf("%u\n", b);
return 0;
}
int main(void)
{
/*
//进制相关的问题
//二进制(0-1)、八进制(0-7)、十六进制(0-9 A-F)
int a = 10;
printf("%d\n", a);
//%x 占位符,输出一个八进制 int 类型
printf("%x\n", a);
printf("%X\n", a);
//%u 占位符,输出一个十六进制 int 类型
printf("%o\n", a);
*/
//定义八进制数据,以0开头
int a = 0123;
//定义16进制数据,以0x开头
int b = 0xabcdef;
printf("%d %d\n", a, b);
//计算机定义数据是,不可以直接定义二进制
return 0;
}
2.2、整型变量的输入
1)VS的C4996错误
scanf 引起的安全警告问题
由于微软在VS中不建议使用C的传统库函数 scanf,srtcpy,sprintf等,所以直接使用这些库函数会提示C4996错误。VS建议使用带_s的函数,如scanf_s,strcpy_s等函数,这些函数不是编撰C函数。
要继续使用此函数,要在源文件中添加宏来避免这个错误:
#define _CRT_SECURE_NO_WARNINGS # 这个宏放在程序第一行,其他位置依然会报错
#pragma warning(disable:4996) # 或者使用这和
- 由于用户输入的可能不是期望的类型,但是依然按照期望的类型进行处理了,最终导致出错,因此是不安全的
2.3 short、int、long、long long
数据类型 | 占用空间 |
---|---|
short | 2字节 |
int | 4字节 |
long | windows为4字节;linux下32位为4字节,64位为8字节 |
long long | 8字节 |
3、sizeof 关键字
计算一个数据类型的大小,单位为字节。返回值为 size_t,在32位系统下是unsigned int,是一个无符号的整数。
sizeof(数据类型) //或者
sizeof(变量名)
注:整型数据在内存中的占据内存大小与操作系统有关,但是:
short<=int <=long<long long
当一个小的类型赋值给大的类型,不会有丢失,但是反过来会有丢失
4、字符型
4.1、字符型变量的输入输出
char 存储一个字符 占用一个字节 单引号’‘
字符型存储时,存放的是字符对应的ASCII码,实际上字符型是一个一字节的整型数据。
- 字符型变量
char ch='a';
- 打印字符型变量
printf("%c\n",ch);
- 打印字符对应的十进制
printf("%d\n",ch);
- ASCII码:
空格:32
‘0’:48
‘A’:65
‘a’:97
- 字符型也可以进行加、减运算
char ch1='a';
char ch2='A';
printf("%d\n",ch1-ch2);
- 小写字母转大写字母,减32;大写字母转小写字母,加32
4.2、转义字符
转义字符 | 含义 | ASCII码 |
---|---|---|
\a |
警报 | 007 |
\b |
退格 | 008 |
\f |
换页 | 012 |
\n |
换行 | 010 |
\r |
回车 | 013 |
\t |
水平制表符 | 009 |
\v |
竖直制表符 | 011 |
\\ |
反斜线 | 092 |
\' |
单引号 | 039 |
\" |
双引号 | 034 |
\? |
问好 | 063 |
\0 |
数字0 | 000 |
\ddd |
8进制转义字符,d的范围0-7 | 3位八进制 |
\xhh |
16进制转义字符,h的范围0-9,a-f,A-F | 3位十六进制 |
打印%也需要进行转义:\%
5、实型(浮点型):float,double
- double类型比float表示的浮点型精度更高。
- 由于存储单元有限,因此浮点型的表示精度也是有限的,存在误差。
- 占位符 %lf 表示double型的输出,但是使用 %f 也可以
5.1、sizeof 字节大小
- float:4字节
- double:8字节
浮点型在内存中的存储分为三部分:
- 符号位
- 指数为
- 小数位
占位符 %p 以无符号十六进制显示内存的地址:
int a=10;
float b=3.14;
printf("%p\n",&a);
printf("%p\n",&b);
大小端对齐存储
5.2、以科学计数法表示浮点型数据
float a=3.2e2f;
float b=3.2e-2f;
float c=3210.454;
printf("%e\n",c);
float d=0.123456;
printf("%e\n",d);
6、进制
x进制就是逢x进一。
6.1、二进制
基数为2,逢二进一,借一当二。
数据在计算机中主要是以补码的形式存储的。
1)十进制转二进制
除二反序取余法
2)二进制转十进制
权值法:将一个二进制从末尾开始乘以二的n次幂,n从0开始
1010 $\rightarrow$ 0 * 2^0+1 * 2^1+0 * 2^2+1 * 2^3=10
3)十进制转八进制
除八反序取余法
4)八进制转十进制
权值法:将一个八进制从末尾开始乘以八的n次幂,n从0开始
5)十进制转十六进制
除十六反序取余法
6)十六进制转十进制
权值法:将一个十六进制从末尾开始乘以十六的n次幂,n从0开始
7)二进制和八进制、十六进制之间的转换
- 8421法则:二进制转十进制,从右往左,分别对应1,2,4,8,……
- 二进制转八进制:二进制从右往左,三位一组,将三位二进制转换成一位八进制
- 八进制转二进制:一位八进制转换成三位二进制
- 二进制转十六进制:二进制从右往左,四位一组,将四位二进制转换成一位十六进制
- 十六进制转二进制:一位十六进制转换成四位二进制
7、计算机内数据的存储方式
7.1、小数转二进制
十进制小数转二进制,小数部分和2相乘,取整数,不足1取0,每次相乘都是小数部分,顺序看取整后的数就是转化后的结果
例如:0.432
0.432*2=(0)(0.864) * 2=(1)(0.728) * 2=(1)(0.456)
由于0.432三位小数,因此结果就只需取三位,对应的二进制结果为0.011
7.2、内存单位
术语 | 含义 |
---|---|
bit(比特) | 一个二进制的一位 |
Byte(字节) | 一个字节为8位二进制,计算机中最小的存储单元 |
7.3、原码
原码:数字的二进制形式
- 最高位作为符号位,0表示正,1表示负
- 其他数值部分就是数值本身绝对的二进制数
- 负数的原码是在其绝对值的原码的基础上,符号位为1
7.4、反码
- 对于 正数,反码与原码相同
- 对于负数,符号位不变,其他部分按位取反
7.5、补码
在计算机系统中,数值一律用补码来存储
- 对于正数,原码、反码、补码相同
- 对于负数,其补码为反码加1
- 补码符号位不动,其他位取反,最后整个数加1,得到原码
补码运算的优点:
- 统一了0的编码
- 将符号位和其他位统一处理
- 将减法运算转换为加法运算
- 两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位直接舍弃
零在计算机中的存储方式:0000 0000
7.6、有符号数和无符号数的取值范围
有符号:
数据存储时,将-0
对应的区间值,设为最小的负数,例如8位,就是-128
有符号字符型取值范围:[-2^7, 2^7-1]
signed int 32bit:[-2^31, 2^31-1]
long long 64bit:[-2^61, 2^61-1]
short 2bit:[2^-15, 2^15-1]
long 32bit:[-2^31, 2^31-1]
无符号:
unsigned char:[0, 2^8-1]
unsigned int:[0, 2^32-1]
unsigned long:[0, 2^32-1]
unsigned short:[0, 2^16-1]
8、数据溢出
char ch=127;
ch+=2;
printf("%d\n",ch); //-127
- 当超过一个数据类型能够存放的最大范围时,数值会溢出。
- 有符号位最高位溢出:符号位溢出会导致数的正负发生变化,最高位溢出会导致最高位丢失
9、类型限定
限定符 | 说明 |
---|---|
extern | 声明一个变量,extern声明的变量没有建立存储空间。extern int a; //变量a在定义的时候没有创建存储空间,告诉编译器有这么一个变量,但是没有告诉内存 |
const | 定义一个常量,常量的值不能修改。const int a=10; |
volatile | 防止编译器优化代码,平时不会使用,只有实现特定功能的代码的时候会使用,防止因为编译器的优化而使代码在某些情况下出错 |
register | 定义寄存器变量,提高效率,register 是建议型的指令,而不是命令型的指令,如果CPU 有空闲的寄存器,那么 register 就生效,如果没有空闲的寄存器,那么 register 就无效。 |
计算机中的变量在存储的时候分三步:1)声明;2)定义;3)使用
10、字符串的格式化输入和输出
10.1、字符串常量
- 字符串是内存中一段连续的 char 空间,以 ‘\0’ 结尾
- 字符串常量是由双引号括起来的字符序列,如 “china”
- 字符串常量和字符常量不同:
- “a” 为字符串常量,编译器会自动在末尾添加一个结束标志位 ‘\0’,即 “a” 包含两个字符 ‘a’ 和 ‘\0’,占两个字节空间
- ‘a’ 为字符常量,占一个字节空间
- 占位符 %s 表示输出一个字符串,遇到 \0 停止,例如:
char *a="hello \0 world"
printf("%s\n",a); //输出为 hello
char *b="hello world"
printf("%s\n",b); //输出为 hello world
char *c[11]="hello world"
printf("%s\n",c); //输出为 hello world83w90mfi3 由于只有11个字节位置,没有空间存储结束标志符 \0 ,%s 在输出的时候找不到结束位置,就会一直往后读取内存,直到遇到 \0 为止,额外输出的内容是不确定的
10.2、printf 函数和 putchar 函数
printf 是输出一个字符串,putchar 是输出一个 char
1)printf
打印格式 | 对应数据类型 | 含义 |
---|---|---|
%d | int | 接受整数值并将它表示为有符号的十进制整数 |
%hd | short int | 短整型数 |
%hu | unsigned short | 无符号短整数 |
%o | unsigned int | 无符号八进制 |
%u | unsigned int | 无符号十进制 |
%x, %X | unsigned int | 无符号十六进制,%x 对应 abcdef,%X 对应 ABCDEF |
%f | float | 单精度浮点数 |
%lf | double | 双精度浮点型 |
%e, %E | double | 科学计数法表示的数,e 和 E 分别对应输出时的 e 的形式 |
%c | char | 字符型,可以把输入的数字按照ASCII码转换为相应的字符 |
%s | char * | 字符串,输出字符串中的字符直至遇到字符串中的空字符(\0)为止 |
%p | void * | 以十六进制形式输出指针 |
%% | % | 输出一个百分号 |
printf 附加格式:
字符 | 含义 |
---|---|
l(字母l) | 附加在d,u,x,o前面,表示长整数 |
- | 左对齐 |
m(代表一个整数) | 数据最小宽度 |
0(数字0) | 将输出的前面补上0直到占满指定列宽为止,不可以搭配使用- |
m.n(代表一个整数) | m指定域宽,即对应的输出项在输出设备上所占的字符数,n值精度,用于说明输出的实型数的小数位数,对于数值型来说,未指定n时,默认的精度 n=6 |
int a=10;
printf("%d\n",a); //10
printf("===%-5d===\n",a); //===10 ===
printf("===%5d===\n",a); //=== 10=== 默认右对齐
printf("===%05d===\n",a); //===00010===
int b=123456;
printf("===%05d===\n",b); //===123456=== 数据的长度大于指定的域宽,就直接输出,若小于,则使用指定字符填充
float c=3.14;
printf("%3.2f\n",c); //3.14
printf("%===7.2f===\n",c); //=== 3.14=== m表示正体的宽度
printf("%===07.2f===\n",c); //===0003.14=== m表示正体的宽度
printf("%===-7.2f===\n",c); //===3.14 === m表示正体的宽度
2)putchar
char ch='a';
//输出字符
printf("%c\n",a); //a
//putchar
putchar(ch); //a
putchar('B'); //B
putchar(97); //a
//输出转义字符
putchar('\n'); //输出一个换行符
- putchar 输出字符,可以是变量,字符,数字(0-127),转义字符
10.3、scanf 函数和 getchar 函数
- getchar 是从标准输入设备读取一个 char
- scanf 同过 % 转义的方式可以得到用户通过标准输入设备输入的数据
1)scanf
char ch;
scanf("%c",&ch);
putchar(ch);
int a,b;
scanf("%d%d",&a,&b); //有多个占位符的时候,输入通过空格或者换行来进行分割,这里可以输入12 34,也可以输入12\n34
scanf("%d,%d",&a,&b); //也可以使用特定的分隔符,例如使用逗号,输入格式为:12,34。但是不能使用 \n 作为分隔符,因为使用 \n 会导致输入无法终止
printf("%d\t%d\n",a,b);
scanf("%3d,%d",&a,&b); //使用域宽限制,可以对整型的输入进行限制,例如这里输入:123456
printf("%d\t%d\n",a,b); //输出结果为:123 456
2)getchar
char ch;
//接收键盘获取字符
ch=getchar(); //输入:b
putchar(ch); //输出:b
ch=getchar(); //输入:abc
putchar(ch); //输出:a putchar只能输入一个字符
//在程序最后添加 getchar() ,可以使窗口停留等待,达到和 system("pause")类似的效果
getchar();