首页 > 系统相关 >C语言 内存操作函数

C语言 内存操作函数

时间:2024-06-21 22:59:32浏览次数:28  
标签:函数 int void C语言 16843009 内存 printf array include

内存管理

进程空间

程序,是经源码编译后的可执行文件,可执行文件可以多次被执行,比如我们可以
多次打开 office。
而进程,是程序加载到内存后开始执行,至执行结束,这样一段时间概念,多次打
开的 wps,每打开一次都是一个进程,当我们每关闭一个 office,则表示该进程结束。
程序是静态概念,而进程动态/时间概念。

进程空间图示

在这里插入图片描述

栈内存(Stack)

栈存储的特点

栈中存放任意类型的变量,但必须是 auto 类型修饰的,即自动类型的局部变量,
随用随开,用完即消。
内存的分配和销毁系统自动完成,不需要人工干预。

栈大小

栈的大小并不大,他的意义并不在于存储大数据,而在于数据交换。

[root@localhost ~]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size
(blocks, -f) unlimited
pending signals                 (-i) 16384
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues
(bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
//10M
cpu time               (seconds, -t) unlimited
max user processes              (-u) 16384
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

堆内存(Heap)

堆存储的特点

堆内存可以存放任意类型的数据,但需要自己申请与释放

堆大小

堆的大小受限于系统的内存大小,一般为物理内存的 1/4 到 1/2。

测试申请大空间

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
    int * p = (int*)malloc(1024*1024*1024); //1G 完全无压力
    if(p == NULL)
    {
        printf("malloc error\n");
        return -1;
    }
    int *q = (int*)malloc((unsigned int)-1);
//无力归天 42 亿个字节 避免整型溢出
    if(q == NULL)
    {
        printf("malloc error\n");
        return -1;
    }
    return 0;
}

堆内存的申请与释放

malloc()

函数声明
void * malloc(size_t _Size);
函数功能

申请指定大小的堆内存空间,并返回指向该空间的指针。

函数参数
  • _Size:要申请的堆内存空间的大小,以字节为单位。
  • 返回值:
  • 成功:返回指向新分配的堆内存空间的指针。
  • 失败:返回 NULL。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
//申请基本数据类型和数组,栈堆空间作对比。
    int a; int *p = &a;
    a = 100; printf("*p = %d\n",a);
    int *pm = (int*)malloc(sizeof(int));
    if(pm == NULL) return -1;
    *pm = 100;
    printf("*pm = %d\n",*pm);
//申请基本数据类型和数组,栈堆空间作对比。
    int array[10]; int *pa = array;
    pm = (int*)malloc(10*sizeof(int));

    for(int i=0; i<10; i++)
    {
        printf("%d\n",pm[i]);
    }
    free(pm);
    return 0;
}

calloc()

函数声明
void * calloc(size_t _Num, size_t _Size);
函数功能

申请指定大小的堆内存空间,并返回指向该空间的指针。自动清零。

函数参数
  • _Num:要申请的堆内存空间的个数。
  • _Size:要申请的堆内存空间的大小,以字节为单位。
  • 返回值:
  • 成功:返回指向新分配的堆内存空间的指针。
  • 失败:返回 NULL。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
    int * array = (int*)calloc(10,sizeof(int));
    for(int i=0; i<10; i++)
    {
        printf("%d\n",array[i]); //己被初始化。
    }
    return 0;
}

realloc()

函数声明
void * realloc(void * ptr, size_t size);
函数功能

调整指定指针所指向的堆内存空间的大小,并返回调整后的指针。

函数参数
  • ptr:指向要调整的堆内存空间的指针。
  • size:新的堆内存空间的大小,以字节为单位。
  • 返回值:
  • 成功:返回指向调整后的堆内存空间的指针。
  • 失败:返回 NULL。
    返回的指针,可能与 ptr 的值相同,也有可能不同。
    若相同,则说明在原空间后面申请,否则,则可能后续空
    间不足,重新申请的新的连续空间,原数据拷贝到新空间,
    原有空间自动释放。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
    int * array = (int*)calloc(10,sizeof(int));
    int * newArray = realloc(array,80);
