1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 【C语言】变量和常量 数据类型 进制转换 数据存储

【C语言】变量和常量 数据类型 进制转换 数据存储

时间:2021-08-01 13:37:57

相关推荐

【C语言】变量和常量 数据类型 进制转换 数据存储

目录

1. 变量

1.1 变量的分类

1.1.1 局部变量

1.1.2 全局变量

1.2变量的使用

1.3变量的作用域和生命周期

1.3.1 作用域

1.3.2 生命周期

2. 常量

2.1字面常量

2.2 const修饰的常变量

2.3#define定义的标识符常量

2.4枚举常量

3. 数据类型

3.1整数类型

3.2浮点数类型

3.3 构造类型

3.4指针类型

3.5空类型

3.6数据类型的大小

4. 进制转换

4.1 二进制数、八进制数、十六进制数转换为十进制数

4.2 十进制数转换为二进制数、八进制数、十六进制数

4.3 二进制数和十六进制数的相互转换

4.4 使用电脑计算器进行进制转换

5.整数在内存中的存储

5.1无符号整数的表示方法

5.2有符号整数的表示方法

5.3大小端模式

6.整型截断、整型提升和算数转换

6.1整型截断

6.2整型提升

6.2.1 负数的整型提升

6.2.2 正数的整型提升

6.2.3 无符号数的整型提升

6.3算数转换

6.4练习题

6.4.1

6.4.2

6.4.3

6.4.4

6.4.5

6.4.6

6.4.7

7.浮点数在内存中的存储

7.1浮点数的存储规则

7.2对于M的规定

7.3对于E的规定

7.3.1E不全为0或不全为1

7.3.2 E全为0

7.3.3 E全为1

7.4练习题

1. 变量

1.1 变量的分类

1.1.1 局部变量

局部变量是{}内部定义的变量。局部变量不初始化默认为随机值。

1.1.2 全局变量

全局变量是{}外部定义的变量。全局变量不初始化默认为0。

当全局变量和局部变量名字相同的情况下局部优先,但是建议不要将全局和局部变量的名字写成一样的。

#include <stdio.h>int a = 100;//全局变量int main(){int a = 10;//局部变量printf("a=%d\n", a);//a=10return 0;}

#include <stdio.h>int x = 5, y = 7;//全局变量void swap(){int z;z = x;x = y;y = z;} int main(){int x = 3, y = 8;//局部变量swap();printf("%d,%d\n", x, y);//3,8return 0;}

上面代码输出结果为3,8。swap()函数调用时用的是全局变量,主函数中定义的变量只在主函数中有效,因为主函数也是一个函数,它与其他函数是平行关系;输出语句这里,考虑局部优先的原则。

1.2变量的使用

#include <stdio.h>int main(){int num1;//声明num1 = 10;//赋值:在已生成的变量中放入数值int num2 = 20;//初始化:在生成变量的时候放入数值int a, b;//一次声明多个变量时,用逗号分隔变量名a = 5;//赋值b = 15;//赋值//计算int sum = num1 + num2;int difference = a - b;//输出printf("%d %d\n", sum, difference);//30 -10return 0;}

变量在生成的时候会被放入不确定的值。因此在声明变量时,除了有特别要求之外,一定要为其赋初始值,进行初始化。最好不要写int n;,要写成int n = 0;。

1.3变量的作用域和生命周期

1.3.1 作用域

作用域(scope)是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。

局部变量的作用域是变量所在的局部范围。全局变量的作用域是整个工程。

1.3.2 生命周期

变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段。

局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。全局变量的生命周期是:整个程序的生命周期。

static用来声明静态变量,改变变量的生命周期。

1. 修饰局部变量→静态局部变量

static修饰局部变量的时候,局部变量出了作用域不销毁。本质上,static修饰局部变量的时候,改变了变量的存储位置的;影响了变量的生命周期,生命周期变长,和程序的生命周期一样。

2. 修饰全局变量→静态全局变量

static修饰全局变量的时候,全局变量的外部链接属性就变成了内部链接属性。这个全局变量只能在本源文件内使用,不能在其他源文件内使用。

3. 修饰函数→静态函数

static修饰函数的时候,函数的外部链接属性就变成了内部链接属性。这个函数只能在本源文件内使用,不能在其他源文件内使用。

2. 常量

2.1字面常量

30; //数值常量3.14; //数值常量'w'; //字符常量"abc";//字符串常量

2.2 const修饰的常变量

const修饰的常变量,本质是变量,但是不能直接修改,有常量的属性。

