文档章节

黑马程序员-3-C语言学习(内存剖析,进制)

 明天过后1
发布于 2014/09/29 01:36
字数 2298
阅读 50
收藏 0

---------------------- Java培训.Net培训Android培训IOS培训、期待与您交流! ----------------------

1. 进制

    进制是一种表示数值的的形式,电脑存储数据都是以 0 和 1 来存储数据的,因此我们必须了解进制概念。

    a. 进制常用类别

        (1) 十进制 : 

            1) 用0 - 9 来表示数值,如 5 ,17 ,107 等等

            2) 特点 : 数值由0 - 9 之间数字组成,逢九进一

            3) 书写格式 : 直接写出十进制数值

        (2) 二进制 : 

            1) 用 0 和 1 来表示数值,如 0b0101 ,0b111 等

            2) 特点 : 只有0和1,逢2进1

            3)  书写格式:以0b开头

        (3) 八进制 : 

            1) 用 0 - 7 来表示数值,如 07 ,010 等

            2) 特点 : 数值由0 - 7 之间数字组成,逢八进一

            3)  书写格式:以0开头

        (4) 十六进制 : 

            1) 用 0 - F 来表示数值,如 0x9 ,0xA ,0xFF 等

            2) 特点 : 数值由0 - F 之间数字组成,逢十六进一

            3) 书写格式:以0x开头            

    b. printf 函数输出格式控制

格式符 功能
%d
以带符号的十进制形式输出整数 ( 正数不输出正号+ )
%o 以不带符号的八进制形式输出整数
%x 以不带符号的十六进制形式输出整数
%u 以不带符号的十进制形式输出整数
%c 输出一个字符
%s 输出一个或多个字符
%f 以小数形式输出单、双精度,默认输出6位小数
%e 以标准指数形式输出单、双精度数,数字部分小数位数为6位


2. 变量内存存储分析

    a. 内存存储细节特点

        (1) 内存都是以"字节"为存储单位

        (2) 每个"字节"都有相应的存储地址(如下图)

        (3) 变量的存储地址为该变量的存储空间的首地址

        (4) 变量的类型是指针访问内存的寻址方式(比如 : int 类型告诉指针从改变量地址开始一次寻址4个字节)

        (5) 复杂变量内存分配符合内存对齐算法

            

    b. 变量存储

        (1) 变量类型分配空间的大小跟编译器有关

            


16位编译器 32位编译器 64位编译器
char 1
1 1
int 2 4 4
float 4 4 4
double 8 8 8

        (2) 变量内存分配存储特点   

            1) 内存寻址方式由大到小

            2) 内存中存储的都是二进制形式

            3) 变量的地址是该变量的首地址

    #include <stdio.h>    
    /*
        变量内存分配原则:
        从高地址向低地址分配空间给变量
    */
    int main(){
        int a;
        int b;
        printf("a address = %p\n",&a);  // 打印结果 :  a address = 0028FF44
        printf("b address = %p\n",&b);  // 打印结果 :  b address = 0028FF40
        
        system("pause");
        return 0;    
    }

    c. 负数在内存中存储

        (1) 了解负数存储形式前,先学习原码,反码,补码的概念

              1) 原码 : 最高位为符号位, 0代表正数,1代表负数,其余位数用来表示数值大小。

                    如 1 的原码 : 0000 0000 0000 0000 0000 0000 0000 0001 

                        -1的原码 : 1111 1111 1111 1111 1111 1111 1111 1111

             2) 反码 : 正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外.

                    如 1 的反码 : 0000 0000 0000 0000 0000 0000 0000 0001

                        -1的反码 : 1000 0000 0000 0000 0000 0000 0000 0000

             3) 补码 : 原码符号位不变,先将原码减去1,最后数值各位取反

                    如 1 的补码 : 0111 1111 1111 1111 1111 1111 1111 1111

                       -1 的补码 : 1000 0000 0000 0000 0000 0000 0000 0001

        (2) 十进制正整数求负整数方式:

            首先了解二进制加减法运算法则 :       

            0-0=1-1=0 

            1-0=1 

            0-1=1(向高位借位) 

            十进制运算 : 0 - 1 = -1;

            把这条等式转化为二进制来运算 : 

                0000 0000 0000 0000 0000 0000 0000 0000   // 0

             -  0000 0000 0000 0000 0000 0000 0000 0001  // 1

        -----------------------------------------------------------------

              1 1111 1111 1111 1111 1111 1111 1111 1111

            由于整数在内存中只存储32为因此上述结果会舍弃第33位 , 那么 -1 二进制 表示方式 : 1111 1111 1111 1111 1111 1111 1111 1111

        (3) 为了方便我们可以把正负整数转化转化为以下规律 : 

            求一个二进制的相反数 : 符号位+1,数值位为取该数的补码数值位


