C语言

09-进制、内存分析、类型说明符、位运算

2020-05-29  本文已影响0人  Andy_Livings

一、进制

1.什么是进制

汉字:十一 十进制:11 二进制:1011 八进制:13

2.二进制

1>特点:只有0和1,逢2进1
2>书写格式:0b或者0b开头
3>使用场合:二进制指令\二进制文件,变量在内存中就是二进制存储
4>二进制和十进制的互相转换
5>n为二进制位所能表示的数据范围(不考虑负数):0~2的n次方-1

3.八进制

1>特点:0~7,逢八进一
2>书写格式:0开头
3>八进制和二进制的互相转换

4.十六进制

1>特点:0~F,逢十六进一
2>书写格式:0x或者0X开头
3>十六进制和二进制的互相转换

5.总结

1>Mac中计算器的使用
2>printf以不同进制形式进行输出


不同进制形式输出
6.习题

1> 判断下列数字是否合理

A B C D E F G
00011 0x0011 0x7H4 10.98 0986 .089 -109
+178 0b325 0b0010 0xFFdc 96f 96.0f 96.0F
-.003 15.4e6 10e8.7 7.6e-6

2> 分别写出它们的十进制、八进制、十六进制

A B
0b0011 1101 0b0111 1011

3> 写出它们的二进制

A B C
67 056 0x004f

二、变量的内存分析

研究变量在内存中的具体存储情况

1.字节和地址

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


“字节”和“地址”

2>不同类型占用的字节是不一样的

2.变量的存储

1>所占用字节数跟类型有关,也跟编译器环境有关


字节数与类型和编译环境的关系

2>变量实例

int b = 10;
int a = 134;

3>查看内存地址的两种方式:%x和%p

4>查看整数的二进制形式

// 输出整数的二进制形式
void putBinary(int n)
{
    int bits = sizeof(n) * 8;
    while (bits-->0) {
        printf("%d", n>>bits&1);
        if (bits%4==0) printf(" ");
    }
    printf("\n");
}
3.负数在内存中的存储

1>一个字节的取值范围
2>负数的表示形式
3>原码、反码、补码

4.取值范围
取值范围
5.习题

写出下列变量在内存中的存储情况
int a = 134;
int b = 0;
int c = -10;

三、类型说明符

1.short和long

1> short和long可以提供不同长度的整型数,也就是可以改变整型数的取值范围。在64bit编译器环境下

2> 总结一下:在64位编译器环境下,short占2个字节(16位),int占4个字节(32位),long占8个字节(64位)。因此,如果使用的整数不是很大的话,可以使用short代替int,这样的话,更节省内存开销。

3> 世界上的编译器林林总总,不同编译器环境下,int、short、long的取值范围和占用的长度又是不一样的。比如在16bit编译器环境下,long只占用4个字节。不过幸运的是,ANSI \ ISO制定了以下规则:

4> 可以连续使用2个long,也就是long long。一般来说,long long的范围是不小于long的,比如在32bit编译器环境下,long long占用8个字节,long占用4个字节。不过在64bit编译器环境下,long long跟long是一样的,都占用8个字节。

5> 还有一点要明确的是:short int等价于short,long int等价于long,long long int等价于long long

2.signed和unsigned

1> 首先要明确的:signed int等价于signed,unsigned int等价于unsigned

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

四、位运算

1.& 按位与

1>功能
只有对应的两个二进位均为1时,结果位才为1,否则为0。
2>举例: 比如9&5,其实就是1001&101=1,因此9&5=1
3>规律

2.| 按位或

1>功能
只要对应的二个二进位有一个为1时,结果位就为1,否则为0。
2>举例: 比如9|5,其实就是1001|101=1101,因此9|5=13

3. ^ 按位异或

1> 功能
当对应的二进位相异(不相同)时,结果为1,否则为0。
2> 举例: 比如9 ^ 5,其实就是1001 ^ 101=1100,因此9 ^ 5 = 12
3> 规律

4.~ 取反

对整数a的各二进位进行取反,符号位也取反(0变1,1变0)

5.<< 左移
6.>> 右移
7.习题

1>在不用引入其他变量的情况下,使用位异或 ^ 运算符实现两个变量值的互换
2>使用位与 & 运算符变量的奇偶性
3>编写一个函数,用来输出整数在内存中的二进制形式