const float pi = 3.14f;//这里的pi是const修饰的常变量pi = 5.14;//err

const修饰指针变量:

const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变,但是指针变量本身的内容可变。

int const* p = &n;//const int* p = &n;*p = 0;//errp = &m;//ok

const如果放在*的右边,修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变。

int* const p = &n;p = &m;//err*p = 0;//ok

2.3#define定义的标识符常量

#include <stdio.h>#define MAX 100#define STR "abcdef"int main(){printf("%d\n", MAX);//100int a = MAX;printf("%d\n", a);//100printf("%s\n", STR);//abcdefreturn 0;}

详见【C语言】程序环境和预处理_秋秋晗晗的博客-CSDN博客中3.2 宏定义。

2.4枚举常量

枚举常量默认是从0开始,依次向下递增1的。

#include <stdio.h>enum Sex{MALE,FEMALE,SECRET};int main(){printf("%d\n", MALE);//0printf("%d\n", FEMALE);//1printf("%d\n", SECRET);//2return 0;}

详见【C语言】自定义类型——结构体、枚举、联合_秋秋晗晗的博客-CSDN博客中3. 枚举。

3. 数据类型

3.1整数类型

字符的本质是ASCII码值,所以也算整数类型。

整数类型分为有符号(signed)和无符号(unsigned)。声明变量时,可以通过加上类型说明符signed或unsigned来指定其中一种数据类型。若不加类型说明符,则默认为有符号(除char外)。

int x = 0;//x是有符号整型signed int y = 0;//y是有符号整型unsigned int z = 0;//z是无符号整型

C99标准并未指定char类型是有符号还是无符号,取决于编译器。C语言编译器在limits.h头文件中以宏定义的形式定义了整数类型所能表示的数值的最小值和最大值。如果CHAR_MIN 为0,则char类型被当作无符号。

#include <stdio.h>#include <limits.h>int main(){printf("VS编译器中的char类型为");if (CHAR_MIN)printf("有符号\n");elseprintf("无符号\n");return 0;}//VS编译器中的char类型为有符号

3.2浮点数类型

3.3 构造类型

关于结构体、枚举、联合详见【C语言】自定义类型——结构体、枚举、联合_秋秋晗晗的博客-CSDN博客

3.4指针类型

int* char* float*等

3.5空类型

void

3.6数据类型的大小

数据类型的大小与操作系统和编译器有关,以下展示VS编译器中各数据类型的大小。

#include <stdio.h>int main(){printf("char %zuB\n", sizeof(char));printf("short %zuB\n", sizeof(short));printf("int %zuB\n", sizeof(int));printf("long %zuB\n", sizeof(long));printf("long long %zuB\n", sizeof(long long));printf("float %zuB\n", sizeof(float));printf("double%zuB\n", sizeof(double));printf("long double %zuB\n", sizeof(long double));printf("指针类型 %zuB\n", sizeof(int*));return 0;}

64位操作系统中:

32位操作系统中:

4. 进制转换

4.1 二进制数、八进制数、十六进制数转换为十进制数

十进制数的每一位都是10的指数幂。如,

1998 = 1×10^3 + 9×10^2 + 9×10^1 + 8×10^0

将这个思路应用于二进制数、八进制数、十六进制数,就能将这些数转换为十进制数。

二进制数101转换为十进制数:

101 = 1×2^2 + 0×2^1 + 1×2^0 = 5

八进制数123转换为十进制数:

123 = 1×8^2 + 2×8^1 + 3×8^0 = 83

十六进制数1FD转换为十进制数:

1FD = 1×16^2 + 15×16^1 + 13×16^0 = 509

4.2 十进制数转换为二进制数、八进制数、十六进制数

将这个思路应用于二进制数、八进制数、十六进制数,就能将十进制数转换为二进制数、八进制数、十六进制数。

十进制数57转换为二进制数:

111001

十进制数57转换为八进制数:

71

十进制数57转换为十六进制数:

39

4.3 二进制数和十六进制数的相互转换

4位二进制数和1位十六进制数是相互对应的(即4位的二进制数0000~1111,就是1位的十六进制数0~F)。

二进制数0111101010011100转换为十六进制数:

0111 1010 1001 1100

7 A 9 C

十六进制数8AF7转换为二进制数:

8 A F 7

1000 1010 1111 0111

4.4 使用电脑计算器进行进制转换

将计算器切换为程序员选项:

将十进制数16转换为二进制数、八进制数、十六进制数:

5.整数在内存中的存储

整数在计算机中以二进制数表示。

整数表示的范围在头文件limits.h中定义。

