stack space and heap space

The memory occupied by a program compiled by C/C++ is divided into the following parts:
 1. The stack area (stack): it is automatically allocated and released by the compiler, which stores the parameter values ​​of functions, the values ​​of local variables, etc. The operation method is similar to A stack of data structures.
 2. Heap area: generally allocated and released by the programmer. If the programmer does not release it, it may be reclaimed by the OS at the end of the program. It is worth noting that it is different from the heap of the data structure, and the allocation method is similar to the data structure. A linked list of structures.
 3. Global area (static): also called static data memory space, which stores global variables and static variables. Global variables and static variables are stored in one area, and initialized global variables and static variables are placed in the same area. Another adjacent area is released by the system after the program ends.
 4. Text constant area: The constant string is placed here, and is released by the system after the program ends.
 5. Program code area: store the binary code of the function body.

1. Stack space
1.1 Automatically release memory without code operation
  The local variables int, local arrays, etc. defined in the program are stored in the stack space. The stack space has a distinctive feature: the variables defined in the function are out of the function scope, and the memory space occupied by them is automatically released. However, the size of the stack space has a maximum limit, which is not suitable for allocating large space;
  therefore, because the stack space is released when it is out of the function scope, it is not suitable for memory requirements to be used elsewhere. Its biggest advantage is that it does not require the programmer to manually release the memory.
1.2 Don't return pointers to local variables as return values
  ​​First, let's take a look at the following code, where the getData function returns a pointer of type int array, and the getData2 function returns another pointer of type int array:

    int *getData()
    {
        int nums[10]={1,2,3,4,5,6,7,8};
        return nums;
    }
    
    int *getData2()
    {
        int aaa[10]={8,7,6,5,4,3,2,1};
        return aaa;
    }

  We first call the getData function in the main function to see if we can get the first three elements of the nums array:

    int main(int argc, char *argv[])
    {
        int *nums = getData();
        printf("%d,%d,%d\n",nums[0],nums[1],nums[2]);
        return 0;
    }

  The running result is shown in the figure below. We found that it is OK. It turns out that the pointer of the local variable can be returned as the return value!

  However, if we call the getData2 function after calling the getData function, will the nums array be printed correctly? Take a look at the execution sequence below:

    int main(int argc, char *argv[])
    {
        int *nums = getData();
        getData2();
        printf("%d,%d,%d\n",nums[0],nums[1],nums[2]);
        return 0;
    }

  Before printing, we executed the getData2 function again, so what about the running result, take a look at the following figure:

  At this time, I suddenly felt that sadness burst! It was still good just now!

  So, the question is, why is this? We just mentioned that the stack is automatically allocated and released by the system, and the life cycle of the local variables inside the function is only in the function cycle. As long as the function is executed, the life cycle of the local variables inside it will end. Therefore, when we execute the first code, the memory area of ​​the array pointed to by the nums pointer may have been released, but the data has not been cleaned up, that is, it is still there. However, after we execute the second sentence of code, an array aaa is defined in the getData2 function, which occupies the memory of the stack space just released, so the area pointed to by nums is aaa. When the second sentence of code is executed, aaa is released again, but its data is still not cleared there, which is the dirty memory area mentioned in the previous articles. So, the final display is 8,7,6 instead of 1,2,3.

2. Heap space
2.1 Technical control all like to drive manual transmission cars

  The biggest advantage of the stack space just mentioned is that the stack space is released when it is out of the function scope, and the programmer does not need to release it manually. Just like an automatic transmission car, we do not need to increase or decrease gears. But what if we control the allocation of memory to ourselves? At this time, you can use the heap space for storage, and the heap space can store large memory that the stack space cannot store. Here, we can use the malloc function to allocate a block of memory of a specified size in the heap space. After it is used up, call the free function to release the memory in time.

    // malloc(要分配的字节数)
    int *nums = (int*)malloc(sizeof(int)*10);
    nums[0]=1;
    nums[1]=8;
    free(nums);

  It should be noted that the size of bytes occupied by the memory to be allocated needs to be specified in the malloc function.
2.2 Several solutions for returning pointers from functions
  (1) malloc in the method, free by the caller when used up.
  Here we can combine malloc and free to solve the problems we encounter in the stack space, rewrite the above code as follows:

    int *getData()
    {
        int *nums = (int*)malloc(sizeof(int)*10);
        nums[0]=1;
        nums[1]=8;
        nums[2]=3;
        return nums;
    }
    int *getData2()
    {
        int *nums = (int*)malloc(sizeof(int)*10);
        nums[0]=2;
        nums[1]=7;
        nums[2]=5;
        return nums;
    }
    int main(int argc, char *argv[])
    {
        int *numsptr = getData();
        int *numsptr2 = getData2();
        // numptr[1]等价于*(numptr+1)
        printf("%d,%d,%d\n",numsptr[0],numsptr[1],numsptr[2]);
        // 不要忘记释放内存
        free(numsptr);
        free(numsptr2);
        return 0;
    }

  Here we have changed all the pointers to be returned to dynamically allocated using malloc, call free in the main function to manually release the memory, and take a look at the running results:

  This time, the output is still the data of the memory area pointed to by the pointer returned by the getData function. There is no cross influence, perfect!
  (2) Define local variables as static

    char *getStr()
    {
        static char strs[]="afsafdasfdsdfsaddafafafasdfadfs";
        return strs;
    }
    int main(int argc, char *argv[])
    {
        char* strsptr = getStr();
        return 0;
    }

  As can be seen from the beginning of this article, in addition to stack space and heap space, there is also a global area, which will not be released until the end of the program.
  But, it should be noted that it is not suitable for multi-threaded calls. If you want to save the returned content, you need the caller to make a copy as soon as possible.
  (3) (recommended) The caller allocates memory space, just sends the pointer to the function, and the function copies the data into the memory.
  How to understand here, that is, three steps, the first step: allocate memory space by the caller ; Step 2: Pass the pointer to the function; Step 3: Copy the data to the memory inside the function. Let's take a small case: analyze the file name and extension from the file name, and see how these three steps are implemented.

 

    // Step3:函数内部把数据拷贝到内存中
    void parseFileName(char* filename,char* name,char* ext)
    {
        char *ptr = filename;
        while(*ptr != '\0')
        {
            ptr++;
        }
        // 记录结尾的指针
        char *endPtr = ptr;
        //ptr移动到了字符串的结尾,再把ptr移动到"."的位置
        while(*ptr != '.')
        {
            ptr--;
        }
        // 两个指针相减表示两个指针相隔的元素的个数
        memcpy(name,filename,(ptr-filename)*sizeof(char));
        memcpy(ext,ptr+1,(endPtr-ptr)*sizeof(char));
    }
    int main(int argc, char *argv[])
    {
        // Step1:由调用者分配内存空间
        char str[] = "[TK-300]美.女.avi";
        char name[20] = {0};
        char ext[20] = {0};
        // Step2:只是把指针传递给函数
        parseFileName(str,name,ext);
        printf("解析完成:\n");
        printf("文件名:%s,后缀:%s\n",name,ext);
       
        return 0;
    }

  This method avoids the function returning the pointer. The memory manually allocated by the programmer is all in the stack space, and then the function is internally processed and then the logically processed data is stored in the specified area in the stack space, and finally the main function. Access the modified memory region. The result of this operation is shown in the following figure:

  Although the file name is a bit evil, the function is still complete, ouch, not bad!

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324504863&siteId=291194637