整形
-
概念:表达整数(非小数)类型的数据
- 语法:
int a = 123; //定义了一个专门用来存储整数的变量a
-
需要注意的地方:
1. int 的本意是integer, 即整数的意思
2. int a 代表在内存中开辟一块小区域,称为a,用来存放整数,a一般被称为变量。
3.变量a所占内存大小,在不同的系统中是不一样的,64、32位系统典型的大小是4个字节
4.变量a有固定的大小,因此也有取值范围:-2147483648到2147483647
-
整形修饰符:
short:用来缩短整形变量的尺寸,减少取值范围并节省内存,称为短整型(整形的一半 2个字节)
long: 用来增长整型变量的尺寸,增大取值范围并占用更多内存,称为长整形(long的大小是等于系统字长64位系统下long=8字节 32位系统long=4字节)
long long : 用来增长整形变量的尺寸,增大取值范围并占用更多的内存,称为长长整形(在64位或32位系统中都是8字节)
unsigned: 用来去除整形变量的符号位,使得整形变量只能表达非负整数
如何使用整形数据
#include <stdio.h>
int main(int argc , char const *argv[])
{
int a = 123; //123是一个十进制的整形数据
int b = 0x123F; //0x123F 是一个十六进制的数据 其中0x表示十六进制
int c = 0123; // 0123是一个八进制的整形数据 其中0表示八进制
/*
%d --> 对应的是十进制的整形
%x --> 对应的是十六进制的整形 , 小写 x 则输出十六进制的字母的时候会使用小写字母
%X --> 对应的是十六进制的整形 , 大写 X 则输出十六进制的字母
%#x --> 对应的是十六进制的整形 , #则会把十六进制的前缀一并输出
%o --> 对应的是八进制的整形
%#o --> 对应的是八进制的整形 , #则会把八进制的前缀一并输出
*/
printf("a:%d b:%d c:$d\n" , a , b , c ); //把所有数据转化为%d 十进制的整形进行输出
printf("a:%d b:%#x c:%#o\n" , a , b , c); // 通过使用 不同的格式控制符(%d %x %o..) 则可
// 以使用不同的进制输出
}
short int a ; // 短整型
long int b ; // 长整型
long long int c ; //长长整形
unsigned int e ; // 无符号整形
unsigned short int f; // 无符号短整型
unsigned long int g; // 无符号长整形
unsigned long long int h //无符号长长整形
- 使用整形修饰符后 , 关键字 int 可以被省略:
short a ; // 短整型
long b ; // 长整型
long long c ; // 长长整形
unsigned e; //无符号整形
unsigned short f; //无符号短整型
unsigned long g; //无符号长整形
unsigned long long h ; // 无符号长长整形
sizeof运算符
sizeof看起来像是一个函数 ,但实际上他是一个运算符。
该变量类型或变量的大小 = sizeof(变量类型 、名字);
符号位 :
- 对于有符号的整型数据,首位(最高位)为符号位,0表示正数,1表示负数。(100,-100)
- 无符号的整形数据,没有符号位。
编码形式:
- 原码:正数直接使用二进制来表达,比如short a=6 ,0000 0000 0000 0110; 更改 a 的值a = -6; 此时 a 的原码就是 1000 0000 0000 0110。
通俗的理解,原码就是一个整数本来的二进制形式。
-
反码:原码取反
-
补码:原码取反+1,也就是反码+1(原码取反+1 == 补码+1)。符号位不变 如负数 -6的补码为 1111 1111 1111 1010 ,注意负数的补码在取反加一的时候,符号位是不动(保持是1)
注意:以上都是针对负数的,正数的原码、反码、补码都是一样的
- 溢出 :超过数据所能表达的范围,称为溢出,就像汽车里程表,最大值和最小值是相邻的
- 进制: 源码中(C语言代码)可以使用八进制、十进制或十六进制,但实际数据内存中一律是二进制。
- 十进制(默认),比如1099
- 八进制,比如013
- 十六进制,比如0x6FF0A
- 格式控制符
- int 整形:%d
- short 整形:%hd, h代表half,即一半的存储字节
- long 整形 :%ld
- long long整形:%lld
- 显示不同进制的前缀%#o、 %#x
浮点型(实型)
- 概念:用来表达实数的数据类型
- 分类:
- 单精度浮点型(float),典型尺寸是4字节
- 双精度浮点型(double),典型尺寸是8字节
- 长双精度浮点型(long double), 典型尺寸是16字节
- 占用内存越多,能表达的精度越高
- 浮点型是通过一定规则计算得到的二进制编码,因此计算的过程中一定可能会导致数据的不准确。
float f1; // 单精度
double f2; //双精度
long double f3; //长双精度
字符
char ch1 = 'a ' ; // 'a'是字符常量,代表字母a
char ch2 = '\n' ; // '\n'是不可见字符常量,代表回车
计算机存储的都是1和0(二进制),因此各种字符都必须被映射为某个数字才能存储到计算机中,因此字符型的数据实际是一个单字节的整形,这中映射关系形成的表为ASCll码表。
man ascii //在linux下用这个命令可以查询ascii码表
#include <stdio.h>
int main(int argc , char const *argv[])
{
char ch1 = 'a' ; //使用 ' a ' 表示一个字符常量 a --> 97
char ch2 = 98 ;
char ch3 = '9' ; //这是一个字符9因此他所对应的ASCII 是57存储到内存 ch3中
printf("%c\n" , ch1); // %c 是一个格式控制符, 用于输出字符类型的数据
printf("%o\n" , ch1); // 以八进制的形式输出字符 a 的ASCII 的值
printf("%d\n" , ch1); // 以整形的形式输出字符 a 的 ASCII的值
printf("%x\n" , ch1); // 以十六进制的形式输出字符 a 的 ASCII的值
printf("%c\n" , ch2); // printf("%d\n" , ch1); // 以整形的形式输出字符 a 的 ASCII的值
printf("%d\n" , ch2); // printf("%d\n" , ch1); // 以整形的形式输出字符 a 的 ASCII的值
printf("%c\n" , ch3); // 输出得到字符 9
printf("%d\n" , ch3); // 输出得到9所对应的ASCII值
return 0;
}
字符本质上就是一个单字节的整形,支持整形所有的运算
char c1 = 20 ;
char c2 = c1 + 'a' ; //等价于char c2 = 20 + 97 ;
printf("%c\n" , c2); //以字符形式输出 117,即 'u’
printf("%d\n" , c2); //以整形形式输出117
字符串
- 定义
// 字符串的定义方式有两种: 指针和数组
char *s1 = "abcd" ; //使用字符指针来表示字符串
char s2[ ] = "abcd" ; //使用字符数组来表示字符串
// 注意,使用数组来定义字符串时,方括号[ ]里面的数字可以省略
// 不省略也可以,但必须比字符串实际占用的内存字节数要大,比如:
char s3[ ] = "apple" ;
- 在内存中的存储
- 在内存中实际上是多个连续字符的组合
- 在任何字符串都以一个'\0'作为结束标记,例如:“funny story”的内存如下
#include <stdio.h>
int main(int argc , char const *argv[ ] )
{
char * str1 = "Hello world" ; //定义一个字符串指针【指向】“Hello world" 该数据不可 //以被修改 (因为数据被存放在常量区)
char str2[ ] = "Hello world"; //定义一个数组,用于【存储】“Hello world” 该数据可修改(因为数据被存放在栈区)
printf("str1:%s\n" , str1) ;
printf("str2:%s\n" , str2) ;
printf("str1:%p\n , str1); //%p 是一个格式控制符,用于输出地址类型的数据
printf("str2:%p\n , str2); //%p 是一个格式控制符,用于输出地址类型的数据
return 0 ;
}
通过地址我们不难看出,str1和str2存放的数据地址是不同的,因为str1的指针指向常量区(只读区域)数据,str2指向的是栈区。
布尔数据类型
- 概念:布尔型数据只有真、假两种值,非零为真,零为假。
- 语法:
bool a = 1; //逻辑真。此处1可以取其他任何非零数值
bool b = 0; //逻辑假
- 注意
- 逻辑真除了1之外,其他任何非零数值都表示逻辑真,等价于1。
- true与false实际上就是两个值为1以及0的宏,因。
- bool类型以及布尔类型的变量都是1个字节
- 在使用bool类型的不管赋值是多少 bool b = -199; 实际上对变量b进行访问的时候他也只是1
- 使用布尔型bool定义变量时需要包含系统头文件stdbool.h。
- 布尔型数据常用与逻辑判断、循环控制等场合。
bool a = 0;
bool b = -199;
bool c = true ; // true -> 真 1
bool d = false ; // false -> 假 0
printf("a:%d\n" , a) ; // 0
printf("b:%d\n" , b) ; // 1
printf("c:%d\n" , c) ; // 1
printf("d:%d\n" , d) ; // 0
printf("true :%d\n" , true ) ; // 1
printf("false:%d\n" , false) ; // 0
printf("sizeof(bool):%ld\n" , sizeof(bool) ) ; // 1
printf("sizeof(a):%ld\n" , sizeof(a)); // 1
printf("sizeof(true):%ld\n" , sizeof(true)); // 4
printf("sizeof(false):%ld\n" , sizeof(false)); // 4
ps:
在C语言中,true是一个宏,其定义在stdbool.h头文件中,它代表的是布尔类型,然而,在C语言的标准中,并没有直接规定布尔类型的大小。这可能会因不同的实现而有所不同。在一些常见的C语言实现中(例如GCC和Clang),true被定义为整数类型,并且通常被实现为int类型的值,这使得sizeof(true) == sizeof(int)。 在这种情况下,sizeof(true)的值通常是4字节(32位系统)或8字节(64位系统)。
常量与变量
- 概念:不可改变的内存称为常量,可以改变的内存称为变量
- 举例
int a =100; //a是变量 , 而100是常量
float f =3.14 //f是变量 , 而3.14是常量
char s[ ] = "abcd" ; //s是变量, “abcd”是常量
- 常量的类型
常量举例 | 说明 | 类型 |
100 | 整型 | int |
100L | 长整型 | long |
100LL | 长长整型 | long long |
100ULL | 无符号长长整型 | unsigned long long |
3.14 | 双精度浮点型 | double |
3.14L | 长双精度浮点型 | long double |
‘a’ | 字符型(单引号) | char |
“abcd” | 字符指针(字符串双引号) | char * |
标准输入
- 概念:键盘是系统的标准输入设备,从键盘中输入数据被称为标准输入
- 相关函数:
scanf () ; //格式化输入函数
fegts () ; //字符串输入函数
int a ;
float f;
scanf("%d" , &a); //从键盘输入一个整形,放入指定的内存地址&a中
scanf("%f" , &f ); //从键盘输入一个浮点数 ,放入指定内存地址&f中
scanf("%d%f" , &a , &f); //从键盘依次输入一个整形和一个浮点型数据,用空白符隔开
char c;
char s[10];
scanf("%c" , &c) ; //从键盘输入一个字符,放入指定的内存地址&c中
scanf("%s" , s) ; //从键盘输入一个单词,放入指定的数组s中(注意不是&s)
fgets(s , 10 , stdin) ; //从键盘输入一行字符串,放入数组s中
#include <stdio.h>
int main(int argc , char const*argv[ ])
{
//从标准输入(键盘)文件中读取指格式的数据,并把数据存入到指定的位置
//%d是一个整形的格式控制符
//&在当前语境中表示取地址
int a = 999;
float f ;
printf("a:%d...\n" , a ) ;
int ret_val = scanf("%d" , &a ) ;
//scanf函数他默认回去扫描键盘文件并从中得到所要数据
//而键盘(标准输入)文件他默认是阻塞的状态
//阻塞 -> 当没有满足条件的数据情况下会导致进入挂起状态(暂停运行)
printf("成功获得%d项数据....\n" ,ret_val )
printf("buf:%s\n" , buf) ;
return 0 ;
}
注意:
- 在使用以上代码的时候如果第一次输入的数据并不符合scanf中要求的类型(比如要求输入%d整形,但是实际输入一个字符串“abc”),scanf则会直接返回失败,而且数据“abc”会直接被scanf留在缓冲区中,则有可能对后面的数据获取造成影响。
- 该函数的返回值是成功匹配到的项目数量,失败时返回0或-1 ,并会把不匹配的数据留在缓冲区。
- 可以配置getchar进行缓冲区的清理 while(getchar() != '\n' ) ;
- 注意格式控制符的问题
//在scanf中一定要慎重添加\n
//注意参数中【格式控制符】: "%d,%c” 在输入数据的时候就需要严格匹配123 , h , 不 然会输入失败。
int ret_val = scanf("%d" ,%c" ,&a ,&c) ;
如何清空标准输入的缓冲区:
getchar() // 默认从标准输入缓冲区获取一个字符
while(1)
{
printf("%d\n" , getchar() );
fgets从指定文件中获取一行(\n)数据:
函数原型 :
char *fgets(char *s ,int size , FILE *stream);
参数分析:
s --> 用于存储获得的数据的缓冲区入口地址
size --> 缓冲区的大小(用于控制获得的数量避免出现段错误【非法访问】)
stream --> 指定从该文件中获取数据
返回值:
成功 返回第一个参数 s
失败 返回 NULL
注意:
- scanf 与 fgets的区别:
- scanf 可以获取任意的基础数据类型, fgets则只能获取字符串类型
- scanf 的结束条件有 空格、TAB制表符 、回车
- fgets 的结束条件有 回车、 大小控制
- 如果都是获取字符串数据则建议使用fgets ,他可以控制获取的长度避免一些不必要的段错误
类型转换
- 概念:不一致但相互兼容数据类型,在同一表达式中将会发生类型转换。
- 转换模式:
- 隐式转换:系统按照隐式规则自动进行转换
- 强制转换:用户显示自定义进行转换
- 隐式规则:从小类型向大类型转换(低精度->高精度),目的是保证不丢失表达式中数据精度
隐式传唤示例代码
char a = 'a' ;
int b = 12 ;
float c =3.14;
float x =a +b -c; //在该表达式中将发生隐式转换 , 所有操作数被提升float
//数据类型的转换只会发生在运算表达式中,并不影响数据本身的类型(数据的类型从定义之初就已经确定无法被改变)
- 强制转换:用户强行将某类数据转化为另一种类型,此过程可能丢失精度
char a = 'a' ;
int b = 12 ;
float c =3.14 ;
float x =a + b - (int)c ; //在该表达式中a隐式自动转化为int , c被强制转化为int
不管是隐式转换,还是强制转化,变换的都是操作数在运算过程中的类型,是临时的,操作数本身的类型不会改变,也无法改变。
数据类型的本质
- 概念:各种不同的数据类型,本质上是用户与系统对某一块内存的数据(二进制)的解释方式的约定。
- 推论:
- 类型转换,实际上是对先前定义的时候的约定,做了一个临时的打破。
- 理论上,可以对任意的数据做任意的类型转化,但转化之后的数据解释不一定有意义。
- 对于进程而言任何的数据都是一堆二进制编码,使用不同的规则来解析二进制编码都是可以的,只不过不一定有意义
12345678911 电话
12345678911 余额 //这个无意义
12345678911 寿命 //这个无意义
整形数据尺寸
- 概念:整形数据尺寸是指某种整形数据所占用内存空间的大小
- C语言标准并未规定整形数据的具体大小,之规定了相互之间的“相对大小”,比如:
- short 不可比 int 长 在(16位系统中short = int = 2字节 64位系统 int > short)
- long 不可比 int 短 (32系统long = int 64系统long > int)
- long型数据长度等于系统字长
- 系统字长: CPU一次处理的数据长度,称为字长。比如32位系统、64位系统。
- 典型尺寸
- char 占用1个字节
- short 占用2个字节
- long long在32位系统中一般占用8个字节,在64位系统中一般占用8个字节
- 存在问题
- 同样的代码,放在不同的系统中,可能会由于数据尺寸发生变化而无法正常运行。
- 因此,系统标准整形数据类型,是不可移植的,这个问题在底层代码中尤为突出
u_32t
u_16t
s_64t
可移植性整形
- 概念: 不管放到什么系统,尺寸保持不变的整形数据,称为可移植性整型
- 关键: typedef给变量类型取别名
typedef int int32_t ; // 将类型int 取个别名 ,称位int32_t
typedef int int32_t ; // 将类型int 取个别名 ,称位int64_t
- 思路
- 为所有系统提供一组固定的、能反应数据尺寸的、统一的可移植性整型名称
- 在不同的系统中,为这些可移植性整型提供对应的typedef语句
- 系统预定义的可移植性整形:
下表列举了C语言中常用的格式控制符,以及它们对应的数据类型和描述:
格式控制符 | 数据类型 | 描述 |
%d | int | 十进制有符号整数 |
%u | unsigned int | 十进制无符号整数 |
%o | unsigned int | 八进制无符号整数 |
%x | unsigned int | 十六进制无符号整数,使用小写字母 |
%X | unsigned int | 十六进制无符号整数,使用大写字母 |
%f | float | 浮点数 |
%lf | double | 双精度浮点数 |
%c | char | 单个字符 |
%s | char* | 字符串 |
%p | void* | 指针地址 |
%n | int* | 存放已经输出字符数的变量指针 |
%% | N/A | 输出 % 符号 |
其中,有些格式控制符还可以附加一些修饰符,例如:
修饰符 | 描述 |
- | 左对齐输出 |
+ | 强制输出带有符号数的正负号 |
空格 | 输出值为正时冠以空格,值为负时印以负号 |
# | 使用其他进制输出值时,增加前缀 0x 或 0 |
0 | 数字前面填充 0 而非空格 |
.精度 | 指定浮点数精度,或字符串输出的最大字符数 |
例如,可以使用格式控制符 "%.2f" 输出一个保留两位小数的浮点数。此外,还可以使用 "%3d" 控制输出的整数位数为 3。