//array = realloc(array,80);
    if(newArray == NULL)
    {
        printf("realloc 失败\n");
        return -1;
    }
    for(int i=0; i<20; i++)
    {
        printf("%d\n",newArray[i]);
    }
    return 0;
}

free()

函数声明
void free(void * ptr);
函数功能

释放指定的堆内存空间。

函数参数
  • ptr:指向要释放的堆内存空间的指针。
  • 返回值:无。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
    int * array = (int*)calloc(10,sizeof(int));
    free(array);
    return 0;
}

应用

动态数组

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

// 主函数
int main()
{
    int len;
    printf("请输入新的长度:");  // 提示用户输入新长度
    scanf("%d", &len);  // 读取用户输入的长度

    int *p = (int*)realloc(NULL, sizeof(int) * len);  // 为指针分配内存空间

    // 打印初始分配的内存空间中的值
    for(int i = 0; i < len; i++)
    {
        printf("%d\n", p[i]);
    }

    // 增加大小
    printf("请输入新的长度:");  // 提示用户输入新长度
    scanf("%d", &len);  // 读取用户输入的长度
    p = (int*)realloc(p, sizeof(int) * len);  // 重新分配内存空间

    // 打印重新分配的内存空间中的值
    for(int i = 0; i < len; i++)
    {
        printf("%d\n", p[i]);
    }

    // 减小大小
    printf("请输入新的长度:");  // 提示用户输入新长度
    scanf("%d", &len);  // 读取用户输入的长度
    p = (int*)realloc(p, sizeof(int) * len);  // 重新分配内存空间

    // 打印重新分配的内存空间中的值
    for(int i = 0; i < len; i++)
    {
        printf("%d\n", p[i]);
    }

    free(p);  // 释放内存空间
    return 0;
}

置空与判空

堆内存使用的逻辑是这样的,申请,判空,使用/释放(配对),置空。常见错误
之一就是释放以后置未置为 NULL 再次作判空使用 或 释放以后继续非法使用。

char*p=(char*)malloc(100);
strcpy(p,"hello");
free(p);/*p 所指的内存被释放,但是 p 所指的地址仍然不变*/
//p = NULL;忘了此句,后而又用到了
.......
if(NULL!=p)
{
/*没有防错*/
strcpy(p,"hello");
/*出错*/
}

重复申请

while (1)
{
char *p = malloc(1000);
printf("xxxxxx\n");
printf("xxxxxx\n");
printf("xxxxxx\n");
printf("xxxxxx\n");
p = malloc(1000);
// 中途可能忘了,重复申请,内存泄漏
free(p);
printf("xxxxxx\n");
Sleep(10);
}

谁申请谁释放模型(并非绝对)

如果没有协同的原则,则有可能会造成,重复释放

void func(char *p)
{
strcpy(p, "American");
printf("%s\n", p);
free(p);
//此处违反了,,谁申请谁释放的原则。
}
int main()
{
char * p = malloc(100);
func(p);
free(p);
return 0;
}

内存操作函数

memcpy

实现两段空间的拷贝,从源地址src开始,拷贝n个字节到目的地址dest。

void * memcpy(void *dest, const void *src, size_t n);
  • dest:目的地址。
  • src:源地址。
  • n:拷贝的字节数。
#include <stdio.h>
#include <string.h>

