c语言基础知识————变量
2017-10-16 20:13
357 查看
零.前言
这两天帮忙给实验室公众号写一篇推文,主要面向大一的萌新。所以重新回顾了一下c语言中关于变量的知识。主要内容
1. 变量的三要素
2. 进制转换,原码,补码
3. 整形的溢出,浮点型的精度丢失问题
4. 初始指针
5. 自动类型转换和强制类型转换
一.引入
a=3;什么是常量,什么是变量,什么是运算符,什么表达式。
上面这个语句中,‘3’是常量。 ‘=’是运算符。‘a’是变量。而’a=3’这个完整的就是一个表达式。
上面整个表达式的含义:就是将常量‘3’赋值给‘a’这个变量。
我们今天主要来谈谈变量,就是‘a’
二.变量
1. 变量是什么
那么变量究竟是什么呢?一个字母‘a’为什么就成为了变量呢?变量就是内存设备里一段连续的存储空间(类似于一个盒子,用来存储数据)。
目前,严格来说,‘a’目前还算不是一个变量。因为它没有经过变量三要素的洗礼。
2. 变量的三要素
int a;上面这个语句,就包含变量的三要素。
int 变量类型。
a 变量名 。
int a;变量的定义。
让我们一个一个来解释
变量的类型
简单来说,变量是类型就是盒子的种类。
为什么变量要有不同的类型呢?
在计算机里,所有的存储数据都是0/1。而且存储的资源也是有限的。为了存储不同种类(整数,实数,字符),不同大小的数据,人们将数据人为分为不同的数据类型。并且对每种类型规定了所占用内存空间的大小,以及数据和0/1之间的转换方式。
那么对于变量而言,它的类型到底意味着什么呢
变量的类型两个作用
说明变量所要占用的内存空间的大小(申请多大的空间),
数据和0/1之间的转换方式(如何存储数据和解释数据的标准)
那我们来看看,c语言中它的常用变量类型都有那些?
变量名
就是‘a’。a其实是对刚申请的内存空间起的一个名字。为了和其他变量区分的标志。
但是呢,起名也有一定的规定,不可以随意起名
1.只能以英文字母、下划线( _ )、美元符号( )开头。后面可以接数字、英文字母、下划线和美元符号( )
2.不能是C语言中的关键字
上面的是必须要做到,下面的则是一些建议
1.变量名最好做到见名知义的程度
2.变量名不要和函数名一样
变量的定义。
int a;这就是一个完整的变量定义语句。
那么,它代表什么含义呢呢?
它表示:申请一段内存大小为4字节的存储空间,其中数据的存储方式和解释为补码,并将段内存空间起名为a
3. 一点思考
为什么整形变量会存在溢出现象呢?溢出: int a= 2147483647 int b = a+1; 最终 b = -2147483648
为什么浮点型变量会有精度的丢失现象呢?
float a = 12.0f; float b = 11.9; float c = a - b; 最终c=0.1000003815
三.深入了解变量
1. 预先了解,十进制转换为二进制,原码,补码。
十进制正整数如果转换为二进制规则
除二取余,倒序排列
解释:将一个十进制数除以二,得到的商再除以二,依此类推直到商等于一或零时为止,倒取将除得的余数,即换算为二进制数的结果
举例
52(10)=110100(2进制)
十进制小数如果转换为二进制
规则
乘二取整,正序排列
解释:对被转换的小数乘以2,取其整数部分(0或1)作为二进制小数部分,取其小数部分,再乘以2,又取其整数部分作为二进制小数部分,然后取小数部分,再乘以2,直到小数部分为0或者已经去到了足够位数。每次取的整数部分,按先后次序排列,就构成了二进制小数的序列
举例
原码
规则
当数据为正数时:最高位为0,表示正数,其余位表示数据
当数据为负数时:最高为位1,表示负数,其余位表示数据
举例
用8字节表示52和-52的原码
52:00110100(原)
-52:10110100(原)
说明
虽然原码简单易懂,但是它存在一些问题,所以计算机中的数据存储并没有采用原码来表示
第一个问题:正0 负0,按照原码的规则既是正数也是负数的0存在两种书写方式即:00000000和10000000
第二个问题,无法进行正负数之间的运算,将-52和52之间转换后的原码进行加法运算,结果并不等于0
反码
规则
当数据为正数时:补码 = 原码
当数据为负数时:原码最高位不变(1),其余位按位取反,末尾加1
举例
用8字节表示52和-52的原码
52:00110100(原) ~ 00110100(补)
-52:10110100(原) ~ 11001011(取反)~ 11001100(补)
说明
补码解决了原码的两个问题。
补码就是c语言中的整形在内存中的数据的储存方式
2. 了解为什么整形变量的表示会发生溢出
先计算int的表示范围int占用4b的内存,就是32位。
那么32位表示正数最大值为:01111111 11111111 11111111 11111111() = 2147483647
32表示负数最大值为:10000000 00000000 00000000 00000000 = -2147483648
为什么会溢出呢
2147483647 + 1 = 01111111 11111111 11111111 11111111+1=10000000 00000000 00000000 00000000 = -2147483648
3. 了解为什么浮点型变量会有精度丢失
12-11.9=?* 将11.9化为二进制为“1011. 1110011001100110011001100…”,可以看出11.9转换为二进制是一个无穷的小数,按照浮点数的存储形式(IEEE754)的时候需要舍弃一些二进制。所以在计算机中永远无法准确存储11.9这个数字。所以计算时会产生误差。
* 扩展,如果有兴趣,可以具体了解一下IEEE754是如何规定浮点数的存储的。
四.初探指针。
1.重新看一遍变量究竟是什么?
之前说过变量是内存设备里一段连续的存储空间,对于内存设备中存储空间我们并没有做过多的介绍。那么我们现在简单说一下它的两个特性存储空间是连续的,一维线性的
存储空间出厂时,每一个存储单位都有一个编号(0~2^32),这个编号就是这个存储单位的地址。
2.指针究竟是什么呢
int *p;p就是一个int型指针变量。
看指针和变量的定义很像,那么指针和变量有什么关系呢?
指针就是一个变量,不过不同于一般的变量,指针变量所占用的空间都是4字节,所存储的是变量的地址。
那么指针前面的类型有什么作用呢?
指针前面的作用如下
p+1时指针所跳跃的字节大小=指针类型的大小
读取p所指向的变量的数据时,所读取的内存大小和数据的解释方式都要依靠指针的类型。
五.不同数据类型间的类型转换
数据类型之间的转换分为自动类型转换和强制类型转换。顾名思义,前者是编译器自动完成的,后者是程序员强制将数据类型进行转换。1.自动类型转换。
出现场景同一句语句或表达式如果使用了多种类型的变量和常量(类型混用)
规则
double ←── float 高
↑
long
↑
unsigned
↑
int ←── char,short 低
1.图中横向箭头表示必须的转换,如两个float型数参加运算,虽然它们类型相同,但仍要先转成double型再进行运算,结果亦为double型。纵向箭头表示当运算符两边的运
2.算数为不同类型时的转换,如一个long 型数据与一个int型数据一起运算,需要先将int型数据转换为long型, 然后两者再进行运算,结果为long型。所有这些转换都是由系统自动
进行的, 使用时你只需从中了解结果的类型即可。这些转换可以说是自动的。
其他场景中出现自动类型转换
1.在程序中将数据用printf函数以指定格式输出时,当要输出的盐据类型与输出格式不符时,便自动进行类型转换
2.赋值表达式中,右边表达式的值自动隐式转换为左边变量的类型,并赋值给他。
3.函数调用中参数传递时,系统隐式地将实参转换为形参的类型后,赋给形参。
4.函数有返回值时,系统将隐式地将返回表达式类型转换为返回值类型,赋值给调用函数。
举个栗子
1.例子1
#include <stdio.h> int main(void) { char a='1'; int b=-4; unsigned c=2; printf("%d %d %d \n",a,a+b,b+c); //结果为49 45 -2 }
问题:b是int(整形) c是unsigned(无符号整形)。按照算术运算自动类型转换规则 b+c结果应该是一个unsigned类型。可是输出的结果是-2,明显不是无符号unsigned啊。难道是之前的规则写错了吗?还是输出写错了呢?
回答:嗯,规则没有错,输出也没有错。原因呢,是因为输出的时候又进行了一次类型转换。%d是输出整形的格式控制符。所以呢 b+c结果为无符号整形,但输出的时候因为控制输出符%d,所以又转换为整形 。如果需要转换为无符号整形,应该用%u.
2.例子2
int main(void) { char a='1'; int b=-4; unsigned c=2; printf("%d %d %u \n",a,a+b,b+c); //结果为49 45 4294967294 }
问题:那么你怎么证明,是因为b+c运算结果为无符号类型。还是%u将结果转换为无符号类型。
回答:真是很好的问题。如果算术运算和输出都会导致自动转换,这样子我们永远无法知道,是什么导致自动转换。所以我们要控制变量,不能用将结果输出查看自动转换的原因。那么该如果进行证明int+unsigned会转换成unsigned。继续来做下一个实验
3.例子3
int main(void) { int b=-4; unsigned c=2; if(b>c) printf("整形b-4大于无符号c2 \n"); else printf("无符号c2大于整形b-4\n"); //结果:整形b-4大于无符号2 }
问题:问题:好奇怪啊,-4居然比2大,为什么呢?
回答:
b=-4 = 10000000 00000000 00000000 00000100(原) = 11111111 11111111 11111111 11111100(补);所以b中存的是上面这堆01码
c=2= 00000000 00000000 00000000 00000010(原) = 00000000 00000000 00000000 00000010(补):所以c中存的上面这堆01码
运算b>c时,b是整形,c是无符号整形。所以将b转换为无符号整形。无符号整形最高位不表示符号位,也表示数据。所以b中存的11111111 11111111 11111111 11111100= 4294967292 c依然是无符号整形为2。
4294967292>2为真,b>c表达式结果为1,执行printf(“整形b-4大于无符号c2 \n”);语句
所以实际上不是-4>2。而是4294967292>2
2.强制类型转换
出现场景:需要将一个表达式转换成指定类型。
规则
强制类型转换是通过类型转换运算来实现的。
其一般形式为: (类型说明符) (表达式)
其功能是把表达式的运算结果强制转换成类型说明符所表示的类型
举个栗子
#include<stdio.h> int main (void) { float b=3.1415; double a = (int)b; printf("a=%lf,b=%lf\n",a,b); //结果 a=3.000000,b=3.141500 }
a=(int)b;先将b强制转换为int。即:(int)3。
a为double类型。所以继续将(int)3自动转换为double类型(结果为:3.000000)
所以输出:结果 a=3.000000,b=3.141500
同时可以看出来b的类型并没有被改变。
相关文章推荐
- javaSE_8系列博客——Java语言的特性(二)--高级语言的基础知识(2)-- 变量和常用数据类型
- javaSE_8系列博客——Java语言的特性(二)--高级语言的基础知识(1)-- 变量
- C语言基础知识【变量】
- javaSE_8系列博客——Java语言的特性(二)--高级语言的基础知识(4)-- 变量和数组
- Go语言基础知识总结(语法、变量、数值类型、表达式、控制结构等)
- 【黑马程序员】-01c语言基础知识(变量和scanf)
- c语言基础知识:局部变量与全局变量
- C语言基础知识学习(变量的储存类型)
- 【脚本语言系列】关于Python基础知识魔法变量,你需要知道的事
- 黑马程序员——C语言基础知识整理——数据类型、常量与变量
- C语言基础知识之(一):进制、基本数据类型、常量、变量、表达式、语句
- C语言基础知识之(十二):结构体作为函数的参数(结构体变量、结构体数组)
- C语言基础知识——常变量以及输入输出函数
- C语言基础知识变量的作用域和存储方式详细介绍
- C语言基础知识(个人简单总结的关于变量和函数方面)
- 学ios需要了解的C语言基础知识-10-内外部函数,内外部变量
- JavaScript 语言基础知识点总结(思维导图)
- C语言基础知识汇总
- C语言基础知识串联3
- JavaScript语言基础---(七)全局变量和局部变量