網站首頁 編程語言 正文
創建可自動擴容的通訊錄
這里我們想實現通訊錄自動擴容,不夠了能擴大內存,變得稍微有點智能,就不得不用到開辟內存的函數malloc和realloc,這兩個函數又和free離不開關系
所以這里我給大家簡單的介紹一下這三個庫函數
malloc:這個函數向內存申請一塊連續可用的空間,并返回指向這塊空間的指針
void *malloc( size_t size );
如果開辟成功,則返回一個指向開辟好空間的指針。
如果開辟失敗,則返回一個NULL指針,因此malloc的返回值一定要做檢查。
返回值的類型是 void* ,所以malloc函數并不知道開辟空間的類型,具體在使用的時候使用者自己
來決定。
如果參數 size 為0,malloc的行為是標準是未定義的,取決于編譯器
這里給大家簡單的演示一下:
int main()
{
int arr[5] = { 0 };
int* ptr = NULL;
ptr = (int*)malloc(5 * sizeof(int));//開辟5個大小為int整型的空間給ptr
//判斷是否開辟成功
if (ptr == NULL)
{
perror(malloc);//打印錯誤信息
return;
}
free(ptr);//釋放內存
ptr = NULL;//消除野指針問題
return 0;
}
realloc:realloc函數的出現讓動態內存管理更加靈活。
有時會我們發現過去申請的空間太小了,有時我們又會覺得申請的空間過大了,那為了合理的時使用內存,我們一定會對內存的大小做靈活的調整。那 realloc 函數就可以做到對動態開辟內存大小的調整
void* realloc (void* ptr, size_t size);
ptr 是要調整的內存地址
size 調整之后新大小
返回值為調整之后的內存起始位置。
這個函數調整原內存空間大小的基礎上,還會將原來內存中的數據移動到新的空間
值得我們注意的是這個函數的開辟內存有兩種情況:
情況1
當原有空間之后有足夠大的空間的時候,要擴展內存就直接原有內存之后直接追加空間,原來空間的數據不發生變化。
情況2
當原有空間之后沒有足夠大的空間時候,原有空間之后沒有足夠多的空間時,擴展的方法是:在堆空間上另找一個合適大小
的連續空間來使用。這樣函數返回的是一個新的內存地址
free:用來釋放內存的,這個函數是搭配開辟內存的函數使用且非常關鍵,如果開辟了內存不及時釋放的話會造成內存釋放等嚴重后果,若重復釋放也會有不良影響,所以需要我們注意。
當我們了解了上面三個函數過后我們來試著建立一個可擴容的通訊錄
這里我們先創建一個結構體用來存放用戶的信息
//在這里進行初始化賦值,若以后有變只需在這一個地方改變
#define MAX 1000
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30
typedef struct PeoInfo
{
char name[NAME_MAX];//姓名
char sex[SEX_MAX];//性別
int age;//年齡
char tele[TELE_MAX];//電話號碼
char addr[ADDR_MAX];//地址
} PeoInfo;
當我們的用戶變多,我們所需要的這樣的結構體也需要增加,我們可以在創建一個包含這個結構體的結構體,里面記錄用戶個數和記錄當前通訊錄的最大容量
typedef struct Contact
{
PeoInfo* data;//可以存放人的信息(可增長)
int sz;//記錄通訊中已經保存的信息個數
int capacity;//記錄通訊錄當前的最大容量
}Contact;
當數量大于3時我們就應該擴容并初始化,具體實現
//通訊錄初始狀態的容量大小
#define DEFAULT_SZ 3
void InitContact(Contact* pc)
{
assert(pc);
pc->sz = 0;
pc->capacity = DEFAULT_SZ;
pc->data = (PeoInfo*)malloc(pc->capacity * sizeof(PeoInfo));
if (pc->data == NULL)
{
perror("InitContact::malloc");
return;
}
memset(pc->data, 0, pc->capacity * sizeof(PeoInfo));
}
void CheckCapacity(Contact* pc)
{
//增容(當用戶等于最大容量時)
if (pc->sz == pc->capacity)
{
//開辟兩個大小為PeoInfo的內存并且強制類型轉換為PeoInfo*類型放在tmp地址處
PeoInfo* tmp = (PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(PeoInfo));
if (tmp != NULL)
{
pc->data = tmp;//將tmp地址給到pc->data達到連續存放的目的
}
else
{
perror("CheckCapacity::realloc");//開辟失敗打印錯誤信息
return;
}
pc->capacity += 2;//開辟成功后及時更新最大容量
printf("增容成功\n");
}
}
添加用戶信息
實現:
void AddContact(Contact* pc)
{
assert(pc);
//動態的版本
CheckCapacity(pc);//輸入前看是否需要擴容
//錄入信息
printf("請輸入名字:>");
scanf("%s", pc->data[pc->sz].name);
printf("請輸入年齡:>");
scanf("%d", &(pc->data[pc->sz].age));
printf("請輸入性別:>");
scanf("%s", pc->data[pc->sz].sex);
printf("請輸入電話:>");
scanf("%s", pc->data[pc->sz].tele);
printf("請輸入地址:>");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("添加成功\n");
}
刪除用戶信息
//找到了返回下標
//找不到返回-1
int FindByName(const Contact* pc, char name[])
{
assert(pc);
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (0 == strcmp(pc->data[i].name, name))
{
return i;
}
}
return -1;
}
//刪之前需要先查找是否有這個用戶
void DelContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通訊錄已空,無法刪除\n");
return;
}
//刪除
//1. 找到
char name[NAME_MAX] = { 0 };
printf("請輸入要刪除人的名字:>");
scanf("%s", name);
int pos = FindByName(pc, name);//通過函數查找
if (pos == -1)
{
printf("要刪除的人不存在\n");
return;
}
//2. 刪除
int j = 0;
for (j = pos; j < pc->sz - 1; j++)
{
pc->data[j] = pc->data[j + 1];
}
pc->sz--;
printf("刪除成功\n");
}
查找聯系人
int FindByName(const Contact* pc, char name[])
{
assert(pc);
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (0 == strcmp(pc->data[i].name, name))
{
return i;
}
}
return -1;
}
void SearchContact(const Contact* pc)
{
char name[NAME_MAX] = { 0 };
printf("請輸入要查找人的名字:>");
scanf("%s", name);
int pos = FindByName(pc, name);
if (pos == -1)
{
printf("要查找的人不存在\n");
return;
}
printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年齡", "性別", "電話", "地址");
printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex,
pc->data[pos].tele, pc->data[pos].addr);
}
修改用戶信息
//修改信息
void ModifyContact(Contact* pc)
{
//首先先找到要修改的人
int input = 0;
char name[NAME_MAX] = { 0 };
printf("請輸入要查找人的名字:>");
scanf("%s", name);
int pos = FindByName(pc, name);
if (pos == -1)
{
printf("要查找的人不存在\n");
return;
}
printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年齡", "性別", "電話", "地址");
printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex,
pc->data[pos].tele, pc->data[pos].addr);
printf("請選擇你要修改的信息:\n");
//用switch語句可以實現只改某一項的信息
do
{
printf("0.修改完畢 1.姓名 2.年齡 3.性別 4.電話 5.地址\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("請輸入修改的名字:>");
scanf("%s", pc->data[pos].name);
break;
case 2:
printf("請輸入修改的年齡:>");
scanf("%d", &(pc->data[pos].age));//注意取地址
break;
case 3:
printf("請輸入修改的性別:>");
scanf("%s", pc->data[pos].sex);
break;
case 4:
printf("請輸入修改的電話:>");
scanf("%s", pc->data[pos].tele);
break;
case 5:
printf("請輸入修改的地址:>");
scanf("%s", pc->data[pos].addr);
break;
}
} while (input);
printf("修改成功\n");
}
以名字將用戶排序
//以姓名排序(A~Z的順序)
void SortContact(Contact* pc)
{
int i = 0;
for (i = 0; i < pc->sz-1; i++)
{
int ret = strcmp(pc->data[i].name, pc->data[i + 1].name);
if (ret > 0)
{
PeoInfo tmp;
tmp = pc->data[i];
pc->data[i] = pc->data[i + 1];
pc->data[i + 1] = tmp;
}
}
printf("排序成功\n");
}
銷毀通訊錄
當結束時銷毀通訊錄,釋放內存,避免出現內存泄漏等問題
void DestroyContact(Contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->capacity = 0;
pc->sz = 0;
printf("銷毀成功\n");
}
這里只展示了功能函數以及我認為一些需要注意的地方,若想看完整版可以去下面的鏈接看看哦
gitee
原文鏈接:https://blog.csdn.net/m0_56653788/article/details/123881442
相關推薦
- 2022-06-27 C#?使用Log4net添加日志記錄的方法_C#教程
- 2022-03-06 使用用C++做一顆會跳動的愛心實例代碼_C 語言
- 2022-07-27 python?iloc和loc切片的實現_python
- 2023-04-27 python請求域名requests.(url?=?地址)報錯_python
- 2022-03-29 python自動化之re模塊詳解_python
- 2022-02-22 使用Flex布局實現頭部固定,內容區域滾動
- 2022-08-25 python數學建模(SciPy+?Numpy+Pandas)_python
- 2022-08-21 Caffe卷積神經網絡solver及其配置詳解_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支