int main(void)
{
    int a[10] = {1,2,3,4,5,0,6,7,8,9}; // 定义整型数组a
    int b[10];  // 定义整型数组b
    memcpy(b, a, 10 * sizeof(a[0]));  // 使用memcpy函数对整型数组进行拷贝
    for(int i = 0; i < 10; i++)
    {
        printf("%d\n", b[i]);  // 输出拷贝后的整型数组b
    }
    printf("***************\n");

    char c[10] = {'a','b','c','d','\0','\n','e','f','g','h'};  // 定义字符数组c
    char d[10];  // 定义字符数组d
    memcpy(d, c, 10 * sizeof(a[0]));  // 使用memcpy函数对字符数组进行拷贝
    for(int i = 0; i < 10; i++)
    {
        printf("%c\n", d[i]);  // 输出拷贝后的字符数组d
    }
    printf("***************\n");

    puts(d);  // 输出字符数组d
    return 0;
}

输出:

1
2
3
4
5
0
6
7
8
9
***************
a
b
c
d



e
f
g
h
***************
abcd

memmove

实现两段空间的移动,从源地址src开始,移动n个字节到目的地址dest。
void * memmove(void *dest, const void *src, size_t n);
  • dest:目的地址。
  • src:源地址。
  • n:移动的字节数。
#include <stdio.h>
#include <string.h>

//实现删除数组中某一个元素,后序元素依次向前,返回新的元素个数。
int deleteArrayByIdx(int *array, int idx, int count)
{
    memmove(array + idx, array + idx + 1, (count - (idx + 1)) * sizeof(*array));
    return count - 1;
}

int main()
{
    int array[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
    int count = sizeof(array) / sizeof(array[0]);
    count = deleteArrayByIdx(array, 2, count);
    for (int i = 0; i < count; i++)
    {
        printf("%d\n", array[i]);
    }
    return 0;
}

输出:

1
2
4
5
6
7
8
9
0

memcmp

实现两段内存的比较,从地址src1开始,比较n个字节,如果相同,返回0,如果不同,返回第一个不同的字节的差值。

int memcmp(const void *src1, const void *src2, size_t n);
  • src1:源地址1。
  • src2:源地址2。
  • n:比较的字节数。

memchr

查找一段空间中的一个字符,若存在则返回,所查找到字符的指针,若无,返回 NULL。

void * memchr(const void *s, int c, size_t n);
  • s:源地址。
  • c:要查找的字符。
  • n:查找的字节数。

memset

将一段空间中的字节设置为指定的值,返回指向修改后的空间的指针。最小单位是字节

void * memset(void *s, int c, size_t n);
  • s:源地址。
  • c:要设置的字符。
  • n:设置的字节数。
#include <stdio.h>
#include <string.h>
int main()
{
    
    char buf[1024];
    //memset(buf,0,1024); //将buf数组中所有元素设置为0
    memset(buf,0,1024*sizeof(char)); //这样作更安全
    //memset(buf,'a',1024); //这样作很危险 因为会将buf数组中所有元素设置为'a'
    printf("buf = %s \n",buf);
    strcpy(buf,"china is great\n");
    printf("buf = %s \n",buf);
    int array[10];
    //memset 函数将整型数组中的每个字节设置为十进制数值 1
    //整型数组 array 的每个元素通常占用4个字节(32位),因此memset函数会将每个4字节的区块都设置为十进制数值 16843009。\
    //十进制数值 16843009 对应的二进制表示是 00000001000000010000000100000001
    memset(array,1,10*sizeof(int));//hex 01010101 -> dec 1684 3009
    for(int i=0; i<10; i++)
    {
        printf("%d\n",array[i]);
    }
    return 0;
}

输出:

buf =
buf = china is great

16843009
16843009
16843009
16843009
16843009
16843009
16843009
16843009
16843009
16843009

y[10];
//memset 函数将整型数组中的每个字节设置为十进制数值 1
//整型数组 array 的每个元素通常占用4个字节(32位),因此memset函数会将每个4字节的区块都设置为十进制数值 16843009。
//十进制数值 16843009 对应的二进制表示是 00000001000000010000000100000001
memset(array,1,10*sizeof(int));//hex 01010101 -> dec 1684 3009
for(int i=0; i<10; i++)
{
printf(“%d\n”,array[i]);
}
return 0;
}

