二 .C语言的数据类型 您所在的位置:网站首页 在c语言中int的范围 二 .C语言的数据类型

二 .C语言的数据类型

2023-07-11 13:43| 来源: 网络整理| 查看: 265

C语言提供了多种数据类型,可以用于存储不同类型的数据。以下是C语言中常用的一些数据类型:

   什么是数据?        

有用的信息称为数据

1. 基本数据类型:

   - int:用于表示整数类型,通常为32位,4个字节。    - char:用于表示单个字符,一个字节。    - float:用于表示单精度浮点数,通常为32位,4个字节。    - double:用于表示双精度浮点数,通常为64位,8个字节。    - void:表示空类型,用于表示无返回值或不具有特定类型的指针。

2. 修饰符类型:

   - short:用于表示短整数类型,通常为16位,2个字节。    - long:用于表示长整数类型,通常为32位,4个字节。    - signed:用于表示带符号整数类型。    - unsigned:用于表示无符号整数类型。

3. 复合数据类型:

   - 数组:用于存储相同类型的多个元素。    - 结构体:用于组合多个不同类型的数据。    - 联合:用于在同一内存空间存储不同类型的数据。    - 枚举:用于定义一组具有命名值的整数常量。

4. 指针类型:用于存储内存地址。

   - int*:指向整数类型的指针。    - char*:指向字符类型的指针。    - void*:用于表示未指定类型的指针。

这仅是C语言中一些常用的数据类型。可以通过使用这些数据类型来定义变量、函数参数和返回类型,并根据需要对它们进行操作和处理。

计算机内部的数据类型

- 字节(byte B):计算机存储容量的一种单位 - 比特位(bit) :二进制数,cpu计算的基本单位 - 二进制数 0 1 - 1字节 = 8比特位(bit)  - 1个千字节(KB) = 1024字节  - 1M = 1024KB  - 1G = 1024M  - 1T = 1024G  

1.整型