五、char类型

1.存储细节

ASCII单字节表(双字节GBK\GB2312\GB18030\Unicode)

注意:在计算机的存储单元中,一个ASCII码值占一个字节(8个二进制位),其最高位(b7)用作奇偶校验位。所谓奇偶校验,是指在代码传送过程中用来检验是否出现错误的一种方法,一般分奇校验和偶校验两种。奇校验规定:正确的代码一个字节中1的个数必须是奇数,若非奇数,则在最高位b7添1;偶校验规定:正确的代码一个字节中1的个数必须是偶数,若非偶数,则在最高位b7添1。

ASCII表
A B C
NUL VT 垂直制表 SYN 空转同步
SOH 标题开始 FF 走纸控制 ETB 信息组传送结束
STX 正文开始 CR 回车 CAN 作废
ETX 正文结束 SO 移位输出 EM 纸尽
EOY 传输结束 SI 移位输入 SUB 换置
ENQ 询问字符 DLE 空格 ESC 换码
ACK 承认 DC1 设备控制1 FS 文字分隔符
BEL 报警 DC2 设备控制2 GS 组分隔符
BS 退一格 DC3 设备控制3 RS 记录分隔符
HT 横向列表 DC4 设备控制4 US 单元分隔符
LF 换行 NAK 否定 DEL 删除
ESC键 VK_ESCAPE (27)
回车键: VK_RETURN (13)
TAB键: VK_TAB (9)
Caps Lock键: VK_CAPITAL (20)
Shift键: VK_SHIFT ($10)
Ctrl键: VK_CONTROL (17)
Alt键: VK_MENU (18)
空格键: VK_SPACE ($20/32)
退格键: VK_BACK (8)
左徽标键: VK_LWIN (91)
右徽标键: VK_LWIN (92)
鼠标右键快捷键:VK_APPS (93)
Insert键: VK_INSERT (45)
Home键: VK_HOME (36)
Page Up: VK_PRIOR (33)
PageDown: VK_NEXT (34)
End键: VK_END (35)
Delete键: VK_DELETE (46)
方向键(←): VK_LEFT (37)
方向键(↑): VK_UP (38)
方向键(→): VK_RIGHT (39)
方向键(↓): VK_DOWN (40)
F1键: VK_F1 (112)
F2键: VK_F2 (113)
F3键: VK_F3 (114)
F4键: VK_F4 (115)
F5键: VK_F5 (116)
F6键: VK_F6 (117)
F7键: VK_F7 (118)
F8键: VK_F8 (119)
F9键: VK_F9 (120)
F10键: VK_F10 (121)
F11键: VK_F11 (122)
F12键: VK_F12 (123)
Num Lock键: VK_NUMLOCK (144)
小键盘0: VK_NUMPAD0 (96)
小键盘1: VK_NUMPAD0 (97)
小键盘2: VK_NUMPAD0 (98)
小键盘3: VK_NUMPAD0 (99)
小键盘4: VK_NUMPAD0 (100)
小键盘5: VK_NUMPAD0 (101)
小键盘6: VK_NUMPAD0 (102)
小键盘7: VK_NUMPAD0 (103)
小键盘8: VK_NUMPAD0 (104)
小键盘9: VK_NUMPAD0 (105)
小键盘.: VK_DECIMAL (110)
小键盘*: VK_MULTIPLY (106)
小键盘+: VK_MULTIPLY (107)
小键盘-: VK_SUBTRACT (109)
小键盘/: VK_DIVIDE (111)
Pause Break键: VK_PAUSE (19)
Scroll Lock键: VK_SCROLL (145)
2.常见错误
char c = A;
char c = "A";
char c = 'ABCD';
char c = '男'; 
3.当做整型使用

在-128~127范围内,可以当做整数来用

4.%c、%d和%i的使用
printf(“%d”, ‘A’);
printf(“%c”, 68);
5.转义字符
转义字符 意义 ASCII码值
\n 将当前位置移到下一行开头(回车换行) 10
\t 跳到下一个TAB位置 9
\\ 代表一个反斜线字符 92
\' 代表一个单引号字符 39
\" 代表一个双引号字符 34
\0 空字符 0
6.习题

