c语言知识数据类型和变量
数据类型:
1.数据表示
1.1.二进制
基数为2的进位制叫二进制 二进制只有0、1两种数码,计数逢2进位。
bit 一个二进制位
8bit == 1byte 一个字节
1.十进制转二进制
问题:23怎么用二进制表示?
答案:00010111
2.二进制转十进制
1010 = 1X2^3 + 0X2^2 + 1X2^1 + 0X2^0
= 1X8 + 0X4 + 1X2 + 0X1
= 10
规律:高位到低位的每个二进制位表示的十进制数据值
...... 1 1 1 1 1 1 1 1 1
...... 256 128 64 32 16 8 4 2 1
...... 2^8 2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0
问题: 11010001的十进制是多少呢?
128+64+16+1 = 209
答案:209
1.2.八进制
表示八进制的数据,数据前面都会有个符号 0。
1.十进制转换八进制
2.八进制转换十进制
0 17 = 1X8^1 + 7X8^0
= 1X8 + 7X1
= 15
3.八进制转二进制
得出的一个技巧是:3个二进制位对应1个八进制位
二进制: 00 001 111
八进制:0 0 1 7
1.3.十六进制
符号为 0x
1.十进制转十六进制
2.十六进制转十进制
0x 2b = 2X16^1 + bX16^0
= 2X16 + bX1
= 43
3.十六进制转二进制
得出的一个技巧是:4个二进制位对应1个十六进制位
二进制: 0000 1111
十六进制:0x 0 F
编程技巧:
需要注意的是,二进制是计算机需要的表示形式,代码
书写使用的话太费事情,所以编程语言里没有二进制数
据的写法,都是以十进制、八进制、十六进制形式表示
数据的。
1.基本数据类型
1.逻辑类型:只有两个量true和false,表示逻辑真值和逻辑假值。
2.整数类型:char、short、int和long。
3.浮点类型:float和double。
4.void类型:主要说明不返回值的函数或指向类型的指针
8bit == 1byte 一个字节
bool类型 :要用bool类型的时要调用头文件
没有这个头文件编译就会报错
必须要引用
对文件进行宏展开
可以看到bool头文件存放的位置,可以看到850行跟上面写的定义bool有所差异,这是因为_Bool也是c的基本数据类型。用vi命令进入846行。
可以看到刚刚引用的是39行的bool,重新改写
可以比较看出可以用系统的的基本类型_Bool
char类型
类型名称 | 长度(字节) | 值域 |
char | 1 | -128~127或0~255(使用/J编译选项) |
signed char | 1 | -128~127 |
unsigned char | 1 | 0~255 |
-128的补码:10000000
#include <stdio.h>
int main(int argc, char *argv[])
{
signed char ch;
//unsigned char ch; ch = 65;
//ch = 'A';
printf("ch=%d %c\n", ch, ch);
return 0;
}
问题1: %d 以整型形式输出,%c以字符形式输出。
数据存储在计算机中,都最终转换成二进制形式,所以可以以整型形式表示。
问题2: 65为什么是A。
原身是电报文,为了显示现代英语。延伸发展后,给出256个固定下来的字符对应数值关系,有一部分是可以显示出来的,一部分是不能显示的。https://www.runob.com/w3cnote/ascii.html
/*查找man手册去了解具体的字符代表的数值,ASCII表中
有256个固定下来的字符*/
'\0'---0
'\n'---10
' ' ---32 (这是个空格)
......
'0' ---48 (差48)
'1' ---49
......
'A' ---65
'B' ---66
......
'a' ---97 (差32)
'b' ---98
short类型:
类型名称 | 长度 | 值域 |
short | 2 | -32768~32767 |
unsigned short | 2 | 0~65535 |
浮点类型
类型名称 | 长度 | 值域 |
float | 4 | -3.40E+38 ~ +3.40E+38 |
double | 8 | -3.40E+38 ~ +3.40E+38 |
int类型
类型名称 | 长度 | 值域 |
int | 4 | -2147483648~2147483647 |
unsigned int | 4 | 0~4294967295 |
2.sizeof():查长度
想要查值域范围:要用到头文件
3.强制数据类型转换
C语言运算表达式允许混合类型在一起运算,但在进行运算时,不同类型的数据要先转换成同一类型,然后再进行运算。转换的形式可以分为自动类型转换(隐形)、赋值转换、强制类型转换。
显现数据转换和隐形数据转换
强制类型转换容易丢失数据精确度,一般是高级类型向低级类型转换,是一种不安全转换。
强制类型转换并不改变变量的数据类型和值。
3.1自动类型转换
参与运算的不同类型的变量,其中的低级类型的变量先向其中的高级类型变量转换后,再运算,结果类型同其中的高级类型。
例如:
char ch='a';
int i=10;
float x=3.14;
double y=7.528e-6;
计算i+ch+x*y
其顺序是先乘法后从左到右算加法。
那么,运算过程中,类型变化是:
x先转换为double类型与y相乘,值类型double类型;
之后i与转换为int类型的ch相加,值类型是int;
然后int值转换成double值和后面的double值相加。
因此,运算式的结果类型是double。
3.2赋值类型转换
如果赋值语句两侧的类型不一致(但都是数值或字符)赋值时进行匹配等号左边类型的转换,可能会改变精度。
实型 = 整型;(整型的数值不变,但会以实型形式存储值到实型变量)
整型 = 实型;(实型的数值舍弃小数点后的部分,保留整型部分存储到整型变量)
同类型的长类型变量 = 同类型短类型变量;(数据转换是正确的,例如, char 和 short 型数据给 int 型变量赋值,不影响精度)
同类型的短类型变量 = 同类型的长类型变量;(可能出错。例如,当 unsigned int 型的值超过了 unsignedshort 变量的取值范围,赋值会出错, unsigned intb = INT_MAX; unsigned short a = b; a的结果为65535 )
#include <stdio.h>
#include <limits.h>
int main(int argc, const char *argv[])
{
unsigned short a = 0;
unsigned int b = INT_MAX;
printf("a = %u, b = %u\n", a, b);
a = b;
printf("a = %u, b = %u\n", a, b);
return 0;
}
a = 0, b = 2147483647
a = 65535, b = 2147483647
当然如果数据类型为 signed 类型,因为数据的符号位问题,会更复杂一些。(补码)
3.3强制类型转换(显示强制转换)
#include <stdio.h> int main(int argc, const char *argv[]) { int a = 10; float b = 3.14; a = (int)b; printf("%d, %d\n", a, (int)b); return 0; }
4.常量
整型常量:运行时不发生变化的数值
指数常量:1.12e+10表示的是1.12✖10的10次方;1.8e-3表示1.8✖10的负三次方(一般用浮点型科学计数法)。
字符常量:单一字符。如‘A’等。可以把字符常量看作一个整数值
A的ASCii码为:65
a:97
空格:32
1:48
4.1.整型常量
10、245、-1
4.2.字符常量
'a' 、'F' 单引号;
4.3.浮点常量
3.14 、 20.5085
%d %ld %c %u %x %s %f %lf
4.4.字符串常量
字符串默认包含结束标志尾零 ‘\0’ ,是转义字符,不显示
"hello world"、"good job" 双引号;
用双引号表示,一串字符表达的数据。如”Hello“。字符串以\0结尾。
如:”9“——‘9’和‘\0’组成。
4.5.宏
原样替换
用标识符代替常量使用的一种常量,其名称通常是一个标识符。也叫符号常量,一般用大写英文字母的标识符。
#define (宏)
在这幅图中很容易会计算成第一种结果,但其实是第二种,因为宏定义会在程序编译之前就会把数展开。
我们可以看到在运行中程序会这样运行。
代码举例
宏函数
(了解)学完函数,用宏实现加法:
#define A a
#define B b
#define ADD ((A)+(B))
或者
优化:#define ADD(A, B) ((A)+(B))
ADD(10, 20)
练习
一个水分子的质量约为3.0*10负23次方克,1夸脱水大约有950g,编写一个程序,要求输入水的夸脱数,然后显示这么多水中包含多少水分子。
5.变量
变量名:由字母、数字、下划线组成,不能以数字开头,不能和c的关键字重名。
变量在内存空间中的首地址,称为变量的地址
变量说明的一般形式是:
是关键字auto(一般没有写存储类型时默认为这个)、register、static和extern
可以是基本数据类型也可以是自定义的数据类型
5.1变量的数据类型
5.1.1字符变量
//1. 定义
char a;
//2. 定义并初始化
char a = 'a';
//3. 赋值
a = 'b';
5.1.2整型变量
//1. 定义
short a;
int b;
long c;
//2. 定义并初始化
int b = 5;
//3. 赋值
b = 1;
5.1.3浮点变量
//1. 定义
float a;
double b;
//2. 定义并初始化
float c = 5.5;
//3. 赋值
c = 1.1;
5.1.4字符串——>字符数组
/*数组是复杂数据类型、是构造类型*/
//初始化 可以预先给定固定的内容
char a[20] = "hello world"; √
//整体赋值是错误的方式!是构造类型,不允许整体赋值!
//a = "error"; X
依次赋值每个成员,或者借助处理字符串的库函数。
5.2局部变量、全局变量、静态变量、外部变量
变量定义的位置、存储类型不同,会影响变量的使用效果。
这里用两个属性描述:作用域、生命周期。
作用域:能使用的范围限制。
生命周期:能使用的时间限制。
5.2.1.作用域
#include <stdio.h>
int main(int argc, const char *argv[])
{
{
int a=10;
printf("in a=%d\n", a);
}
/*作用域*/
//printf("out a=%d\n", a); //不能打印出来,因为a的作用域在上个括号里面
return 0;
}
5.2.2.生命周期
#include <stdio.h>
void fun(void)
{
int b;
printf("b=%d\n", b);
}
int main(int argc, const char *argv[])
{
/*生命周期*/
fun();
printf("hello world\n");
fun();
/*作用域*/
//printf("b=%d\n", b);
return 0;
}
5.2.3变量存储类型
auto说明的变量只能在某个程序范围内使用,通常在函数体内或函数中的复合语句里。
register称为寄存器型,register变量是想将变量放入CPU的寄存器中,这样可以加快程序的运行速度。如申请不到就使用一般内存,同auto;
register变量必须是能被cpu所接受的类型。这通常意味着register变量必须是一个单个的值,并且长度应该小于或者等于整型的长度。
不能用&来获取register变量的地址。
static变量称为静态存储类型的变量,即可以在函数体内,也可以在函数体外说明。(默认是0)。
局部变量使用static修饰,有以下特点:
在内存中以固定地址存放的,而不是以堆栈方式存放。
只要程序没结束,就不会随着说明它的程序段的结束而消失,下次再调用该函数,该存储类型的变量不再重新说明,而且还保留上次调用存入的数值。(特别像全局变量)
这个代码中a输出的值一直为1,a是局部变量,每次循环的时候a的值都会被重新赋予0。
用static存储类型定义之后,发生了改变。因为static的特点,使得进入新循环后a的值并没有被重新赋予。
static修饰全局变量,其他文件无法使用。
extern:当变量在一个文件中时的函数体外说明,所有其他文件中的函数或程序段都可以引用这个变量。
extern称为外部参照引用型,使用extern说明的变量是想引用在其他文件中函数体外说明的变量。
建了两个文件extern1.c和extern2.c。在extern2.c中定义了一个变量,但是在extern1.c中并没有调用这个变量,想要调用这个变量就可以用extern来定义。
在全局变量多文件编译的话,全局变量默认是extern属性所以右边的文件虽然没有说存储类型但是默认为extern。
static修饰全局变量,其他文件无法使用。