zoukankan      html  css  js  c++  java
  • 【C】Re08 内存

    一、概述

    程序运行之后,所有的数据加载到内存上

    内存会被操作系统进行分区处理,

    划分的区域主要分为4个:

    【1、代码文本区 text】

    存放开发者编写的代码文本,二进制内容形式

    【2、静态全局区 StaticGlobal】 数据区 + 未初始化数据区(data + bss)

    存放各种形式的变量和常量(全局变量,静态变量,常量)

    常量会在静态全局区中单独划分一个区域存储

    【3、栈区 Stack】 

    该区域存储容量小。

    存放局部变量,函数的形参,函数返回值(大于4字节的,小于4字节存放在寄存器中)

    【4、堆区 Heap】

    该区域存储容量大。

    malloc函数申请的内存会放在堆中

    #include <stdio.h>
    #include <stdlib.h>
    
    // 全局变量 全局区
    int global_a = 100; // mem-addr g-a -> 0000000000403010
    int global_b = 200; // mem-addr g-b -> 0000000000403014
    
    // 全局常量 全局区
    const int gca = 100; // 0000000000404000
    const int gcb = 200; // 0000000000404004
    
    void fun() {
    
        // 局部变量 栈区
        int a = 100; //  mem-addr a -> 000000000061FDEC
        int b = 200; //  mem-addr b -> 000000000061FDE8
    
        // 静态局部变量 全局区
        static int sa = 100; // mem-addr sa -> 0000000000403018
        static int sb = 200; // mem-addr sb -> 000000000040301C
    
        // 局部常量 栈区
        const int ca = 100; // 000000000061FDDC
        const int cb = 200; // 000000000061FDD8
    
        // 堆区
        char * p = malloc(64); // mem-addr malloc(64) -> 00000000001D1460
    
        printf("mem-addr g-a -> %p
    ", &global_a);
        printf("mem-addr g-b -> %p
    ", &global_b);
    
        printf("mem-addr a -> %p
    ", &a); 
        printf("mem-addr b -> %p
    ", &b);
    
        printf("mem-addr sa -> %p
    ", &sa);
        printf("mem-addr sb -> %p
    ", &sb);
    
        printf("mem-addr gca -> %p
    ", &gca);
        printf("mem-addr gcb -> %p
    ", &gcb);
    
        printf("mem-addr ca -> %p
    ", &ca);
        printf("mem-addr cb -> %p
    ", &cb);
    
        printf("mem-addr malloc(64) -> %p
    ", p);
    
        // 字符串常量 全局区
        printf("mem-addr iteral -> %p
    ", &"hello c-language"); // mem-addr iteral -> 0000000000404072
    }
    
    int main() {
        fun();
    
        return 0;
    }

    二、Memset & Memcpy

    memset函数可以直接对内存的存储值进行写入操作

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void functionMemset() {
        // 用于设置内存地址的存储值
        char buffer[64] = "This is a buffer data, can be byte or character";
        printf("buffer is %s
    ", buffer);
    
        // memset(目标变量地址, 统一变更的存储值, 要替换的个数);
        memset(buffer, 'c', 20);
        printf("use memset to change buffer, now buffer is %s
    ", buffer);
    
        // 主要用途是清空内存的存储值
        memset(buffer, 0, 64);
        printf("after use memset(buffer, 0, 64) to clear mem, now buffer is %s
    ", buffer);
    }
    
    int main() {
        functionMemset();
        return 0;
    }

    memcpy 是对内存的存储值进行操作

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void printfArray(char charArr[], int size) {
        for (int i = 0; i < size; ++i) {
            printf("%d ", charArr[i]);
        }
        printf("
    ");
    }
    
    void functionMemCopy() {
        // 复制内存地址的存储值
        char origin[64] = "aaa,  jjj";
        char update[64] = {0};
    
        // 可以使用 strcpy 实现字符复制
        strcpy(update, origin); // 但是遇到会停止复制
        printfArray(update, sizeof(update) / sizeof(char));
    
        memset(update, 0, sizeof(update));
        printfArray(update, sizeof(update) / sizeof(char));
    
        memcpy(update, origin, sizeof(update)); // 使用内存复制则无视字符转移直接复制
        printfArray(update, sizeof(update) / sizeof(char));
    
        // 用途2 给数组进行赋值
        int arr[5] = {1, 2, 3, 4, 5};
        int arr2[5];
    
        memcpy(arr2, arr, sizeof(arr2));
        int size = sizeof(arr2) / sizeof(int);
    
        for (int i = 0; i < size; ++i) {
            printf("%d, ", arr2[i]);
        }
    
        printf("
    ");
    }
    
    int main() {
        functionMemCopy();
        return 0;
    }

    三、Memmove & Memcmp

    移动存储值

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void functionMemMove() {
    
        // 存储值移动的方式1,使用memcpy实现
        int arr[5] = {10, 20, 30, 40, 50};
    
        for (int i = 0; i < 5; ++i) {
            printf("%d ", arr[i]);
        }
        printf("
    ");
        memcpy(arr + 2, arr + 3,  3 * sizeof(int));
    
        for (int i = 0; i < 5; ++i) {
            printf("%d ", arr[i]);
        }
        printf("
    ");
        // -----------------------------------------------------------
        int arr2[5] = {10, 20, 30, 40, 50};
        for (int i = 0; i < 5; ++i) {
            printf("%d ", arr2[i]);
        }
        printf("
    ");
        memmove(arr2 + 2, arr2 + 3,  3 * sizeof(int));
        for (int i = 0; i < 5; ++i) {
            printf("%d ", arr2[i]);
        }
        printf("
    ");
    
        // 演示的效果一样,但是使用memcpy可能会有不一致的情况,memmove效率比cpy低,但是操作安全
    }
    
    int main() {
        functionMemMove();
        return 0;
    }

    存储值比较?

    void functionMemCompare() {
        char str1[32] = "helloword";
        char str2[32] = "hellowords";
    
        if (strcmp(str1, str2) == 0) { // strcmp(str1, str2) == 0
            printf("str1 == str2 false
    ");
        } else {
            printf("str1 == str2 true
    ");
        }
    
        if (memcpy(str1, str2, sizeof(str1)) == 0) { // strcmp(str1, str2) == 0
            printf("str1 == str2 false
    ");
        } else {
            printf("str1 == str2 true
    ");
        }
    }
    
    int main() {
        functionMemCompare();
        return 0;
    }

    四、Malloc函数

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    // C 库函数 void * malloc(size_t size) 分配所需的内存空间,并返回一个指向它的指针。
    void functionMalloc() {
        // 申请的内存区域是堆区区域,里面的内容是随机的,随机应该成上一个被释放的内存地址存储过的值
        int * intTypePointer = malloc(4);
    
        // 查看该地址存放的值
        printf("this mem-addr is %p, value is %d
    ", intTypePointer, *intTypePointer);
    
        // 一些写法的寓意
        int * arr = malloc(sizeof(int) * 10); // 表示申请的是一个数组,元素个数为10
    
        // 注意! malloc 申请的内存空间,直到程序结束之前会一直占用 如果需要释放该内存空间,则调用函数free实现
    
        // malloc有可能申请不到内存空间,因此需要判断一下指针是否存在地址值;
        if (intTypePointer == NULL) { // 为空指针的情况有内存空间申请过大
            printf("Null Pointer");
        }
    }
    void functionMalloc2() {
        int * p = malloc(sizeof(int));
    
        printf("this mem-addr is %p, value is %d
    ", p, *p);
    
        memset(p, 0, sizeof(int));
        printf("this mem-addr is %p, value is %d
    ", p, *p);
    
        *p = 233;
        printf("this mem-addr is %p, value is %d
    ", p, *p);
    
        if (p != NULL) {
            free(p);
        }
    
        printf("this mem-addr is %p, value is %d
    ", p, *p);
    
        *p = 123;
        printf("this mem-addr is %p, value is %d
    ", p, *p);
    }
    int main() {
        functionMalloc2();
        return 0;
    }

    五、内存操作的注意事项

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int * theLocalVariableMemoryAddress() {
        int num = 100;
        printf("num -> %p value -> %d
    ", &num, num);
        return &num; // 函数结束之后 局部变量出栈,内存空间释放, 程序不能再对这个空间进行任何的读写操作
    }
    
    void attentionForMemOperate() {
        // 不要返回局部变量的地址
        int * illegalPointer = theLocalVariableMemoryAddress();
    
        // 但是事实上C语言依然可以同这个非法指针进行控制
    
        // 打印操作:
        printf("illegalPointer -> %p value -> %d
    ", illegalPointer, *illegalPointer);
        printf("illegalPointer -> %p value -> %d
    ", illegalPointer, *illegalPointer);
        printf("illegalPointer -> %p value -> %d
    ", illegalPointer, *illegalPointer);
        printf("illegalPointer -> %p value -> %d
    ", illegalPointer, *illegalPointer);
    }
    
    int main() {
        attentionForMemOperate();
        return 0;
    }

     五、指针形参实参问题

    // 同级指针修饰内存失败
    void allocateSpace(int * doublePointer) {
    
        doublePointer = malloc(sizeof(int));
    
        *doublePointer = 1000;
    
        printf("*doublePointer = %d
    ", *doublePointer);
    }
    
    void allocateSpace2(int ** doublePointer) {
    
        *doublePointer = malloc(sizeof(int));
    
        **doublePointer = 1000;
    
        printf("*doublePointer = %d
    ", **doublePointer);
    }
    
    int main() {
        int * pointer = NULL;
        
        allocateSpace2(&pointer);
        printf("*pointer = %d
    ", *pointer);
    
        allocateSpace(pointer);
        printf("*pointer = %d
    ", *pointer); // 还是形参和实参的问题,实参出栈之后没有变化
        return 0;
    }

    六、安全的销毁指针

    void freePointer(int ** pointer) {
        if (*pointer != NULL) {
            free(pointer); // 释放之后 还需要把指针赋值为空,调用者不可以再访问指针了
            *pointer = NULL;
        }
    }

     

  • 相关阅读:
    trackr: An AngularJS app with a Java 8 backend – Part III
    trackr: An AngularJS app with a Java 8 backend – Part II
    21. Wireless tools (无线工具 5个)
    20. Web proxies (网页代理 4个)
    19. Rootkit detectors (隐形工具包检测器 5个)
    18. Fuzzers (模糊测试器 4个)
    16. Antimalware (反病毒 3个)
    17. Debuggers (调试器 5个)
    15. Password auditing (密码审核 12个)
    14. Encryption tools (加密工具 8个)
  • 原文地址:https://www.cnblogs.com/mindzone/p/13949151.html
Copyright © 2011-2022 走看看