3. 类型说明符

    a. short 和 long

        short == short int

            long == long int

            long long == long long int

        不同编译器对这些类型分配空间规则不一样 :

            

        由于编译器众多,因此需要一个约定来规范 :         

                short跟int至少为16位(2字节)

                long至少为32位(4字节)

                short的长度不能大于int,int的长度不能大于long

                char一定为为8位(1字节),毕竟char是我们编程能用的最小数据类型


            由于这些数据类型都是有符号的,因此它们的取值范围可以根据它们内存中存储的二进制形式进行推敲 :

                如 : short 占用 2 个byte ,16位 最高位为符号位,取值范围可以这样表示 : -2^15 ~ (2^15 ) - 1  

                其它类型以此类推

    b. signed 和 unsigned

            signed 和 unsigned 主要用来描述该类型的最高位是否用来充当符号位,当然如果不用来充当符号位那么该类型就没有负数部分;

                signed : 表示有符号,就是说最高位充当符号位  // signed int == int 取值范围 : -2^31 ~ (2^31 ) - 1  

                unsigned : 表示没有符号,也就是说最高位不用来充当符号位 // unsigned int 取值范围 : 0~2^32 -1


4. 位运算

    学习位运算前首先得了解数值而二进制表示方式。

    a. & 按位与

        运算法则 : 两个数的二进制位对齐,逐位比较,两个二进位均为1时,结果位才为1,否则为0。

            如 9 & 5 = 1

                0000 0000 0000 0000 0000 0000 0000 1001

          &   0000 0000 0000 0000 0000 0000 0000 0101

         -----------------------------------------------------------------

           0000 0000 0000 0000 0000 0000 0000 0001

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

    b. | 按位或

        运算法则 : 两个数的二进制位对齐,逐位比较,二进位有一个为1时,结果位就为1,否则为0。

            如 9 | 5 = 13

                    0000 0000 0000 0000 0000 0000 0000 1001

              |     0000 0000 0000 0000 0000 0000 0000 0101

         -----------------------------------------------------------------

             0000 0000 0000 0000 0000 0000 0000 1101

    c. ^ 按位异或

        运算法则 : 两个数的二进制位对齐,逐位比较,(不相同)时,结果为1,否则为0 

            如 9 ^ 5 = 12

                    0000 0000 0000 0000 0000 0000 0000 1001

              ^    0000 0000 0000 0000 0000 0000 0000 0101

         -----------------------------------------------------------------

             0000 0000 0000 0000 0000 0000 0000 1100

            规律 :          

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

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

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

        

        /*
            利用^交换两个变量的值
        */
        int main(){
            int a =10;
            int b =100;
            a = a ^ b; // a--> a ^ b
            b = a ^ b; // b--> a ^ b ^b == 10
            b = a ^ b; // b--> a ^ b ^ a ^ b ^b ==100
        }

    d. ~ 取反

        运算法则 : 对整数的各二进位进行取反,符号位也取反(0变1,1变0)

                如 ~9 = -10

                ~  0000 0000 0000 0000 0000 0000 0000 1001

         -----------------------------------------------------------------

                    1111 1111 1111 1111 1111 1111 1111 0110

    e. << 左移

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

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

    f. >> 右移

      运算法则 : 

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

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

            为负数时,符号位为1,最高位是补0或是补1 取决于编译系统的规定


5. 位运算符的应用( 二进制字符串 和 整数之间的转换 )

    a. 打印出整数的二进制字符串

      /*
        把一个整数打印出它的二进制字符串
        num : 所要打印的整数
     */
    void printBinary(int num){
        // 总共要打印多少位数字
        int size = sizeof(num) * 8;
        printf("size = %d\n",size);
        while ( size > 0 ) {
            // 每打印4位数字输出一个空格
            if ( size % 4 ==0 ) {
                printf(" ");
            }
            size --;
            printf("%d",(num >> size) & 1);
             
        }
        printf("\n");
         
    }

    b. 二进制字符串转化为整数

