您的位置:首页 > 编程语言 > C语言/C++

C语言之进制、位运算符、数组

2015-10-01 20:09 471 查看

一 进制基本概念

1.什么是进制?

是一种计数的方式,数值的表示形式

2.常见的进制

十进制、二进制、八进制、十六进制

3.进制数字进位方法

十进制 0、1、2、3、4、5、6、7、8、9 逢十进一

二进制 0、1 逢二进一

书写形式:需要以0b或者0B开头,比如0b101

八进制 0、1、2、3、4、5、6、7 逢八进一

书写形式:在前面加个0,比如045

十六进制 0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F 逢十六进一

16进制就是逢16进1,但我们只有0~9这十个数字,所以我们用A,B,C,D,E,F这五个字母来分 别表示10,11,12,13,14,15。字母不区分大小写。

书写形式:在前面加个0x或者0X,比如0x45

4.编程输出各种进制



二 进制转换

10 进制转 2 进制

除2取余, 余数倒序得到的序列就是二进制表示形式

2 进制转 10 进制

每一位二进制进制位的值 * 2的(当前二进制进制位索引)

索引从0开始, 从右至左

将所有位求出的值相加

2 进制转 8 进制

三个二进制位代表一个八进制位, 因为3个二进制位的最大值是7,而八进制是逢八进一



8 进制转 2 进制

每一位八进制位的值 * 8的(当前二进制进制位索引)

索引从0开始, 从右至左

将所有位求出的值相加

2 进制转 16 进制

四个二进制位代表一个十六进制位,因为4个二进制位的最大值是15,而十六进制是逢十六进一



16 进制转 2 进制

将16进制的每一位拆成4为二进制位

三 原码反码补码

原码反码补码基本概念

数据在计算机内部是以补码的形式储存的

数据分为有符号数和无符号数

无符号数都为正数,由十进制直接转换到二进制直接存储(其实也是该十进制的补码)即可。 有符号数用在计算机内部是以补码的形式储存的。

( 正数的最高位是符号位0,负数的最高位是 符号位1。 对于正数:反码==补码==原码。 对于负数:反码==除符号位以外的各位取反。补码=反码+1)

正数的首位地址为0,其源码是由十进制数转换到的二进制数字

负数的首位地址为1,其源码后面的位也为10进制数转换过去的二进制数字,都是用补码方式表示 有符号数的。

原码

原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值

反码

正数的反码是其本身

负数的反码是在其原码的基础上, 符号位不变,其余各个位取反

补码

正数的补码就是其本身

负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)

正数的特点:(三码合一) 正数的原码就是TA的反码就是TA的补码;

负数的反码在其原码的基础上, 符号位不变,其余各个位取反,补码是在反码的基础上+1

四 位运算符介绍

什么是位运算符?

位运算是指按二进制进行的运算

运算符只能用于整型操作数,即只能用于带符号或无符号的 char,short,int与long类型

位运算符与(& 按位与)

只有对应的两个二进位均为1时,结果位才为1,否则为0

口诀: 同1为1

规律

二进制中,与1相&就保持原位,与0相&就为0

应用场景:

按位与运算通常用来对某些位清0或保留某些位。例如把a的高位都清0,保留低八位,那么就a&255

判断奇偶: 将变量a与1做位与运算,若结果是1,则 a是奇数;若结果是0,则 a是偶数

任何数和1进行&操作,得到这个数的最低位

位运算符或( | 按位或)

只要对应的二个二进位有一个为1时,结果位就为1,否则为0

位运算符异或(^ 按位异或)

当对应的二进位相异(不相同)时,结果为1,否则为0

规律

相同整数相^的结果是0。比如5^5=0

位运算符取反(~ 取反)

各二进位进行取反(0变1,1变0)

多个整数相^的结果跟顺序无关。比如5^6^7=5^7^6

因此得出结论:a^b^a = b

左移位运算符

把整数a的各二进位全部左移n位,高位丢弃,低位补0。左移n位其实就是乘以2的n次方

由于左移是丢弃最高位,0补最低位,所以符号位也会被丢弃,左移出来的结果值可能会改变正负性

右移位运算符

把整数a的各二进位全部右移n位,保持符号位不变。右移n位其实就是除以2的n次方

为正数时, 符号位为0,最高位补0

为负数时,符号位为1,最高位是补0或是补1

五 变量内存分析

1.字节和地址

为了更好地理解变量在内存中的存储细节,先来认识一下内存中的“字节”和“地址”。

内存以“字节为单位”



里面的每个小框框就代表着内存中的一个字节,白色数字就是每个字节的地址。可以发现,内存中相邻字节的地址是连续的

一个字节只有8位,所能表示的数据范围是非常有限的,因此,范围较大的数据就要占用多个字节,也就是说,不同类型的数据所占用的字节数是不一样的

2.变量的存储

一个变量所占用的存储空间,不仅跟变量类型有关,而且还跟编译器环境有关系。同一种类型的变量,在不同编译器环境下所占用的存储空间又是不一样的

下面的表格描述了在不同编译器环境下的存储空间占用情况



变量存储单元的第一个字节的地址就是该变量的地址

任何变量在内存中都是以二进制的形式存储。一个负数的二进制形式,其实就是对它的正数的二进制形式进行取反后再+1。(取反的意思就是0变1、1变0)

3. 变量在内存中存储的原则

先分配字节地址大内存,然后分配字节地址小的内存(内存寻址是由大到小)