5.1无符号整数的表示方法

unsigned int a = 25;

00000000000000000000000000011001 1×2^4+1×2^3+0×2^2+0×2^1+1×2^0=25

高位<------------------------------------->低位

n位可以表示的无符号整数有0~2^n-1

5.2有符号整数的表示方法

有符号整数有3种二进制表示方法,即原码、反码和补码。最高位为符号位,0表示正数,1表示负数,其余为数值位。在计算机中整数以补码的形式存储。

原码:直接将数值按照正负数的形式翻译成二进制。

正数的反码、补码与原码相同。负数的反码、补码要经过如下计算。

反码:将原码的符号位不变,其他位依次按位取反。补码:反码+1就得到补码。

int a = -25;//原码:10000000000000000000000000011001//反码:11111111111111111111111111100110//补码:11111111111111111111111111100111

8位有符号整数的取值范围如下图所示:(补码10000000不表示-0,表示-128)

5.3大小端模式

大端(存储)模式是指,数据的低位保存在内存的高地址中,数据的高位保存在内存的低地址中。

小端(存储)模式是指,数据的低位保存在内存的低地址中,数据的高位保存在内存的高地址中。

如0x12345678,

大端模式:12 34 56 78

低地址<--->高地址

小端模式:78563412

低地址<--->高地址

判断当前计算机是大端模式还是小端模式:

#include <stdio.h>int check_sys(){int a = 1;return *(char*)&a;}//或者使用联合类型//int check_sys()//{//union Un//{//char c;//int i;//}u;//u.i = 1;//return u.c;//}int main(){int ret = check_sys();if (ret == 1)printf("小端\n");elseprintf("大端\n");return 0;}

1(int型)的补码用十六进制表示为0x00000001,

大端模式:0000 00 01

低地址<--->高地址

小端模式:01 00 00 00

低地址<--->高地址

*(char*)&a表示取出a的地址,然后强制类型转换为char*,再解引用,此时只能访问一个字节的内容。如果这一个字节的内容为0,为大端模式;如果这一个字节的内容为1,为小端模式。

6.整型截断、整型提升和算数转换

6.1整型截断

整型截断是将所占字节大的元素赋给所占字节小的元素时会出现数值的舍去现象。在赋值过程中只将占字节较长的变量的低位赋给占字节较短的变量。

char a = -1;

-1为int型,

原码:10000000000000000000000000000001

反码:11111111111111111111111111111110

补码:11111111111111111111111111111111

char类型只占8位,将-1赋给a,发生整型截断,保留8个低位,即a存储为11111111。

6.2整型提升

C的整型算术运算总是至少以缺省(默认)整型类型的精度来进行的。为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。

有符号的整型提升高位补充符号位,无符号的整型提升高位补0。

6.2.1 负数的整型提升

char c1 = -1;

c1存储为1111111,因为数据类型为signed char,所以当c1发生整型提升时,高位补充符号位1,整型提升后的结果是:11111111111111111111111111111111

6.2.2 正数的整型提升

char c2 = 1;

c2存储为00000001,因为数据类型为signed char,所以当c2发生整型提升时,高位补充符号位0,整型提升后的结果是:00000000000000000000000000000001

6.2.3 无符号数的整型提升

unsigned char c3 = -1;

c3存储为1111111,因为数据类型为unsigned char,所以当c3发生整型提升时,高位补0,整型提升后的结果是:00000000000000000000000011111111

6.3算数转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数转换为另一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换。

long double

double

float

unsigned long int

long int

unsigned int

int

如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。

6.4练习题

6.4.1

#include <stdio.h>int main(){char a = -1;signed char b = -1;unsigned char c = -1;printf("a=%d,b=%d,c=%d", a, b, c);return 0;}//a=-1,b=-1,c=255

-1为int型,

原码:10000000000000000000000000000001

反码:11111111111111111111111111111110

补码:11111111111111111111111111111111

整型截断:

a、b、c均存储为11111111

整型提升:

有符号的a、b整型提升为11111111111111111111111111111111----输出有符号整型---->-1

无符号的c整型提升为00000000000000000000000011111111----输出有符号整型---->255

6.4.2

#include <stdio.h>int main(){char a = -128;printf("%u\n", a);return 0;}//4294967168

-128为int型,

原码:10000000000000000000000010000000

反码:11111111111111111111111101111111

补码:11111111111111111111111110000000

整型截断:

a存储为10000000

整型提升:

有符号的a整型提升为11111111111111111111111110000000----输出无符号整型---->4294967168

6.4.3

#include <stdio.h>int main(){char a = 128;printf("%u\n", a);return 0;}//4294967168

128为int型,

原码、反码、补码:00000000000000000000000010000000

整型截断:

a存储为10000000

整型提升:

有符号的a整型提升为11111111111111111111111110000000----输出无符号整型---->4294967168

6.4.4

#include <stdio.h>int main(){int i = -20;unsigned int j = 10;printf("%d\n", i + j);return 0;}//-10

-20为int型,

原码:10000000000000000000000000010100

反码:11111111111111111111111111101011

补码:11111111111111111111111111101100

i存储为11111111111111111111111111101100

10为unsigned int型,

j存储为00000000000000000000000000001010

i+j=11111111111111111111111111101100+00000000000000000000000000001010

=11111111111111111111111111110110----输出有符号整型---->10

6.4.5

#include <stdio.h>int main(){unsigned int i;for (i = 9; i >= 0; i--){printf("%u\n", i);}return 0;}//9//8//7//6//5//4//3//2//1//4294967295//4294967294//…死循环

先输出9 8 7 6 5 4 3 2 1 0,而后0-1=-1

-1的补码:11111111111111111111111111111111----输出无符号整型---->4294967295

6.4.6

#include <stdio.h>#include <string.h>int main(){char a[1000];int i;for (i = 0; i < 1000; i++){a[i] = -1 - i;}printf("%d", strlen(a));return 0;}//255

strlen()函数计算字符串的长度,从字符串开头依次向后计数,直到遇见第一个字符串结束符\0(ASCII码值为0)为止,然后返回计数器值(长度不包含\0)。

-1 -2 … -128 127 126 … 1 0 -1 …

128+127=255

6.4.7

#include <stdio.h>unsigned char i = 0;int main(){for (i = 0; i <= 255; i++){printf("hello world\n");}return 0;}//死循环

unsigned char类型的取值范围:0~255,所以i <= 255恒成立,死循环。

7.浮点数在内存中的存储

浮点数表示的范围在头文件float.h中定义。

7.1浮点数的存储规则

根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成这种形式:

(-1)^S * M * 2^E

(-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数。M表示有效数字,1≤M<2。2^E表示指数位。

十进制的5.5,写成二进制是101.1,相当于1.011×2^2 。此时,S=0,M=1.011,E=2。

对于32位的浮点数,最高的1位是符号位S,接着的8位是指数E,剩下的23位为有效数字M。对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。

7.2对于M的规定

1≤M<2 ,即M可以写成1.xxxxxx的形式。IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。

7.3对于E的规定

E为一个无符号整数(unsigned int),如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。但是,科学计数法中的E是可以出现负数的,所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数127;对于11位的E,这个中间数是1023。

例如,十进制的5.5(float),写成二进制是101.1,相当于1.011×2^2 。此时,S=0,M=1.011,E=2。M只保存011,E存储2+127=129,即10000001,所以5.5(float)的存储形式为:01000000101100000000000000000000

指数E从内存中取出分为三种情况:

7.3.1E不全为0或不全为1

E:减去中间值(127或1023)

M:前面加上1.

例如,01000000101100000000000000000000,S=0,M=1.011,E=2,为1.011×2^2,即101.1,十进制为5.5。

7.3.2 E全为0

E:1-中间值(=-126或-1022)

M:前面加上0.

例如,00000000001100000000000000000000,S=0,M=0.011,E=-126,为0.011×2^(-126),表示一个接近于0的很小的数字。

7.3.3 E全为1

E:255-127=128或2047-1023=1024

M:如果M全为0,表示±∞

例如,01111111100000000000000000000000表示正无穷大。

7.4练习题

#include <stdio.h>int main(){int n = 9;float* pFloat = (float*)&n;printf("n的值为:%d\n", n);//9printf("*pFloat的值为:%f\n", *pFloat);//0.000000*pFloat = 9.0;printf("num的值为:%d\n", n);//1091567616printf("*pFloat的值为:%f\n", *pFloat);//9.000000return 0;}

int n = 9;float* pFloat = (float*)&n;

9的补码:00000000000000000000000000001001

n:9

*pFloat:00000000000000000000000000001001,为0.00000000000000000001001×2^(-126),当有效数字为6位时,输出0.000000

int n = 9;float* pFloat = (float*)&n;*pFloat = 9.0;

*pFloat:9.0表示成二进制为1001.0,即1.001×2^3,存储为01000001000100000000000000000000,当有效数字为6位时,输出9.000000。

num:01000001000100000000000000000000----输出整型---->1091567616

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。