/*
    计算一个二进制字符串的整数值
    例如 : 0000 0000 0000 0000 0000 0000 0000 0110  --> 6
    参数 : const char *s 所要计算的二进制字符串,字符必须为32位自能包含空格(可选),或则0 和1
    返回计算结果
  
 */
int strToInt(const char *s){
    // 最总计算的值
    int num = 0;
    int i = 0;
    unsigned long size = strlen(s);
   // printf("size = %ld\n",size);
    char c = 'a';
    // 遍历该字符串
    while ( size > 0 ) {
        // 从最后一个字符取出字符来进行检查
        c = s[size-1];
        if ( c == '0' || c == '1' ){ // 如果是0 和 1
            num += ( c == '1' ? 1 << i : 0 );
            i++;
            size--;
        } else if ( c == ' ' ){
            size--;
            continue;
        } else {
            return -1;
        }
         
    }
    return num;
}




---------------------- Java培训.Net培训Android培训IOS培训、期待与您交流! ---------------------- 

 详情请查看:http://edu.csdn.net/heima

 

© 著作权归作者所有

共有 人打赏支持
粉丝 2
博文 23
码字总数 36166
作品 0
佛山
私信 提问
黑马程序员.bobo.DAY.2

class VarDemo{public static void main(String[] args){System.out.println(60);System.out.println(0x3c);}} 11002(0)+12(1)+12(2)= 数值2(0)+数值2(1)+数值2(2) 0 0 1 1 0 1 0 1 =128 64 ......

BobbyLou
2015/05/14
0
0
C++中引用和匿名对象的理解和本质剖析

大家对C++的引用应该都不陌生吧,抱着既要知其然,也要知其所以然的态度。 下面将按照是什么?怎么用?为什么需要?本质剖析的流程来想大家一一描述。 引用时什么? 引用其实就是给变量起的一...

沙米笔记
2016/04/10
2.5K
24
C语言自学完备手册(27)——指针(1)

版权声明: https://blog.csdn.net/lfdfhl/article/details/83105627 自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–o...

谷哥的小弟
2018/10/17
0
0
关于二维指针强制转换及传递的简单剖析

关于二维指针强制转换及传递的简单剖析。 C语言中的两大利器:强制转换、指针。很多小伙伴在学习C语言的过程中都遇到过一支拦路虎,那就是指针。 C很自由,但是自由同样暗示着你需要付出更多...

so_foolish
2017/04/01
0
0
八、数组

说明:这个C语言专题,是学习iOS开发的前奏。也为了让有面向对象语言开发经验的程序员,能够快速上手C语言。如果你还没有编程经验,或者对C语言、iOS开发不感兴趣,请忽略 为了让大家更好地学...

长平狐
2013/03/28
64
0

没有更多内容

加载失败,请刷新页面

加载更多

大数据教程(11.9)hive操作基础知识

上一篇博客分享了hive的简介和初体验,本节博主将继续分享一些hive的操作的基础知识。 DDL操作 (1)创建表 #建表语法CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name [(col_name ...

em_aaron
今天
0
0
OSChina 周四乱弹 —— 我家猫真会后空翻

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @我没有抓狂 :#今天听这个# 我艇牛逼,百听不厌,太好听辣 分享 Led Zeppelin 的歌曲《Stairway To Heaven》 《Stairway To Heaven》- Led Z...

小小编辑
今天
2
0
node调用dll

先安装python2.7 安装node-gyp cnpm install node-gyp -g 新建一个Electron-vue项目(案例用Electron-vue) vue init simulatedgreg/electron-vue my-project 安装electron-rebuild cnpm ins......

Chason-洪
今天
3
0
scala学习(一)

学习Spark之前需要学习Scala。 参考学习的书籍:快学Scala

柠檬果过
今天
3
0
通俗易懂解释网络工程中的技术,如STP,HSRP等

导读 在面试时,比如被问到HSRP的主备切换时间时多久,STP几个状态的停留时间,自己知道有这些东西,但在工作中不会经常用到,就老是记不住,觉得可能还是自己基础不够牢固,知识掌握不够全面...

问题终结者
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部