C进阶-动态内存
Posted 程序彤
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C进阶-动态内存相关的知识,希望对你有一定的参考价值。
malloc,有借有还再借不难
int main()
int *p = malloc(10 * sizeof(int)); // 借空间
if (p == NULL)
printf("%s\\n", strerror(errno));
else
printf("成功\\n");
for (int i = 0; i < 10; ++i)
*(p + i) = i;
for (int i = 0; i < 10; ++i)
printf("%d\\n", *(p + i));
printf("%s\\n", p);
// 还空间
free(p);
p = NULL;
return 0;
malloc开辟后不初始化,直接返回第一个地址空间。malloc、calloc,relloc都必须和free成对使用,并最终p置空。relloc在调整空间时分两种情况:当前调整空间后有无空闲空间。
int* p = realloc(null,40)等价于int* p = malloc(40);
动态开辟空间常见错误
1. 对NULL指针解引用
若malloc开辟空间失败,那么就是对空指针解引用
2. 对动态开辟的内存空间越界访问了
开辟40个字节,而访问第i=11个元素。
3. 对非动态开辟的内存用free释放
不要莫名其妙的free
4. 使用free释放动态开辟内存的一部分(常见)
若当前的p和之前p所指地址发生变化后,*p++,则必出错。若星(p+i)则无错
5. 对同一空间free多次。(为将p习惯置于空指针NULL)
6. 最佳实践。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void GetMemory1(char **p)
*p = (char*)malloc(100);
char* GetMemory2(char* p)
return (char*) malloc(100);
char* GetMemory3(void)
char p[] = "hello lwt"; //出错
// static int a =10; return &a;,返回类型为int*,则不出错。
return p;
void Test1(void)
char* str = NULL;
// GetMemory1(&str); // 法一:成功
str = GetMemory2(&str); // 法二:成功
strcpy(str,"hello");
printf(str);
// Test2从新开始,返回栈空间的地址问题
void Test2(void)
char* str = NULL;
str = GetMemory3();
printf(str);
int main()
Test1(); // 成功
Test2(); // 报错,非法访问内存空间,此时的p地址虽然在,但不知指向了谁。
return 0;
柔型数组(0长度数组)
- 柔型数组成员前必须至少有一个其他成员变量
- sizeof不计算柔型数组大小,默认+0
- 让数组变得弹性可扩展,依赖于malloc和realloc。
#include <stdio.h>
#include <stdlib.h>
struct S
int n;
int arr[0]; // 柔性数组
s;
int main()
printf("%d\\n", sizeof(s)); // 4
struct S *ps = malloc(sizeof(struct S) + 5 * sizeof(int)); // 24
printf("%d\\n", sizeof(ps)); // 指针8不是24
printf("******************\\n");
ps->n = 666;
for (int i = 0; i < 5; ++i)
ps->arr[i] = i;
struct S *ptr = realloc(ps, 44);
if (ptr != NULL)
ps = ptr;
for (int i = 5; i < 10; ++i)
ps->arr[i] = i;
for (int i = 0; i < 10; ++i)
printf("%d\\n", ps->arr[i]);
free(ps);
ps = NULL;
return 0;
第二种写法不用柔性数组也能将一个int* arr进行替代柔型数组:ps->arr = malloc(5*sizeof(struct S));
释放空间从内而外释放。
哪一种写法更好,使用柔性数组还是不使用呢?
柔型数组优势(虽不用也行)
- 尽可能少的导致free太多释放导致的错误,而使用第二种方式会free释放两次。
- malloc开辟的独立空间可能导致内存碎片,致使内存利用率变低,而使用柔性数组则可避免。
对比传统指针两次malloc不使用柔型数组,效果相似 法二代码:
#include <stdio.h>
#include <stdlib.h>
struct S
int n;
int* arr; // 柔性数组
s;
int main()
struct S* p = (struct S*) malloc(sizeof(struct S));
p->n = 100;
p->arr = malloc(10* sizeof(int));
for (int i = 0; i < 10; ++i)
p->arr[i] = i;
for (int i = 0; i < 10; ++i)
printf("%d\\n", p->arr[i]);
// 两次malloc,必须两次free
free(p->arr);
p->arr = NULL;
free(p);
p = NULL;
return 0;
动态开辟内存空间扩容通讯录升级版代码
contact.h文件
//#define MAX 1000
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
#define DEFAULT_SZ 3
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct PeoInfo
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tele[MAX_TELE];
char addr[MAX_ADDR];
;
struct Contact
struct PeoInfo *data;
// struct PeoInfo data[MAX];
int size; // 当前已有条数
int capacity; // 通讯录当前容量
;
enum Option
EXIT,ADD,DEL,SELECT,UPDATE,SHOW,SORT
;
void InitContact(struct Contact* ps);
void AddContact(struct Contact* ps);
void ShowContact(const struct Contact *ps);
void DelContact(struct Contact *ps); // 删除指定条目
void SelectContact(const struct Contact* ps);
//int FindByName(struct Contact* ps,char name[MAX_NAME]); //不需要在这声明,加上static不向外暴露
void UpdateContact(struct Contact* ps);
void DestroyContact(struct Contact* ps);
contact.c文件
#include "contact.h"
void CheckCapacity(struct Contact* ps)
if(ps->size == ps->capacity)
struct PeoInfo* ptr = realloc(ps->data,(ps->capacity+2)*sizeof(struct PeoInfo));
if(ptr!=NULL)
ps->data = ptr;
ps->capacity+=2;
printf("扩容成功\\n");
else
printf("扩容失败\\n");
else
printf("无需扩容,size++直接添加新联系人:>\\n");
// 抽取查找函数,必须事先声明
static int FindByName(struct Contact *ps, char name[MAX_NAME])
int i = 0;
for (i = 0; i < ps->size; ++i)
if (0 == strcmp(ps->data[i].name, name))
return i; // 找到了,抓取当前i值
return -1;
void InitContact(struct Contact *ps)
// memset(ps->data, 0, sizeof(ps->data));
// ps->size = 0;
ps->data = (struct PeoInfo*)malloc(3*sizeof(struct PeoInfo));
if(ps->data ==NULL)
return;
ps->size = 0;
ps->capacity = DEFAULT_SZ;
void AddContact(struct Contact *ps)
// if (ps->size == MAX)
// printf("通讯录已满,无法增加\\n");
// return;
// else
// printf("请输入名字:>");
// scanf("%s", ps->data[ps->size].name);
// printf("请输入年龄:>");
// scanf("%d", &(ps->data[ps->size].age));
// printf("请输入性别:>");
// scanf("%s", ps->data[ps->size].sex);
// printf("请输入电话:>");
// scanf("%s", ps->data[ps->size].tele);
// printf("请输入地址:>");
// scanf("%s", ps->data[ps->size].addr);
// ps->size++;
// printf("!!!添加成功!!!\\n");
//
CheckCapacity(ps); // 检测当前通讯录容量,如果满扩容,如果未满,size++增加数据就行
printf("请输入名字:>");
scanf("%s", ps->data[ps->size].name);
printf("请输入年龄:>");
scanf("%d", &(ps->data[ps->size].age));
printf("请输入性别:>");
scanf("%s", ps->data[ps->size].sex);
printf("请输入电话:>");
scanf("%s", ps->data[ps->size].tele);
printf("请输入地址:>");
scanf("%s", ps->data[ps->size].addr);
ps->size++;
printf("!!!添加成功!!!\\n");
void ShowContact(const struct Contact *ps)
if (ps->size == 0)
printf("通讯录为空\\n");
// return;
else
printf("%20s\\t%4s\\t%5s\\t%12s\\t%20s\\n", "名字", "年龄", "性别", "电话", "地址");
for (int i = 0; i < ps->size; ++i)
printf("%20s\\t%4d\\t%5s\\t%12s\\t%20s\\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].tele,
ps->data[i].addr);
void DelContact(struct Contact *ps)
printf("请输入要删除的人名-联系人:>");
char name[MAX_NAME];
int i = 0;
scanf("%s", name);
// for (i = 0; i < ps->size; ++i)
// if (0 == strcmp(ps->data[i].name, name))
// break; // 找到了,抓取当前i值
//
//
int pos = FindByName(ps, name); // 找到返回下标,找不到-1
// if (i == ps->size)
if (pos == -1)
printf("要删除的人不存在\\n");
else
int j = 0;
for (j = pos; j < ps->size - 1; j++)
ps->data[j] = ps->data[j + 1];
ps->size--;
printf("删除成功\\n");
void SelectContact(const struct Contact *ps)
printf("请输入要查的人名:>");
char name[MAX_NAME];
scanf("%s", name);
int pos = FindByName(ps, name);
if (pos == -1)
printf("要查找的人不存在\\n");
else
printf("%20s\\t%4s\\t%5s\\t%12s\\t%20s\\n", "名字", "年龄", "性别", "电话", "地址");
printf("%20s\\t%4d\\t%5s\\t%12s\\t%20s\\n", ps->data[pos].name, ps->data[pos].age, ps->data[pos].sex,
ps->data[pos].tele,
ps->data[pos].addr);
void UpdateContact(struct Contact* ps)
printf("请输入要修改的人名:>");
char name[MAX_NAME];
scanf("%s", name);
int pos = FindByName(ps,name);
if(pos == -1)
printf("要修改的人不存在\\n");
else
printf("请输入名字:>");
scanf("%s", ps->data[pos].name);
printf("请输入年龄:>");
scanf("%d", &(ps->data[pos].age));
printf("请输入性别:>");
scanf("%s", ps->data[pos].sex);
printf("请输入电话:>");
scanf("%s", ps->data[pos].tele);
printf("请输入地址:>");
scanf("%s", ps->data[pos].addr);
printf("!!!修改成功!!!\\n");
void DestroyContact(struct Contact* ps)
free(ps->data);
ps->data = NULL;
main.c文件
#include <stdio.h>
#include "contact.c" // main.c引入contact.c以上是关于C进阶-动态内存的主要内容,如果未能解决你的问题,请参考以下文章