动态内存分配
头文件:<stdlib.h>
1. 内存申请
-
void* malloc(size_t size)( size:需要申请的内存大小)
#include<stdio.h> #include<stdlib.h> #include<string.h> /*strerror通过标准错误的编号,获得错误的描述字符串,方便用户查找,返回值是指向错误信息的指针。*/ #include<errno.h> /*errno获取错误内容*/ int main() { int* p = (int*)malloc(10*sizeof(int ));/* void*需要强制类型转换*/ if (p == NULL)/*(内存可能申请失败)*/ { printf("%s\n", strerror(errno)); } else { for (int i = 0; i < 10; i++) { *(p + i) = i;/*!内存申请时p不可以改变,否则p指向的空间无法释放*/ printf("%d", *(p + i)); } } free(p);/*内存释放*/ p = NULL;/*指针初始化,防止指针对申请的内存破坏. 同时可避免多次释放的程序错误出现*/ return 0; }
-
void * calloc(size_t num,size_t size) (元素数量, 每个元素的大小)
-
与malloc不同的是calloc会初始化内存为0。
2. 内存调整
void realloc(void ptr,size_t size);(ptr:需要调整的内存地址,size调整后的内存大小)
调整时的注意事项
-
原有内存空间之后有足够大的内存空间,则在原来内存空间后面自己追加,原来空间数据不改变
-
原有内存空间之后没有足够大的内存空间,则在堆空间找到一个新的空间使用并把原内存复制,释放原来的内存空间,最后返回新内存空间的地址。
-
需要用一个新变量接收realloc(否则开辟失败返回的空指针会使指向原来内存空间的指针悬空,即找不到原来申请的内存空间)
c/c++程序中的内存知识
内存泄漏:内存中的数据出现丢失
自定义对齐值#pragma pack(n) #pragma pack()取消自定义对齐值
由于内存对齐以下程序不会崩溃
struct s{ char a[3]; int i }b; for(i=0;i<=3;i++) b.a[i]='a'+i; 因为对齐值为4,因此在定义char a【3】时实际给a分配了四个字节
3内存管理函数
menset(a,5,5*sizeof(int))将a开头5个20个字节设置为5
memcpy(a,5,s)将s开头的5个字节复制到a
memmove(a,5,s)将s开头的5个字节移动到a
memcmp(a,s,5)比较a和s开头的5个字节
memchr(a,ch,5)将a开头的5个字节查找ch第一次出现的位置
4. 动态内存分配应用——柔性数组
特点
-
结构中的柔性数组成员前面必须至少一个其他成员。
-
sizeof 返回的这种结构大小不包括柔性数组的内存。
-
包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小
柔性数组的使用
struct S { int a; char arr[];//柔性数组 }; void Test1() { //为结构体动态开辟空间,前半部分开的空间大小是4个字节,后半部分是给柔性数组arr开辟的空间 struct S* ps = (struct S*)malloc(sizeof(struct S) + 100 * sizeof(char)); ps->a = 20; strcpy(ps->arr, "abcdefg"); printf("柔性数组:%d\n", ps->a); printf("柔性数组:%s\n", ps->arr); //若是觉得柔性数组开辟100字节不够使用,可以用realloc为其重新开辟空间 struct S* ptr = (struct S*)realloc(ps, sizeof(struct S) + 200 * sizeof(char)); if (ptr != NULL) ps = ptr; free(ps); ps = NULL; } struct B { int a; char* arr; }; void Test2() { //先为结构体B开辟空间,为8个字节 struct B* ps = (struct B*)malloc(sizeof(struct B)); //此时为结构体中的指针arr动态开辟空间 ps->arr = (char*)malloc(sizeof(char)* 100); ps->a = 20; strcpy(ps->arr, "abcdef"); printf("指针:%d\n", ps->a); printf("指针:%s\n", ps->arr); //若是觉得指针指向的空间开辟100字节不够使用,可以用realloc为其重新开辟空间 char* ptr = (char*)realloc(ps->arr, 200 * sizeof(char)); if (ptr != NULL) ps->arr = ptr; free(ps->arr); ps->arr = NULL; free(ps); ps = NULL; }
开辟数组与开辟指针的区别
柔性数组的优势
-
方便内存的释放,只需一次就可以把内存全部释放
-
提高访问速度 ,提高内存利用率,相比于指针开辟的空间是连续的,同时减少了内存碎片的产生
文件
文件的打开
1打开文件 FILE *fp=fopen(文件名,使用文件的方式)\隔开目录时要注意用转义字符
2关闭文件 int fclose(文件类型指针)
3键盘---标准输入流:stdin
4屏幕--标准输出流:stdout
文件的定位和监测
文件的定位
1long int a=ftell(文件类型指针)返回检测文件首位置到当前位置的字节数,调用失败时返回-1l
2rewind(文件类型指针)将指针重新定位到文件首
3fseek(文件类型指针,位移量,起始点)
起始点:
-
SEEK_SET 文件首开始
-
SEEK_CUR 文件当前位置
-
SEEK_END 文件尾
文件的检测
1feor(文件类型指针)如果到达文件尾则返回非0否则返回0
2ferror(文件指针)检测文件在输入输出时是否出错,未出错返回0,出错则返回非0
3perror(“1”)打印内容然后打印错误信息
文件的读写
1fgetc(文件类型指针)读取一个字符然后文件后移一个字节 如果读到文件结束符则返回EOF(stdio中的一个符合常量值为-1)
fgec(stdin)==getchar()(返回值为该字符的ASCLL码)
2fputc(字符表达式,文件类型指针)将字符写入文件中,同时文件后移一个字节,写入失败返回EOF
fputc(ch,stdout)==putchar(ch)(返回值为该字符的ASCLL码)
3fscanf(文件类型指针,格式字符串,输入项地址列表)写入失败返回EOF
fscanf(stdin,“%d”,&i)==scanf(“%d”,&i)(返回值为读取数据个数)
4fprintf(文件类型指针,格式字符串,输出项列表)写入失败返回EOF
fprintf(stdout,“%d”,&i)==printf(“%d”,&i)(返回值为读取数据个数)
5fread(a,sizeof(int),10,fp)将fp的文件中读取4*10个字节放于a数组中(读取成功返回值为个数,否则返回0)
6fwrite(b,sizeof(int),6,fp)将b的4*6个字节写入fp的文件中 (写入成功返回值为个数,否则返回0)
7fgets(pstr,n,fp)从fp中读取n-1个字符然后在字符后面加\0,如果遇到换行或文件结束则结束读取,(返回值为pstr首地址否则为NULL)
8fputs(pstr,fp)将pstr写入文件不包括\0