动态内存分配
malloc
-
头文件:
#include <stdlib.h>
-
函数功能:
void *malloc(size_t size)
分配所需的内存空间,并返回一个指向它的指针 -
函数原型:
-
函数名:
malloc
-
形参:
size_t size
内存块大小,以字节为单位。本质是unsigned int
-
返回值类型:
void*
返回一个指针,指向已分配大小的内存,若请求失败,返回NULL
-
int *p = (int *)malloc(4); //注意刚开始为void类型,需要强制转换
-
说明:
-
malloc
函数分配的内存没有默认值; -
malloc
函数申请的内存是连续的;
-
calloc
-
头文件:
#include <stdlib.h>
-
函数功能:
void *calloc(size_t nitems,size_t size)
分配所需的内存空间,并返回一个指向它的指针malloc
和calloc
的不同是calloc
可以为0 -
函数原型:
void *calloc(size_t nitems,size_t size)
-
函数名:
calloc
-
形参:
-
size_t nitems
申请多少个; -
size_t size
一个占多少内存单元
-
-
返回值类型:
void*
,请求失败,返回NULL
-
int *p = (int *)calloc(3,4);//3个元素,每个4字节
if(!p)printf("内存申请失败!\n");
-
说明
-
calloc
分配的内存有默认值,默认为0; -
calloc
申请的内存空间连续; -
calloc
大多数为数组申请内存;
-
int a[3] = {1,2,3};//在栈区
int *p = (int *)calloc(3,4);//在堆区
if(!p)printf("申请失败!\n");
//转存
for(int i = 0; i < 3; i++)
{
p[i] = a[i];
}
free(p);
p = NULL;
realloc
-
头文件:
#include <stdlib.h>
-
函数功能:重新调整之前调用
malloc
或calloc
所分配的ptr
所指向内存块的大小。 -
函数原型:
void *realloc(void *ptr,size_t size)
-
函数名:
realloc
-
形参:
-
void *ptr
:是malloc
或者calloc
的返回值 -
size_t size
:重新分配后的内存大小
-
-
返回值:
void*
:该函数返回一个指针,指向已分配大小的内存。如果请求失败,返回NULL
。
-
int *p = (int*)malloc(4);
int *w = (int*)realloc(p,20);
// int *q = (int*)realloc(p,0); // 等效于free(p)
free
-
头文件:
#include <stdlib.h>
-
函数功能:释放之前调用
malloc、calloc、realloc
所分配的内存空间,是访问完记得使用NULL置空。 -
函数原型:
void free(void *ptr)
-
函数名:
free
-
形式参数:
void *ptr:calloc,malloc.realloc
的返回值 -
返回值类型:
void
:没有返回值
-
-
注意:
-
-
堆内存中的指针才需要回收,栈中系统会自动回收
-
堆内存不能重复回收,运行会报错
-
-
说明:
1.堆的内存空间相比较栈要大很多
2.内存分配函数返回的指针变量可以参与运算(只读),但不能被修改(p++或者p+=i 是错误的)
void与void*区别(了解)
-
定义:
-
void
:空类型,数据类型的一种 -
void*
:空指针类型,指针类型的一种,可匹配任意类型的指针,类似于通配符
-
-
void
-
说明:
void
作为返回值类型使用,表示无返回值;作为形参,表示形参列表为空,在调用函数时不能给实参
-
-
举例:
// 函数声明
void fun(void);
// 函数调用
fun();
-
void*
-
说明:
-
void*
是一个指针类型,但该指针的数据类型不明确,无法通过解引用获取内存中的数据, 因为void*
不知道访问几个内存单元。 -
void*
是一种数据类型,可以作为函数返回值类型,也可以作为形参类型 -
void*
类型的变量在使用之前必须强制类型转换,明确它能够访问几个字节的内存空间
-
-
#include <stdio.h>
#include <stdlib.h>
void* fun(void* p) // 指针函数(返回值类型是指针的函数,此时返回的是不明确类型,需要外部强转)
{
int *p;
// double *p;
// long *p;
// char *p;
return p;
}
// 函数调用
void main()
{
int *p;
void* a = fun(p);// 这种接收方式,实际上没有意义
printf("%p\n",a);// 可以正常打印,打印出一个地址
*a = 10;// 编译报错,void*变量不能解引用访问数据
int *w = (int*)a;
*w = 10;// 编译和运行正常,void*变量a在使用前已经强制类型转换了,数据类型明确了,访问的内存单元明确了。
}
-
说明:
-
void*作为返回值类型:这个函数可以返回任意类型(
char*,int*,double*等
)的指针。 -
void*作为形参类型:这个函数在调用时,可以给任意类型(
char*,int*,double*
等 )的指针。
-
-
总结:
-
void* 类似于通配符,不能对void*类型的变量解引用(因为不明确内存单元的大小)。
-
void*在间接访问(解引用)前要强制类型转换,但不能太随意,否则存和去的数据类型不 一致。
-
内存
memset
填充
-
头文件:
#include <string.h>
-
函数原型:
void *memset(void *s,int c,size_t n);
-
函数功能:填充
s
开始的堆内存空间前n
个字节,使得每个字节值为c
。 -
函数参数:
-
void *s
:待操作内存首地址。 -
int c
:填充的字节数据。 -
size_t n
:填充的字节数。
-
-
返回值:
s
-
注意:c常常设置为0,用于动态内存初始化
案例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test1()
{
int *p = (int*)malloc(4 * sizeof(int));
if(!p)
{
puts("内存分配失败!");
return;
}
// 给这块内存进行初始化操作(填充)
memset(p,0, 4 * sizeof(int));
printf("%d\n",*(p+1));
free(p);
p = NULL;
}
int main()
{
test1();
return 0;
}
memcpy/memmove
拷贝
-
头文件:
#include <string.h>
-
函数原型:
void *memcpy(void *dest,const void *src,size_t n);
适合目标地址与源地址内存无重叠的情况。void *memmove(void *dest,const void *src,size_t n);
-
-
函数功能:拷贝
src
开始的堆内存空间前n个字节,到dest
对应的内存中。 -
函数参数:
-
void *dest
:目标内存首地址。 -
void *src
:源内存首地址。 -
size_t n
:拷贝的字节数。
-
-
返回值:
dest
-
注意:访问内存空间需和申请的内存空间相同,否则数据不安全
-
注意:
memcpy
与memmove
一般情况下是一样的,建议使用memmove
进行内存拷贝; -
因为
memmove
函数是自适应(从后往前或者从前往后)拷贝,当被拷贝的内存和目的地的内存有重叠时,不会拷贝错误。而memcpy
函数是从前往后拷贝,被拷贝的内存和目的地内存有重叠时,拷贝错误。案例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test1()
{
// int *p1 = (int*)malloc(4 * sizeof(int));
// int *p2 = (int*)malloc(6 * sizeof(int));
// for(int i = 0; i < 4; i++)
// p1[i] = 10 + i;
// memset(p2,0,6 * sizeof(int));
// 创建数组
int p1[4] = {11,12,13,14};
int p2[6] = {21,22,23,24,25,26};
// 将p1中的数据通过内存拷贝函数,拷贝到p2
// memcpy(p2+2,p1+1,2*sizeof(int)) // int p2[6] = {21,22,12,13,25,26}
memmove(p2+2,p1+1,2*sizeof(int));
// 测试输出数组
for(int i = 0; i < 4; i++)
printf("%4d",p1[i]);
printf("\n");
for(int j = 0; j < 6; j++)
printf("%4d",p2[j]);
printf("\n");
// free(p1);
// free(p2);
// p1 = NULL;
// p2 = NULL;
}
int main()
{
test1();
return 0;
}
memcmp
比较
-
头文件:
#include <string.h>
-
函数原型:
int memcmp(void *dest,const void *src,size_t n)
-
函数功能:比较
src
和dest
内存前n个字节的数据; -
函数参数:
-
void *dest
:目标内存首地址 * -
const void* src
:源内存首地址 -
size_t n
:比较的字节数
-
-
返回值:
-
0
:数据相同 -
>0
:dest
中的数据大于src
-
<0
:dest
中的数据小于src
-
-
注意:n一般和
src
,dest
的总容量一样;如果不一样,比较结果不确定。案例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test1()
{
int *p1 = (int*)malloc(3*sizeof(int));
int *p2 = (int*)malloc(4*sizeof(int));
// int p1[4] = {1,0,3,6};
// int p2[4] = {1,2,3,4};
// int result = memcmp(p1,p2,4*sizeof(int));
*p1 = 65;
*p2 = 70;
char *a = (char*)p1;
char *b = (char*)p2;
printf("%c,%c\n",*a,*b);
int result = memcmp(a+1,b+1,1*sizeof(char));
printf("%d\n",result);
}
int main()
{
test1();
}
memchr/memrchr
查找
-
头文件:
#include <string.h>
-
函数原型:
int *memchr|*memrchr(const void *s,int c,size_t n)
-
函数功能:在s开始的堆内存空间前n个字节中查找字节数据c
-
函数参数:
-
const void *s
:待操作内存首地址; -
int c
:待查找的字节数据 -
size_t n
:查找的字节数
-
-
返回值:返回查找到的字节数据地址
-
注意:若内存中无重复数据,
memchr
和memrchr
结果相同;若内存中有重复数据,memchr
和memrchr
结果不同;举例
void *memrchr(..);// 使用时编译会报错,需要使用外部声明
// 外部申请
extern void *memrchr(..);
案例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 声明外部函数
extern void *memrchr(const void *s,int c,size_t n);
void test1()
{
int *p = (int*)malloc(4*sizeof(int));
if(!p)
{
puts("内存分配失败!");
return;
}
// 给变量赋值
for(int i = 0; i < 4; i++)
{
p[i] = i * 2;
}
p[3] = 4;
for(int i = 0; i < 4; i++)
{
printf("%d,",p[i]);
}
printf("\n");
// 内存查找 memchr
int *x = (int*)memchr(p,4,4*sizeof(int));
printf("%p--%p--%d\n",x,p,*x);
// 内存查找 memrchr
int *y = (int*)memrchr(p,4,4*sizeof(int));
printf("%p--%p--%d\n",y,p,*y);
free(p);
p = NULL;
}
int main()
{
test1();
}
main函数的原型
main
函数有多种定义格式,凡是函数相关的结论对main
函数同样有效。
-
main
函数的完整写法
int main(int argc, char *argv[]){}
int main(int argc, char **argv){}
argc:表示命令行参数的数量。至少为1,因为第一个参数(argv[0]是程序名称或路径)
argv:参数数组,argv[0]为第一个参数,就是程序的名称或路径
案例:
若有一个example程序
./example arg1 arg2 arg3 //此时argc的值为4,argv[0] = ./example
扩展写法
int main(){}
int main(void){}
void main(){}
main(){} ---- int main(){}
void main(void){}
int main(int a){}
int main(int a,int b,int c){}
-
注意:若函数没有返回值类型,默认返回类型是int
#include "stdio.h"
int main(int argc,char **argv)
{
int k;
for (k=1;k < argc;k++)
printf("%s\n",argv[k]);
}