输出:

buf =
buf = china is great

16843009
16843009
16843009
16843009
16843009
16843009
16843009
16843009
16843009
16843009

标签:函数,int,void,C语言,16843009,内存,printf,array,include
From: https://blog.csdn.net/gopher9511/article/details/139725878

相关文章

  • 【C语言】16.动态内存管理
    文章目录1.为什么要有动态内存分配2.malloc和free2.1malloc2.2free3.calloc和realloc3.1calloc3.2realloc4.常见的动态内存的错误4.1对NULL指针的解引⽤操作4.2对动态开辟空间的越界访问4.3对⾮动态开辟内存使⽤free释放4.4使⽤free释放⼀块动态开辟内存的⼀部......
  • 用C语言实现扫雷
    开发工具:VS2022;创建三个文件第一个头文件:game.h游戏的数据类型和函数声明的位置//游戏的数据类型和函数声明#define_CRT_SECURE_NO_WARNINGS#pragma#include<stdio.h>#include<stdlib.h>#include<time.h>#defineEASY_COUNT10#defineROW9#defineCOL9#de......
  • c语言程序实验————实验报告十三
    c语言程序实验————实验报告十三实验项目名称:实验报告十三结构体运用程序设计实验项目类型:验证性实验日期:2024年5月30日一、实验目的1.掌握结构体类型变量的定义和使用2.掌握结构体类型数组的概念和应用3.掌握结构体类型指针的概念和应用4.掌握共用体的概念和......
  • word中如何插入“映射函数Ψ“及其它数学符号
    目录 操作步骤1.符号2.字体3.其它符号 操作步骤1.符号(1).插入-符号-其他符号(M)。如图1图1 2.字体(1).将字体更改为:CambriaMath(2).将滚动条拖拽到最底,然后点动向上调整10次,即可看到这个符号。如图2(3). 版本:office163.其它符号(1).其它符号都在Camb......
  • Go 内存模型与分配机制
    ......
  • c语言程序实验————实验报告十二
    c语言程序实验————实验报告十二实验项目名称:实验报告十二用指针处理函数与数组实验项目类型:验证性实验日期:2024年5月30日一、实验目的1.掌握指针变量的定义格式,会定义和使用指针变量2.能正确建立指针变量与数组(包括一维、两维和字符串数组)的联系,并正确使用指......
  • C语言--指针详解(二)
    C语言--指针详解(二)一.前言二.指针运算(1)指针+-整数(2)指针-指针(3)指针的关系运算三.指针类型分类及详解(1)整型指针(2)浮点型指针(3)字符指针(4)特殊指针类型void*(5)函数指针(6)数组指针(7)结构体指针五.指针与数组5.1数组名的理解5.2数组指针5.3指......
  • 【C++】priority_queue的模拟实现与仿函数
    文章目录1.优先级队列的介绍与使用1.1介绍1.2使用2.模拟实现2.1push2.2pop2.3top、empty、size2.4迭代区间构造3.仿函数1.优先级队列的介绍与使用1.1介绍优先级队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。......
  • 一文读懂Java多线程并发之内存模型
     什么是内存模型?Java内存模型(JavaMemoryModel)描述了Java编程语言中的线程如何与内存进行交互,是和多线程相关的一组规范,需要各个JVM的实现来遵守JMM规范,以便于开发者可以利用这些规范,更方便地开发多线程程序。有了这些规范,即便同一个程序在不同操作系统的虚拟机上运行......
  • C++list类的常见函数以及其模拟实现
    文章目录前言一、list内部成员有什么?二、构造函数以及析构函数1.默认构造2.传参构造3.迭代器构造4.深拷贝以及运算符=的重载1.深拷贝2.=的重载5.析构函数三、迭代器的模拟实现1.正向迭代器2.反向迭代器四、常见函数及其实现1.insert函数2.erase函数3.clear函数4.push_......