1.编写一个函数,将小写字母转为大写
2.说出程序的输出结果

int main()
{
    int i = 67 + '4';
    char c = 'c' - 10;
    
    printf("%d - %c\n", i, i);
    printf("%d - %c\n", c, c);
    return 0;
}



六、程序实现

01-进制

void into_system(void) {
    
    /*
     %d\%i  十进制形式输出整数
     %c 输出字符
     %p 输出地址
     %f 输出小数
     %o 八进制形式输出整数
     %x 十六进制形式输出整数
     */
    
    // 默认情况下,就是十进制
    int number = 12;
    
    // 二进制(0b或者0B开头)
    int number2 = 0B1100;
    
    // 八进制(0开头)
    int number3 = 014;
    
    // 十六进制(0x或者0X开头)
    int number4 = 0xc;
    
    // %d以10进制整数的形式输出一个数值
    printf("%x\n", number);
    printf("%d\n%d\n%d\n", number2, number3,number4);
}

02- 内存存储细节

void memory_storage_details(void) {
    
    /*
     字节    变量         内容
     ffc1
     
     ffc2    number2    0000 1101
     ffc3               0000 0000
     ffc4               0000 0000
     ffc5               0000 0000
     
     ffc6    number     0000 1100
     ffc7               0000 0000
     ffc8               0000 0000
     ffc9               0000 0000
     */
    
    // 一个int类型数据占据4个字节、32bit
    // 0000 0000 0000 0000 0000 0000 0000 1100
    int number = 12; // 1100
    
    // 0000 0000 0000 0000 0000 0000 0000 1101
    int number2 = 13; // 1101
    
    printf("%d\n%d\n", number, number2);
}
内存存储细节

03-进制转换

void hexadecimal_conversion(int n) {
    
    /*
     1.二进制转十进制
     0b1100 = 0 * 2的0次方 + 0 * 2的1次方 + 1 * 2的2次方+ 1 * 2的3次方
     = 0 + 0 + 4 + 8 = 12
     0b1111 = 1 + 2 + 4 + 8 = 15
     0b1010 = 10
     
     2.十进制转二进制
     67 = 64 + 2 + 1 = 2的6次方 + 2的1次方 + 2的0次方
     = 0b1000000 + 0b10 + 0b1
     = 0b1000011
     
     3.n位二进制的取值范围
     2位二进制位的取值范围:0~3  0~2的2次方-1
     3位二进制位的取值范围:0~7  0~2的3次方-1
     n位二进制位的取值范围:0~2的n次方-1
     
     
     4个字节 -> 31bit
     0    000 0000 0000 0000 0000 0000 0000 1100
     0 ~ 2的31次方-1
     */
    
    // 输出一个整数的二进制存储形式
    int bits = sizeof(n) * 8;
    while (bits-->0) {
        printf("%d", n>>bits&1);
        if (bits%4==0) printf(" ");
    }
    printf("\n");
}

04-类型说明符

void type_specifier(void) {
    
    /*
     int 4个字节  %d
     short 2个字节 %d
     long 8个字节  %ld
     long long 8个字节 %lld
     
     signed
     unsigned  %u
     */
    
    // 0000 0000 0000 0000 0000 0000 0000 0000
    // 2的31次方-1
    // 2的32次方-1
    int num;
    
    /*
     signed和unsigned的区别:
     signed 最高位要当做符号位
     unsigned 最高位不要当做符号位
     */
    // signed == signed int
    // signed 有符号:正数、0、负数
    signed int a = 10;
    signed a2 = 10;
    
    // unsigned int == unsigned
    // unsigned 无符号:0、正数
    unsigned int b = 10;
    unsigned b2 = 10;
    
    long unsigned int c = 34343;
    long unsigned c2 = 423432;
    
    short unsigned int d = 4343;
    short unsigned d2 = 43243;
    
    short signed int e = 54354;
    short signed e2 = 434;
}

void longAndShort()
{
    // long == long int
    long int a = 100645654654645645l;
    long a2 = 100645654654645645l;
    
    // long long int == long long
    long long int c = 100645654654645645ll;
    long long c2 = 4535435435435ll;
    
    // short == short int
    short int d = 5454;
    short d2 = 43434;
    
    //printf("%lld\n", c);
    
    int s = sizeof(long long int);
    printf("%d\n", s);
}