因为内存寻址是由大到小,所以先定义的变量的内存地址会比后定义的大

number1地址 > number2

变量的首地址,是变量所占存储空间字节地址最小的那个地址



低位保存在低地址字节上,高位保存在高地址字节上

六 char类型

1.char类型基本概念

char是C语言中比较灵活的一种数据类型,称为“字符型”。它是用来存储字符的,因此可以将一个字符常量赋值给一个字符型变量

1个字符型变量占用1个字节,共8位,因此取值范围是-2^7~2^7-1。在这个范围内,你完全可以将字符型变量当做整型变量来使用

在某些字符前面加上”\”形成的字符,称为“转义字符”,比如\n、\t、\0



2.char型数据存储原理

char a=’a’ —–>取出’a’的ASCII码值97,然后转换2进制,存储在一个字节中

3.char型使用注意事项

当把一个字符赋值给一个char类型变量,那么系统首先查这个字符所对应的ASCII码,然后把这个ASCII值放到变量中

根据变量中存储的ASCII值,去查ASCII表中对应字符,然后把这个字符打印控制台上,整型和字符型可以互相转换。

字符型变量不能用来存储汉字

不支持多个字符,多个字符是字符串

七 类型说明符

C语言提供了以下4种说明符,4个都属于关键字:

short 短型 等价于 short int

long 长型 等价于 long int

signed 有符号型

unsigned 无符号型

这些说明符一般就是用来修饰int类型的,所以在使用时可以省略int

short和long可以提供不同长度的整型数,也就是可以改变整型数的取值范围。

在64bit编译器环境下,int占用4个字节(32bit),取值范围是-2^31~2^31-1;

short占用2个字节(16bit),取值范围是-2^15~2^15-1;

long占用8个字节(64bit),取值范围是-2^63~2^63-1

signed和unsigned的区别就是它们的最高位是否要当做符号位,并不会像short和long那样改变数据的长度,即所占的字节数。

signed:表示有符号,也就是说最高位要当做符号位,所以包括正数、负数和0。signed的取值范围是-2^31 ~ 2^31 - 1

unsigned:表示无符号,也就是说最高位并不当做符号位,所 以不包括负数。

八 数组

数组的基本概念

数组就是用来存储一组数据的

数组的几个名词

数组:一组具有相同数据类型的数据的有序的集合

数组元素:构成数组的数据。数组中的每一个数组元素具有相同的名称,不同的下标,可以作为单个变量使用,所以也称为下标变量。

数组的下标:是数组元素的位置的一个索引或指示。(从0开始)

数组的维数:数组元素下标的个数。根据数组的维数可以将数组分为一维、二维、三维、多维数组

数组的分类

按存储的内容分类

数值数组:用来存储数值得

字符数组:用来存储字符 ‘a’

指针数组:用来存放指针(地址)的

结构数组:用来存放一个结构体类型的数据

… …

按维度分类

一维数组

二维数组

多维数组

定义数组

元素类型 数组名[元素个数];

初始化数组

一般会在数组定义的同时进行初始化

其中在{ }中的各数据值即为各元素的初值,各值之间用逗号间隔

指定数组的元素个数,对数组进行部分显式初始化

定义的同时对数组进行初始化,没有显式初始化的元素,那么系统会自动将其初始化为0

不指定元素个数,定义的同时初始化,它是根据大括号中的元素的个数来确定数组的元素个数

指定元素个数,同时给指定元素进行初始化

int nums[5] = {[4] = 3,[1] = 2};


先定义,后初始化

注意:如果定义数组后,没有初始化,数组中是有值的,是随机的垃圾数

对于数组来说,一旦有元素被初始化,其他元素都被赋值0

数组的使用

通过下标(索引)访问

数组的遍历

遍历的意思就是有序地查看数组的每一个元素

数组长度计算方法

因为数组在内存中占用的字节数取决于其存储的数据类型和数据的个数,

数组在内存中占用的总字节数:sizeof(数组名);

数组所占用存储空间 = 一个元素所占用存储空间 * 元素个数(数组长度)

所以计算数组长度可以使用如下方法:数组的长度 = 数组占用的总字节数 / 数组元素占用的字节数

数组注意事项

在定义数组的时候[]里面只能写整型常量或者是返回整型常量的表达式

错误写法

// 1.没有指定元素个数,错误
int a[];

// 2.[]中不能放变量
int number = 10;
int ages7[number]; // 不报错, 但是没有初始化, 里面是随机值
printf("%d\n", ages7[4]);

int number = 10;
int ages7[number] = {19, 22, 33} // 直接报错
int ages8[5];

// 3.只能在定义数组的时候进行一次性(全部赋值)的初始化
int ages10[5];
ages10 = {19, 22, 33};

// 4.一个长度为n的数组,最大下标为n-1, 下标范围:0~n-1
int ages11[4] = {19, 22, 33}
ages[8]; // 数组角标越界


数组内部存储细节

存储方式:

1)计算机会给数组分配一块连续的存储空间

2)数组名代表数组的首地址,从首地址位置,依次存入数组的第1个、第2个….、第n个元素

3)每个元素占用相同的字节数(取决于数组类型)

4)并且数组中元素之间的地址是连续。

数组的地址

在内存中,内存从大到小进行寻址,为数组分配了存储空间后,数组的元素自然的从上往下排列存储,整个数组的地址为首元素的地址。

数组越界导致的问题

约错对象

程序崩溃
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: