目录
memcpy(string.h)
注:void* 可以接收任意类型的指针
void *destination:目标数组地址 转为 void* 类型的指针。
const void * source :被复制的的数组地址,转为 const void *类型表示不能被修改。
size_t num :需要拷贝的字节数(你打算拷贝多少个字节的内容)。
作用:复制内存块
将源地址内容按照 给定大小的 num 个字节内容 拷贝至目标地址,
该函数不检查源中的任何终止 null 字符 - 它总是准确复制 num 个字节。
\t 表示制表符 tab 也就是d后面的4个空格
拷贝是完全拷贝了滴,只不过打印的时候用的%s遇见\0就停止以才是这个结果
为避免溢出,目标参数和源参数所指向的数组的大小应至少为 num 个字节,并且不应重叠(对于重叠的内存块,memmove 是一种更安全的方法)
#include<stdio.h> #include<string.h> int main() { char arr[20] = { 0 }; char arra[20] = "sjd f\nh i\0asufhdi"; memcpy(arr, arra, 15); printf("%s\n", arr); return 0; }
memcpy 的模拟实现
循环里面的代码也可以用
des 和 sou 代替
void* Mymemcpy(void* destination , const void* source , size_t num) { #if 0; char* des = (char*)destination; char*sou = (char*)source; #endif (char*)destination; (char*)source; while (num--) { *(char*)destination = *(char*)source; ((char*)destination)++;//后置++优先级最高,所以要用括号哦括起来这个强制类型转换 //否则会认为先++后强制类型转换 ((char*)source)++; } //return destination; } int main() { int arr[15] = { 1,2,3,4,5,6,7,8,9,10 }; int arra[15] = { 0 }; Mymemcpy(arra,arr,(sizeof(arr[1])*10)); return 0; }
memmove (string.h)
void *destination:目标数组地址 转为 void* 类型的指针。
const void * source :被复制的的数组地址,转为 const void *类型表示不能被修改。
size_t num :需要拷贝的字节数(你打算拷贝多少个字节的内容)。
作用:移动内存块(允许重叠)
将 num 字节的值从源指向的位置复制到目标指向的内存块。复制就像使用了中间缓冲区一样进行,从而允许目标和源重叠。
源指针和目标指针所指向的对象的基础类型与此函数无关;结果是数据的二进制副本。
该函数不检查源中的任何终止 null 字符 - 它总是准确复制 num 个字节。
为避免溢出,目标参数和源参数所指向的数组的大小应至少为 num 个字节
默认,des 和soure 指向的同一块空间,绿色为soure 起始地址,黄色为des起始位置,
如果我们想要挪动,就需要先挪最后一位,依次递减挪动,先挪5再432,如果先挪2到4那么4就被修改,就不能达到效果
反之起始位置大于目标地址,那么就从头开始挪动
void* mymemmove(void* des, void* soure, size_t n)
{
int i = 0;
void* ret = des;
if (des > soure)
{
while (n--)
{
*(((char*)des)+n) = *(((char*)soure)+n);
}
}
else
while (i<n)
{
*((char*)des)++ = *((char*)soure)++;
i++;
}
return ret;
}
int main()
{
int arr[] = { 1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9, };
//arr+3,arr,20 1 1 2 2 1 1 2 2 3
// 3 3 4 4 5 3 4 4 5 5
mymemmove(arr, arr+4, 20);
for (int i = 0; i < 17; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
动态内存管理函数
malloc (stdlib.h)
作用 :开辟一块动态内存空间
返回值:• 如果开辟成功,则返回⼀个指向开辟好空间的指针。• 如果开辟失败,则返回⼀个 NULL 指针,因此malloc的返回值⼀定要做检查。• 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使时由你自己决定需要它是什么类型
我这里没有释放空间,不建议模仿,这里因为程序结束会回收,所以问题不大,因为代码短不会影响到后面。一定要记得判断空间是否开辟成功int main() { //开辟5个整形的空间 int* p = (int*)malloc(sizeof(int) * 5); if (p == NULL) { perror(malloc); return EOF; } int i = 0; for (i; i < 5; i++) { *p = i; printf("%d ", *p); p++; } return 0; }
free(stdlib.h)
作用:
用来释放掉动态内存函数开辟的空间
切记:
ptr 一定要指向那块空间的起始位置,否则就是不完全释放后面可能会出现泄露
如果你乱给指针,那么free函数也是乱来的
如果是空指针没有操作
代码建议:
每次使用指针变量接收完地址后,建议拷贝一份,什么操作都用拷贝的变量区执行,最后free(p) ,p为接收开辟的地址的变量
int main() { //开辟5个整形的空间 int* p = (int*)malloc(sizeof(int) * 5); int* ret = p; if (p == NULL) { perror(malloc); return EOF; } int i = 0; for (i; i < 5; i++) { *ret= i; printf("%d ", *ret); ret++; } free(p); return 0; }
calloc(stdlib.h)
作用:
开辟一块空间
参数:
size_t num 元素个数
size_t size 每个元素的类型
返回值:
开辟成功返回地址
失败返回 NULL
calloc 会把每个字节初始化为0,而malloc 不会。
realloc(stdlib.h)
作用:
更改 ptr 所指向的空间大小
参数:
ptr 需要被修改空间的地址(只能增加)
size 为扩容后总空间大小
返回值:
原有空间的后面足够分配的情况,返回原地址(ptr)
原有空间的后面不够配的的情况,在堆上另找一块空间并且会拷贝原空间的内容,再返回新地址
NULL表示开辟失败,不会有其他操作,ptr 的内容还在
使用动态内存常见错误
1 对NULL指针的解引⽤操作
2 对动态开辟空间的越界访问3 对⾮动态开辟内存使⽤free释放4 使⽤free释放⼀块动态开辟内存的⼀部分5 对同⼀块动态内存多次释放6 动态开辟内存忘记释放(内存泄漏)忘记释放不再使⽤的动态开辟的空间会造成内存泄漏。切记:动态开辟的空间⼀定要释放,并且正确释放