C/C++教程

C语言-内存函数

本文主要是介绍C语言-内存函数,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

内存函数

在 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;
}
这篇关于C语言-内存函数的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!