在C语言中,整型(Integer)是一种用于表示整数数值的数据类型。C语言提供了多种整型数据类型,具体选择哪个整型类型取决于所需的数值范围和内存占用,64位系统典型的大小是4字节(VS code软件是32位的 。

以下是C语言中常见的整型数据类型:

int:用于表示普通的整数类型,通常为32位

short:用来缩短整型变量的尺寸,减少取值范围并节省内存,称为整型。

long:用来增长整型变量的尺寸,增大取值范围并占用更多的内存,称为长整型

long long:用来增长整型变量的尺寸,增大取值范围并占用更多的内存,称为长长整型

unsigned:用来去除整型变量的符号位,使得整型变量只能表达非负整数

int a;//整形 short int a; // 短整型 %hd half表示一半的意思 long int b; // 长整型 %ld long long int c; // 长长整型 %lld unsigned int e; // 无符号整型 %u unsigned short int f; // 无符号短整型 %hu unsigned long int g; // 无符号长整型 %lu unsigned long long int h; // 无符号长长整型 %llu

使用整型修饰符后,关键字int可以省略:

int a;//整形 short a; // 短整型 long b; // 长整型 long long c; // 长长整型 unsigned e; // 无符号整型 unsigned short f; // 无符号短整型 unsigned long g; // 无符号长整型 unsigned long long h; // 无符号长长整型 格式控制符

int 整型:%d

unsigned int 无符号整型 : %u

short整型:%hd,h代表half,即一半的存储字节

long整型:%ld

long long整型:%lld

显示不同进制的前缀 : %#o(八进制)、%#x(十六进制)

符号位:

有符号的整型数据,首位为符号位,0表示正数,1表示负数。

无符号的整型数据,没有符号

demo #include int main(int argc, char const *argv[]) { // 申请2个字节的空间,并取名为a,俗称定义变量a // 空间a的内容为随机数 // a空间只能存放整数 // a空间存放的最大值为2字节的数据 short int a; // 在同一个作用域({})下,不能出现两个同名的变量名 //short int a; a = 10; // 将10存放到空间a里面 // 申请空间并将100放到里面 // 即定义变量并初始化 short b = 100; printf("%hd\n",b);//h的意思为half即int 的一半(这样做节省空间) /* h的意思为half即int 的一半(unsigned是无符号的 所以只能是正数,如果ub输入负数则发生数据溢出,以后会说) */ unsigned short ub = 200; printf("%hu\n",ub); /* char类型只有一个字节,而%d输出4个字节, 所以hhd是一半的一半即一个字节 */ char c = -15; printf("c = %hhd\n",c); unsigned char uc = 15; printf("%hhu\n",c); int d = -1024; printf("%d\n",d);// %d即能表示负数也能表示正数 unsigned int ud = 1024; printf("%u\n",ud); // %u为无符号输出 long int le = 1000L; // L表示1000为长整型 printf("%ld\n",le); long long int lle = 100000LL; printf("%lld\n",lle); // LL表示100000为长长整型 float f = 3.14; printf("%f\n",f); // 浮点型 double lf = 3.1415; printf("%lf\n",lf); // 双精度浮点型 // 在32位机里面,此类型越界无效(即最大值超过2^32) long double llf = 3.1415926; printf("%Lf\n",llf); int number = 10; printf("%#o\n",number);// 八进制输出 printf("%#x\n",number);// 十六进制输出 return 0; } 表格:C语言中全部的数据类型及它的取值范围,取值范围计算过程,以表格的形式呈现出来

unsigned char                      0~255                    (1111 1111)(0~2^8-1) char                                     -128... + 127          (0111 1111)

short                                    -32768~32767 unsigned short                     0~65535                (1111 1111 1111 1111) 2^16-1 unsigned int                         0... 2^32-1             4294967295

取值范围的计算过程如下:

对于带符号整数类型,范围计算基于补码表示法。一般而言,对于一个 n(n为bit,1字节8bit) 位的带符号整数类型,其范围可以计算如下:

最小值:-2^(n-1) 最大值:2^(n-1)-1

无符号整数类型的范围计算方式是将所有位都用于非负数部分,因此其范围计算如下:

最小值:0 最大值:2^n-1

编码形式

把一个整数转换为二进制的数

55=(0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0011 0111)

-55 = (1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1100 1001)

二进制的数在考虑正负中,首位数字为符号位,0为+,1为-,且符号位不参与运算

补码

正数的补码不变(还是正数本身),负数的补码绝对值取反加一

衍生——计算机数据溢出问题

1.当编译器以整型输出的时候%d,是以补码还原的方式解读 2.当cpu将数据进行运算的时候,直接以内存中存放的方式来运行,也就是以补码的方式参与运算 3.%u输出的时候,值区域范围:0-4294967295(有符号转为无符号的时候)(2^32) 4.%hhu方式打印,值域范围:0-255 (2^8)

 

解析:int a的取值范围是0—255,不发生溢出

           char b的取值范围是-128—+127,输入255发生溢出,255对应-1号位,所以%d输出-1

          而在u的取值范围内-1对应0的后一位即最大值(4294967295),所以输出4294967295

 

 解析:unsigned short a的取值范围为0—65535,a赋值-1发生溢出,

            int b=a;不发生溢出

 作业题 //作业题 unsigned char a = 257; char b = 129; printf("a:%hhu\n",a);//half // 练习 printf("b:%hhd\n",b); // 作业1 printf("b:%hhu\n",b); //先算出%hhd在绝对值取反加一就是%hhu(注意借位问题)

 进制与进制转换

进制:源码中可以使用八进制、十进制或者十六进制,但实际数据中一律是二进制

十进制(默认,0~9),比如1234 %d %u

八进制(0~7),比如013 %#o

十六进制(0~15),比如0x6FF0A %#x

进制转换

十进制--》二进制、八进制、十六进制

十进制转二进制除2取余数,倒序排序,高位补0

 十进制转八进制;12(10)=14(8).

 二进制八进制十六进制转十进制

 最小二乘法(小数转二进制 ) 

2.浮点型

概念:用来表达实数(有理数和无理数)的数据类型

  分类:

单精度浮点型(float),典型尺寸是4字节                    

双精度浮点型(double),典型尺寸是8字节

长双精度浮点型(long double),典型尺寸是16字节

占用内存越多,能表达的精度越高

float f1;//单精度 double f2;//双精度 long double f3;//长双精度

作业题

3.字符 char ch1 = 'a'; // 'a'是字符常量,代表字母a char ch2 = '\n'; // '\n'是不可见字符常量,代表回车 ASCII码表

char a = 'a';// 存储在内存中是97 char b = '1';// 存储在内存中是49 char c1 = 20; char c2 = c1 + 'a'; // 等价于char c2 = 20+97; printf("%c\n",c2); // 以字符形式输出117,即 'u' printf("%d\n",c2); // 以整型形式输出117 // 小写字符转大写字符 ' ' = 32 char a7 = 'b'- ' '; printf("%c\n",a7); 转义字符

转义字符是在编程中用于表示特殊字符的一种机制。在C语言中,你可以使用转义字符来表示不能直接键入或显示的字符,或者在字符串中插入特殊的字符序列。

以下是C语言中常用的一些转义字符:

- \\:反斜杠 - \':单引号 - \":双引号 - \n:换行 - \r:回车 - \t:制表符(tab键) - \b:退格(Backspace) - \f`:换页 - \a:响铃(需要电脑有蜂鸣器) - \0:空字符(字符串结束标志)

-\ddd:表示八进制数,打印出来的是该数字对应的ascii码

八进制数ddd范围在  0 - 7,且八进制数转化为十进制的数不能超过127,否则乱码(ASCII码就只有128位,十六进制同理)

-\xhh:表示十六进制 打印出来的是该数字对应的ascii码

使用转义字符的方式是在需要表示特殊字符的地方,将其前面加上反斜杠`\`。

以下是一些示例:  

printf("Hello, World!\n");    // 换行 printf("This is a \"quote\".");    // 引号 printf("C:\\path\\to\\file.txt");   // 路径中的反斜杠 printf("Tab\tSeparated");    // 制表符 printf("Beep\aBeep\a");    // 响铃 printf("Line1\rLine2");    // 回车 printf("Backspace\b");    // 退格 printf("Form feed\f");    // 换页 printf("Null character\0");    // 空字符(字符串结束标志) printf("%c\n",'\102'); // 八进制 printf("%c\n",'\x41'); //A printf("efg\a"); printf("abcd\b"); printf("efg\n"); // 转义字符---八进制'\xxx',注意x的大小为0-7 // 注意转义字符的范围一定是127以内,不要超出char类型范围 int a = '\102'; printf("%o,%d,%c\n",a,a,a); //printf("%o\n",'\109');// 不合法,单个字符是0-7 // 转义字符---十六进制'\xhh',注意x的大小为0-F int b = '\x4f'; printf("%x,%d,%c",b,b,b); 注意

在使用转义字符时,一定要将其放在合适的上下文中,以确保能够正确解释和显示特殊字符的含义。

4.字符串 // 字符串的定义方式有两种:指针和数组 char *s1 = "abcd"; // 使用字符指针来表示字符串 char s2[]= "abcd"; // 使用字符数组来表示字符串 // 注意,使用数组来定义字符串时,方括号[]里面的数字可以省略 // 不省略也可以,但必须必字符串实际占用的内存字节数要大,比如: char s3[] = "apple"; char a = 'a' //就是单个字符(一个字节) char *a="abcd" //"abcd"有五个字节即 "abcd\0",'\0'为字符串结束标志字符 "funny story"

 字符串以"\0"结尾且"\0"占用空间

5.布尔类型数据

概念:布尔型数据只有真、假两种取值,非零为真,零和false为假。

语法: bool a = 1; // 逻辑真,此处1可以取其他任何非零数值 bool b = 0; // 逻辑假 c 备注: bool类型非0即为真,0和false为假,且bool的头文件是stdbool.h #include #include int main(int argc, char const *argv[]) { // 在c语言,非0为真,0为假 // bool为布尔类型,一般只有两种状态 true:真 false:假 // 作用是作为标志位,增加代码的可读性 bool flage = true; bool flage1 = false; printf("%d\n",flage1); //0 //enum 为枚举类型 enum color{yellow=10,gree,blue,red}; printf("%d",yellow); //10 printf("%d",red); //13 return 0; }

6.常量与变量

概念:不可改变的内存称为常量,可以改变的内存称为变量

int a = 100; // a是变量,而100是常量 float f = 3.14; // f是变量,而3.14是常量 char s[] = "abcd"; // s是变量,"abcd"是常量

7.标准输入

概念:键盘是系统的标准输入设备,从键盘中输入数据被称为标准输入

scanf(); // 格式化输入函数 fgets(); // 字符串输入函数 int a; float f; scanf("%d", &a); // 从键盘输入一个整型,放入指定的内存地址 &a 中 scanf("%f", &f); // 从键盘输入一个浮点数,放入指定的内存地址 &f 中 // 从键盘依次输入一个整型和一个浮点型数据,用空白符隔开 scanf("%d%f", &a, &f); char c; char s[10]; // 从键盘输入一个字符,放入指定的内存地址 &f 中 scanf("%c", &c); // 从键盘输入一个单词,放入指定的数组 s 中(注意不是&s) scanf("%s", s ); //用s就找不到地址 fgets(s, 10, stdin); // 从键盘输入一行字符串,放入数组 s 中 注意1:

scanf() 与 printf() 不同,scanf() 的格式控制串不可乱写,尤其是结尾处的 \n

用户必须完全按照 scanf() 中描述的输入格式控制串来输入数据,否则将出错。

// 此处输入时必须带逗号 scanf("%d,%d", &a, &b); // 此处必须先输入a=,然后才能输入整数 scanf("a=%d", &a); // 此处结束输入时按下的回车符将被scanf()误以为格式控制符,无法正常结束输入 scanf("%d\n", &a); 注意2:

scanf() 的返回值,代表成功从键盘读取的数据的个数

无法匹配 scanf() 指定格式的数据,将被遗留在输入缓冲区中,不会消失

// scanf() 试图从键盘读取两个整数 // 返回值 n 代表成功读取的个数,比如: // 输入100 200,则 n 将等于2 // 输入100 abc,则 n 将等于1 // 输入abc xyz,则 n 将等于0;输入abc 200,n也将等于0 /* 如果成功读取一个整数,则n等于1;如果成功读取两个整数, 则n等于2;如果无法按照预期的格式读取整数,则n等于0 */ int n = scanf("%d%d", &a, &b); // 根据 scanf() 的返回值,判断用户是否输入了正确的格式 while(n != 2) { // 需要清空缓冲区并提示用户重新输入 char s[50]; fgets(s, 50, stdin); printf("请重新输入两个整数\n"); n = scanf("%d%d", &a, &b); } demo #include int main() { printf("input msg : "); int a; float b; char c; // &a获取a的地址 // scanf不要添加任何除了格式化输出的字符%外的所有任何字符 //scanf("%c,%d\n,%f",&c,&a,&b); // 取到缓冲区的数据,返回实际取到的内容的个数 // 取不到缓冲区的数据,返回0 int n = scanf("%d",&a);//为判断,如果scanf("%d",&a)拿取成功则n为1,失败则为0 // 用getchar()将输入缓冲区的内容取走(缓冲区有什么就拿什么), int getMsg = getchar(); printf("n : %d\n",n); printf("get msg : %d\n",getMsg);//以转义字符的形式输出 scanf("%f\n",&b); scanf("%c",&c); printf("show msg : %d,%f,%c\n",a,b,c); return 0; } /* 输入a=1时, scanf("%d",&a)拿1, n判断为真(1), 然后回车int getMsg = getchar()拿到\t(回车), printf("n : %d\n",n)输出1, getMsg输出\t(回车)的ASCII值为10, 然后继续输入scanf("%f\n",&b)为3.14, 继续输入scanf("%c",&c)为c, 最后的结果为1,3.140000,c */ /* 输入a=q时, scanf("%d",&a)拿空值(0), n判断为假(0), int getMsg = getchar()拿到q, printf("n : %d\n",n)输出0, getMsg输出q的ASCII值为113, 然后继续输入scanf("%f\n",&b)为3.14, 继续输入scanf("%c",&c)为c, 最后的结果为0,3.140000,c */ 8.类型转换

概念:不一致但相互兼容的数据类型,在同一表达式中将会发生类型转换。

转换模式:

隐式转换:系统按照隐式规则自动进行的转换

强制转换:用户显式自定义进行的转换

隐式规则:从小类型向大类型转换,目的是保证不丢失表达式中数据的精度

隐式转换示例 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; int d = (int)c; float x = a + b - (int)c; // 在该表达式中a隐式自动转换为int,c被强制转为int

注意:不管是隐式转换,还是强制转换,变换的都是操作数在运算过程中的类型,是临时的,操作数本身的类型不会改变,也无法改变。

数据类型的本质

概念:各种不同的数据类型,本质上是用户与系统对某一块内存数据的解释方式的约定。

推论:

类型转换,实际上是对先前定义时候的约定,做了一个临时的打破。

理论上,可以对任意的数据做任意的类型转换,但转换之后的数据不一定有意义。

整型数据尺寸

概念:整型数据尺寸是指某种整型数据所占用内存空间的大小

C语言标准并未规定整型数据的具体大小,只规定了相互之间的 “ 相对大小 ” ,比如:

short 不可比 int 长

long 不可比 int 短

long 型数据长度等于系统字长(32位操作系统(2^32)long是占用4字节,64位操作系统(2^64)long 是占用8字节)(考试会考)

系统字长:CPU 一次处理的数据长度,称为字长。比如32位系统、64位系统。

典型尺寸:

char 占用1个字节

short 占用2个字节

int 在16位系统中占用2个字节,在32位和64位系统中一般都占用4个字节

long 的尺寸等于系统字长

long long 在32位系统中一般占用4个字节,在64位系统中一般占用8个字节

存在问题:

同样的代码,放在不同的系统中,可能会由于数据尺寸发生变化而无法正常运行。

因此,系统标准整型数据类型,是不可移植的,这个问题在底层代码中尤为突出。

可移植性整型

概念:不管放到什么系统,尺寸保持不变的整型数据,称为可移植性整型(一个整形数据(类型)在所有系统下都不报错)

关键:typedef

typedef int int32_t;  // 将类型 int 取个别名,称为 int32_t typedef long int64_t; // 将类型 long 取个别名,称为 int64_t

思路:

为所有的系统提供一组固定的、能反应数据尺寸的、统一的可移植性整型名称

在不同的系统中,为这些可移植性整型提供对应的 typedef 语句

系统预定义的可移植性整型:

int8_t int16_t int32_t int64_t ​ uint8_t uint16_t uint32_t uint64_t //练习:自定义以上数据类型 pid_t time_t size_t demo: #include ​ // 给变量取别名称为可移植数据类型 typedef char int8_t; typedef unsigned char uint8_t; typedef short int16_t; typedef unsigned short uint16_t; typedef int int32_t; typedef unsigned int uint32_t; ​ ​ int main(int argc, char const *argv[]) {    int8_t a = 'p';    printf("%c\n",a);    return 0; } ​ ​ 提问: 有时候我们需要使用 int32_t 类型变量代替 int 类型变量的原因是什么?

int是系统基本的数据类型,其长度在不同平台下的大小尺寸是有区别的,为了使同一份代码能够在不同的操作系统下面运行,并且尺寸不发生改变,一般使用类似于int32_t这样的可移植类型来定义数据,这些类型是不同平台下对基本数据类型的封装,然后统一发布,这些移植的数据类型一般是放在头文件中,比如/usr/include/stdin.h



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有