05- 位运算

void an_operation(void) {
    
    /* 按位与 &
     
     10101010000
     00000100000
     -------------
     00000000000
     
     10111011
     10101101
     ---------
     10101001
     
     1001
     0101
     -----
     0001
     */
    
    /*
     按位或 |
     1001
     0101
     -----
     1101
     */
    
    
    /*
     按位异或 ^
     1.相同数值进行异或,结果肯定是0,比如9^9
     2.交换 9^5^6 == 9^6^5
     3.任何数值跟0进行异或,结果还是原来的数值,9^0 == 9
     4.a^b^a == a^a^b == 0^b == b
     
     1001
     0101
     -----
     1100
     
     1001
     1001
     -----
     00000
     
     0101
     0000
     ----
     0101
     
     9^5^9 == 9^9^5 = 0^5 = 5
     
     a^b^a == b
     */
    //printf("%d\n", 9^9);
    
    //printf("%d\n", 9 ^ 5);
    
    /*
     按位取反 ~
     ~0000 0000 0000 0000 0000 0000 0000 1001
     1111 1111 1111 1111 1111 1111 1111 0110
     */
    //printf("%d\n", ~9);
    
    /*
     左移 <<
     
     0000 0000 0000 0000 0000 0000 0000 0000
     00 0000 0000 0000 0000 0000 0000 100100
     
     9<<1 -> 9 * 2的1次方 == 18
     9<<2 -> 9 * 2的2次方 ==36
     9<<n -> 9 * 2的n次方
     */
    
    //printf("%d\n", 9<<1);
    
    /*
     右移 >>
     0000 0000 0000 0000 0000 0000 0000 0000
     000000 0000 0000 0000 0000 0000 0000 10
     111111 1111 1111 1111 1111 1111 1111 10
     
     8>>1 -> 8/2 == 4
     8>>2 -> 8/2的2次方 == 2
     8>>n -> 8/2的n次方
     */
    
    printf("%d\n", 8>>3);
}

06-使用位异或运算符交换两个变量的值

void exchange_values_of_two_variables_using_bit_xor_operator(void) {
    
    int a = 10;
    int b = 11;
    
    /* 借助第三方变量
     int temp = a;
     a = b;
     b = temp;
     */
    
    /*
     a = b - a;
     b = b - a;
     a = b + a;
     */
    
    // a^b^a == b
    
    // a -->  10^11
    // b -->  10
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
    
    printf("a = %d, b = %d\n", a, b);
}

07-用位与&运算符判断变量的奇偶性

void determine_parity_variable(void) {
    
    /*
     15: 1111
     9:  1001
     
     14: 1110
     10: 1010
     */
    int a = 15;
    
    /*
    a&1 == 1 // 奇数
    a&1 == 0 // 偶数
     */
    
    /*
     if (a % 2) {
     printf("奇数\n");
     } else {
     printf("偶数\n");
     }
     */
    
    a % 2 == 0 ? printf("偶数\n") : printf("奇数\n");
    
    // a % 2 ? printf("奇数\n") : printf("偶数\n");
}

08-写一个函数,用来输出整数在内存中的二进制形式

void printBinary(int number) {
    
    /*
     0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 1111
     
     9 : 0000 0000 0000 0000 0000 0000 0000 1001
     -10 : 1111 1111 1111 1111 1111 1111 1111 0110
     */
    
    // 记录现在挪到第几位
    // (sizeof(number)*8) - 1 == 31
    int temp = ( sizeof(number) << 3 ) - 1;
    
    while ( temp >= 0 ) {
        // 先挪位,再&1,取出对应位的值
        int value = (number >> temp) & 1;
        printf("%d", value);
        
        //
        temp--;
        
        // 每输出4位,就输出一个空格
        if ( (temp + 1) % 4 == 0 ) {
            printf(" ");
        }
    }
    
    printf("\n");
    
    /*
    int bits = sizeof(number) * 8;
    while (bits-->0) {
        
        int s = number>>bits&1;
        printf("%d", s);
        
        if (bits % 4 == 0) {
            printf(" ");
        }
    }
    printf("\n");
     */
}
上一篇 下一篇

猜你喜欢

热点阅读