Jump to content

Hello visitors, welcome to the Hacker World Forum!

Red Team 1949  (formerly CHT Attack and Defense Team) In this rapidly changing Internet era, we maintain our original intention and create the best community to jointly exchange network technologies. You can obtain hacker attack and defense skills and knowledge in the forum, or you can join our Telegram communication group to discuss and communicate in real time. All kinds of advertisements are prohibited in the forum. Please register as a registered user to check our usage and privacy policy. Thank you for your cooperation.

TheHackerWorld Official

Featured Replies

Posted

 

内存函数

在 C 语言中,当一个程序被加载到内存中运行,系统会为该程序分配一块独立的内存空间,并且这块内存空间又可以再被细分为很多区域,比如:栈区、堆区、静态区、全局区等

栈区:保存局部变量。存储在栈区的变量,在函数执行结束后,会被系统自动释放。

堆区:由 malloc、calloc、realloc……等函数分配内存。其生命周期由 free 函数控制,在没有被释放之前一直存在,直到程序运行结束。

栈内存

定义在函数内部的局部变量,都保存在栈区。栈区的特点是:函数执行结束后,由系统 “自动回收”局部变量所对应的内存空间。所谓的“自动回收”其实是操作系统将这块栈内存又分配给其他函数中的局部变量使用。

当定义局部变量时,系统会在栈区为其分配一块内存空间,当函数执行结束后系统负责回收这块内存,又分配给其他局部变量使用。

以下代码执行后,会发现输出的a,b变量内存地址是一样的。可以说明局部变量对应的内存在函数执行结束后,会被系统回收分配给其他函数中的局部变量使用。因此,在C语言中,不能将局部变量的地址作为函数返回值返回,否则可能出现问题

#include<stdio.h>

void showA()
{
	int a;
	printf("&a=%p\n",&a);
}

void showB()
{
	int b;
	printf("&b=%p\n",&b);
}

int main(void)
{
	showA();
	showB(); 
	getchar();
	return 0;
}

栈内存:

(1) 由系统自动分配、释放。如:函数形参、局部变量。

(2) 栈内存比较小,在 VS2012 中,栈内存默认最大为 1M,如果局部变量占用的栈内存过大,会发生栈溢出。

#include<stdio.h>
int main(void)
{
int a[9900000];//会产生StackOverflow
getchar();
return 0;
}

堆内存

使用 malloc 系列函数分配的内存都属于堆区,使用完后调用 free 函数进行释放,否则可能会造成内存泄漏(即这块内存无法被再次使用)。

malloc 函数
函数原型: void *malloc(int size);

头文件: #include <stdlib.h>

参数列表: size:分配多少个字节。

功能: 申请指定大小的堆内存。

返回值:如果分配成功则返回指向被分配内存的指针,否则返回空指针 NULL。

void *表示“不确定指向类型”的指针,使用前必须进行强制类型转化,将 void*转化为“确定指向类型”的指针。

free 函数

函数原型: void free(void* ptr);

头文件: #include <stdlib.h>

参数列表: ptr:指向要被释放的堆内存。

功能: 释放 ptr 指向的内存空间。

在C语言中,被 free 之后的堆内存,将会被操作系统回收再分配,不建议继续使用, 否则输出的结果将难以预料。

#include<stdio.h>
#include<stdlib.h>

int main(void)
{
	int *p = (int *)malloc(sizeof(int));//void *类型的返回值必须进行强制类型转化
	*p = 200;
	printf("%p, %d\n", p, *p);//输出指针p所指向的内存地址,输出此内存地址中的值
	free(p);
	getchar();
	return 0;
}

堆内存

(1)由程序员自己申请、释放。如果没有释放,可能会发生内存泄露,直到程序结束后由系统释放。

(2)堆内存比较大,可以分配超过 1G 的内存空间。

函数返回数据的两种方式

  1. 在被调函数中使用 malloc 分配内存,在主调函数中 free 释放内存。
#include<stdio.h>
#include<stdlib.h>

int* getMemory()
{
    int* p_int=(int*)malloc(sizeof(int));//被调函数分配使用内存
    *p_int=100;
    return p_int;
}

int main(void)
{
    int* p=getMemory();
    printf("%d\n",*p);
    free(p); //主调函数释放内存
    getchar();
    return 0;
}

分配内存与释放内存是分开的,容易导致程序员忘记在主调函数中释放内存,从而导致内存泄漏,

2.在主调函数中分配堆内存,在被调函数中使用堆内存,最后又在主调函数中释放堆内存。

#include<stdio.h>
#include<stdlib.h>

void fun(int *p_int)
{
	*p_int=100;
}

int main(void)
{
    int* p=(int*)malloc(sizeof(int)); //主调函数分配堆内存
    fun(p);
    printf("%d",*p);
    free(p); //主调函数释放堆内存
    getchar();
    return 0;
}

此方法较为推荐

使用 malloc 函数分配的堆内存,系统不会初始化内存,分配的内存中还会残留旧数据。因此,引用未初始化的堆内存,输出的数据也将是未知的。

#include<stdio.h>
#include<stdlib.h>

int main(void)
{
int *p_int=(int*)malloc(sizeof(int));
printf("%d",*p_int);//输出随机未知数据
getchar();
return 0;
}

为了避免引用堆内存中的未知数据,一般使用 malloc 在堆区分配内存后,需要将这块堆内存初始化为0

memset

函数原型:void* memset(void *dest, int c, size_t size);
头文件: #include <string.h>
参数列表: dest:被初始化的目标内存区域。 c:要设置的字符。 size:初始化 size 个字节。
功能: 将 dest 指向的内存空间前 size 个字节初始化为 c。 返回值: dest的内存地址。

#include<stdio.h>
#include<string.h>

int main(void)
{
	char arr[10] = {0};
    //会把arr的前5个字节的元素设置为@
	memset(arr, '@',5);
	getchar();
	return 0;
}

memcpy

函数原型:void* memcpy(void* destination, const void* source, size_t num);

memcpy函数会从source指针的位置向后复制num个字节的数据到destination指针指向的内存的位置中
但是source和destination的num个字节的数据在内存中不能有重叠,否则复制的结果是未知的
memcpy可以复制任意类型的数据

#include<stdio.h>
#include<string.h>
 
struct S
{
	int age;
	char name[5];
};

int main(void)
{
	struct S arr1[] = {{18,"abc"}, {22, "456"}};
	struct S arr2[3] = {0};
    //从内存中可以看到,arr1的数据已经拷贝到arr2中
	memcpy(arr2, arr1, sizeof(arr1));
	getchar();
	return 0;
}

简单实现my_memcpy

void* my_memcpy(void* dest, void* source, size_t num)
{
    assert(dest && source);
	void* res = dest;
	while(num--){
		*(char*)dest = *(char*)source;
		++(char*)dest;
		++(char*)source;
	}
	return res;
}

memmove

函数原型:void* memmove(void* destination, const void* source, size_t num);

memmove函数会从source指针的位置向后复制num个字节的数据到destination指针指向的内存的位置中
但是source和destination的num个字节的数据在内存中可以有重叠

memcmp

函数原型:int memcmp(void* ptr1, void* prt2, size_t num);

比较从ptr1指针以及ptr2指针开始的num个字节的数据的大小

#include<stdio.h>
#include<string.h>

int main(void)
{
	int res = 0;
	char arr1[] = {1,2,3,4,5};
	char arr2[] = {1,2,4,5,5};
    //比较
	res = memcmp(arr2, arr1,3);
	printf("%d", res);
	getchar();
	return 0;
}

Create an account or sign in to comment

Recently Browsing 0

  • No registered users viewing this page.