C语言1. 通讯录——结构体+枚举应用

需求:
请添加图片描述
类型和函数的声明都在h头文件
通讯录的main函数文件——test文件:

#define _CRT_SECURE_NO_WARNINGS

#include "learn17_Contact.h"


void menu()
{
	printf("******************************************\n");
	printf("****1. add			2. del		**********\n");
	printf("****3. search		4. modify	**********\n");
	printf("****5. sort			6. print**************************************\n");
	printf("****7. exit					**************************************\n");
	printf("******************************************\n");
}

// 利用枚举默认值更好switch的选项
// 1、2、3、4、5、6:
enum Option
{
	EXIT,	// 0
	ADD,	// 
	DEL,
	SEARCH,
	MODIFY,
	SORT,
	PRINT
};
void test()
{
	int input = 0;
	// 创建通讯录
	//PeoInfo data[1000];	// 存1000人信息
	//int sz = 0;	// 通讯录中已经保存的信息个数
	// 有通讯录结构体时,上面两行都不需要了
	Contact con;	// 通讯录
	// 初始化通讯录	sz要置为0
	InitContact(&con);
	do
	{
		menu();
		printf("请选择>");
		scanf("%d", &input);
		switch (input)
		{
			case ADD:
				AddContact(&con);		// 要改con,所以要传con地址	传con只是形参的拷贝
				break;
			case DEL:
				DelContact(&con);
				break;
			case SEARCH:
				SearchContact(&con);
				break;
			case MODIFY:
				break;
			case SORT:
				break;
			case PRINT:
				PrintContact(&con);	// 这里传con可以,因为只打印,但是传地址,效率高,因为后期结构体存的内容多,很大时,形参临时拷贝会很慢
				break;
			case 0:
				printf("退出通讯录\n");
				break;
			default:
				printf("选择错误\n");
				break;
		}
	} while (input);	// 当input是0,这个while就停了。
}


int main()
{
	test();
	return 0;
}

contact通讯录头文件

#pragma once
#define _CRT_SECURE_NO_WARNINGS

#define MAX 1000
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 35
#include<string.h>
#include<stdio.h>
#include<assert.h>

typedef struct PeoInfo
{
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tele[TELE_MAX];
	char addr[ADDR_MAX];
}PeoInfo;

// 创建通讯录结构体,包含通讯录结构体数组和sz,不然直接对data[1000]操作,做函数传参时,需要又传通讯录data,又要传大小sz
typedef struct Contact
{
	PeoInfo data[1000];	// 放1000人信息
	int sz;	// 通讯录中记录保存信息个数
}Contact;

void AddContact(Contact* pc);
void InitContact(Contact* pc);
void PrintContact(Contact* pc);
void DelContact(Contact* pc);
void SearchContact(Contact* pc);

头文件的实现

#include "learn17_Contact.h"

void InitContact(Contact* pc)
{
	// 初始化
	assert(pc);	// pc空值直接报错
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));	// 大小直接用->data,不需要乘法了,因为data本身就算1000个的大小
}

void AddContact(Contact* pc)
{
	if (pc->sz == MAX)
	{
		printf("通讯录已满,无法添加\n");
		return;
	}
	// 录入
	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");
}


void PrintContact(const Contact* pc)
{
	assert(pc);
	int i = 0;
	printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (i = 0; i < pc->sz; i++)
	{

		// 左对齐,加负号
		printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}
}

// 找到了返回下标
// 根据名字找人,找不到返回-1
int FindByName(Contact* pc, char name[])
{
	assert(pc);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		// strcmp比较:
		if (0 == strcmp(pc->data[i].name, name))
		{
			return i;
		}
	}
	return -1;
}

void DelContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录已空,无法删除\n");
	}
	// 删除
	// 1. 
	printf("输入要删的人名");
	char name[NAME_MAX] = {0};
	scanf("%s",&name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	// 2. 删除,做覆盖
	for (int i = pos; i <=pc->sz-2 ; i++)
	{
		pc->data[i] = pc -> data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

void SearchContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录已空,无法查找\n");
	}
	// 删除
	// 1. 
	printf("输入要找的人名:");
	char name[NAME_MAX] = { 0 };
	scanf("%s", &name);
	int pos = FindByName(pc, name);
	int i = pos;
	if (pos == -1)
	{
		printf("要查找的人不存在\n");
		return;
	}
	printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在C语言中,我们经常会使用结构体来组织一些数据,而结构体中也可能会包含指针类型的成员。当我们对整个结构体进行初始化时,需要考虑如何初始化指针类型的成员。 这时,我们可以使用C标准库中的memset函数来进行初始化。memset函数可以将一块内存区域的值全部设置为某个给定的值。其函数原型如下: ```c void *memset(void *s, int c, size_t n); ``` 其中,s表示要填充的内存区域的起始地址,c表示要填充的值,n表示要填充的字节数。 对于结构体中的指针类型成员,我们可以将其设置为NULL,表示该指针指向空地址。例如,下面是一个结构体及其初始化示例: ```c #include <stdio.h> #include <string.h> struct Student { char name[50]; int age; float score; struct Student *next; }; int main() { struct Student stu; memset(&stu, 0, sizeof(stu)); printf("name: %s\n", stu.name); printf("age: %d\n", stu.age); printf("score: %f\n", stu.score); printf("next: %p\n", stu.next); return 0; } ``` 在上面的示例中,我们定义了一个Student结构体,其中包含了一个指向下一个结构体的指针类型成员next。在main函数中,我们使用memset函数将整个结构体初始化为0,包括指针类型成员next。输出结果如下: ``` name: age: 0 score: 0.000000 next: (nil) ``` 可以看到,对于指针类型成员next,其被初始化为了NULL,即空地址。这样,在程序中使用该结构体时,我们就可以通过判断指针是否为NULL来进行相关操作了。 ### 回答2: 在C语言中,使用memset函数可以将一块内存区域的内容全部设置为指定的值。其中,结构体是一种自定义的数据类型,可以将不同类型的变量组合在一起,形成一个新的数据类型。 在使用memset函数对结构体进行初始化时,需要注意结构体内指针的处理。由于memset函数只能对连续的内存区域进行初始化,而指针成员变量所指向的内存区域往往不连续,因此不能直接对指针进行初始化。 如果要对结构体内的指针进行初始化,可以采用以下方法之一: 1. 使用静态初始化:通过给结构体的指针成员变量赋初值,将其指向一个已经分配好内存的对象或数组。例如,可以使用malloc函数动态分配内存,并将指针成员变量指向该内存区域。 ``` struct Example { int* ptr; }; // 静态初始化 int main() { struct Example ex; int value = 1; ex.ptr = &value; return 0; } ``` 2. 在结构体定义之后,使用malloc函数为指针成员变量分配内存。这样可以确保在使用memset函数初始化结构体之前,指针成员变量已经指向了有效的内存地址。 ``` struct Example { int* ptr; }; // 动态初始化 int main() { struct Example ex; ex.ptr = malloc(sizeof(int)); memset(&ex, 0, sizeof(ex)); return 0; } ``` 需要注意的是,在使用完内存后,要记得使用free函数释放动态分配的内存,避免内存泄漏。 总之,在使用memset函数初始化结构体时,需要考虑结构体内指针的处理,可以使用静态初始化或者在结构体定义后动态分配内存。 ### 回答3: memset是C语言中的一个库函数,用于按字节对特定内存块进行初始化或设置。它的原型为void *memset(void *ptr, int value, size_t num)。 对于结构体内的指针,memset函数通常不能直接使用。这是因为memset仅用于按字节进行内存设置,对于指针类型的变量,只会设置指针本身的值,而不会处理指针所指向的内存块。 如果我们想要将结构体内的指针进行初始化,可以使用其他方法。一种常用的方法是使用malloc函数动态分配内存,并将指针指向这块内存。例如: ```c #include <stdlib.h> typedef struct{ int* ptr; } MyStruct; void initStruct(MyStruct* s){ s->ptr = malloc(sizeof(int)); *s->ptr = 0; } ``` 在上述代码中,我们定义了一个结构体MyStruct,其中包含一个指向int类型的指针ptr。通过initStruct函数,我们可以为MyStruct类型的实例进行初始化,即将ptr指针动态地分配为一块int类型的内存,并设置其初始值为0。 需要注意的是,在使用完分配的内存后,我们需要使用free函数来释放内存,防止内存泄漏。 在C语言中,结构体、链表和枚举是非常常用的数据结构和语法特性。结构体用于组合不同类型的数据,形成一个自定义的数据类型;链表用于存储动态数据集合,其特点是可以灵活地添加和删除元素;枚举用于定义一组有限的命名常量,使代码更加易读和易维护。在实际编程中,合理使用这些特性可以提高代码的可读性和可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值