Lenguaje C - libreta de direcciones

introducción

La libreta de direcciones es un pequeño proyecto muy simple y práctico en lenguaje C. Implica muchos conocimientos básicos en lenguaje C. Poder escribir de forma independiente este pequeño proyecto de libreta de direcciones demuestra que tiene cierto dominio del conocimiento del lenguaje C. Hoy discutiremos la implementación de tres versiones de la libreta de direcciones.

1. Versión estática de la libreta de direcciones

contacto.h

pragma once es para evitar que el archivo de encabezado se llame repetidamente en la memoria mientras el programa se está ejecutando.

El archivo de encabezado string.h es para llamar a la función de cadena

No es necesario decir más sobre stdio.h

El archivo de encabezado afirmar.h hace referencia a la función de afirmación para evitar que algunos punteros sean NULL y afecten la operación del programa.

 enum se utiliza para enumerar las ocho funciones principales de la libreta de direcciones para aumentar la legibilidad y estandarización del código.

Defina directamente una gran cantidad de variables que aparecen en contact.c en contact.h. Cuando encuentre estas variables más adelante, no es necesario volver a definirlas, lo que mejora la eficiencia del código.

 Crear una estructura para almacenar información de contacto.

Crea otra estructura

data [MAX] es una matriz que puede almacenar 1000 información de Ploinfo (es decir, la estructura anterior)

sz se utiliza para registrar el número de contactos.

#pragma once 
#include<string.h>
#include<stdio.h>
#include<assert.h>
//类型的声明


enum Option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	PRINT,
	CLEAR,
	SORT
};


#define MAX 1000
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 30
#define TELE_MAX 12


typedef struct Ploinfo
{
	char name[NAME_MAX];  //姓名
	char sex[SEX_MAX];    //性别
	int age;              //年龄
	char addr[ADDR_MAX];  //地址
	char tele[TELE_MAX];  //电话号码
}Ploinfo;


typedef struct Contact
{
	struct Ploinfo data[MAX]; //存放联系人的数组
	int sz;                   //统计联系人的个数
}Contact;






//函数的声明


//contact 初始化
void InitContact(Contact* pc);


//Contact 增加联系人的信息
void AddContact(Contact* pc);


//Contact 打印联系人的信息
void PrintContact(const Contact* pc);//只是打印,不会改变Contact里面的数据,所以可以const来修饰


//Contact 删除指定联系人
void DelContact(Contact* pc);


//Contact 查找指定联系人
void SearchContact(Contact* pc);


//Contact 修改指定联系人信息
void ModifyContact(Contact* pc);


//Contact 通讯录信息排序
void sortContact(Contact* pc);


//Contact 通讯录信息清空
void ClearContact(Contact* pc);

contacto.h

contact.h es un archivo de encabezado que creamos de forma independiente, que contiene todos los archivos de encabezado y variables que necesitamos para ejecutar contact.c

Al comienzo de contact.c, solo necesita citar este archivo de encabezado contact.h.

La función InitContact se utiliza para inicializar la libreta de direcciones. Antes de agregar información de contacto, tanto los datos como el sz deben inicializarse a 0.

afirmar evita que la PC sea NULL

memset es una función de cadena. Su función aquí es establecer todos los espacios en los datos [MAX] en 0.

La función AddContact se utiliza para agregar información de contacto.

Antes de agregar, debe confirmar si la libreta de direcciones tiene suficiente espacio, si no es suficiente, no podrá agregarlo.

Si puede agregarlo, simplemente continúe ejecutando la siguiente declaración. No daré muchos detalles aquí. Eche un vistazo al código fuente a continuación.

 Lo único a lo que debe prestar atención aquí es que en la declaración printf, "-" está a la izquierda, por lo que sin agregar un signo, está a la derecha.

La modificación y eliminación de información de contacto especificada son inseparables de la función FindByName, porque para implementar la modificación y eliminación, primero debe encontrar el elemento que desea eliminar y modificar. Si no puede encontrarlo, no es necesario eliminarlo ni modificarlo.

Cómo se implementa la función FindByName:

El principio es utilizar un bucle for para recorrer los nombres en los datos. Cada dato tiene un subíndice único i. Compare el nombre que se encontrará con el nombre en los datos a través de strcmp. Si son iguales, strcmp devuelve 0 y luego, en el bucle for, anide una declaración if. Si 0 == el valor devuelto por strcmp, entonces, en este momento, el subíndice de datos se devolverá a las funciones Del y Modify para eliminar y modificar la información de contacto especificada. Si es así Atravesado, es mejor no encontrarlo, esta persona salta directamente del bucle for, devuelve - 1 y devuelve las funciones Del y Modificar.

Esta declaración está incluida en la función Del Modify Search.

Si lee el código fuente detenidamente, encontrará que algunas partes de la función Del Modify Search son iguales.

1. Necesidad de determinar si la libreta de direcciones está vacía

2. Necesidad de determinar si el contacto que busca existe

3. Todos deben llamar a FindByName

La función Ordenar implementa la clasificación de la información de contacto. Hay 5 tipos de información de contacto. Sus tipos pueden ser iguales o diferentes. No podemos ordenarlos por separado. Aunque definitivamente se puede lograr si lo forzamos, no es necesario. En nuestro teléfonos móviles La libreta de direcciones está básicamente ordenada por nombre, por lo que sería más realista si también ordenáramos por nombre.

Los nombres son de tipo char, podemos usar directamente strcmp para compararlos y luego ordenarlos.

Aquí, se usa un bucle for doble para anidar una declaración if, y se crea un tmp de tipo Ploinfo como una variable intermedia para intercambiar datos y lograr la clasificación.

#include"contact.h"




//contact初始化
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
}


//Contact函数的使用 —— 添加联系人
void AddContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == MAX)
	{
		printf("通讯录容量已满!无法添加!\n");


		return;
	}


	printf("请输入姓名 =>\n");
	scanf("%s", pc->data[pc->sz].name);


	printf("请输入性别 =>\n");
	scanf("%s", pc->data[pc->sz].sex);


	printf("请输入年龄 =>\n");
	scanf("%d", &pc->data[pc->sz].age);


	printf("请输入电话号码 =>\n");
	scanf("%s", pc->data[pc->sz].tele);


	printf("请输入地址 =>\n");
	scanf("%s", pc->data[pc->sz].addr);


	pc->sz++;


	printf("添加联系人成功!\n");
}


//Contact 打印联系人的信息
void PrintContact(const Contact* pc)
{
	assert(pc);


	int i = 0;
	printf("%-10s %-5s %-5s %-15s %-20s\n","姓名","性别","年龄","电话","地址");


	for (i = 0;i < pc->sz;i++)
	{
		printf("%-10s %-5s %-5d %-15s %-20s\n", pc->data[i].name, pc->data[i].sex,
			pc->data[i].age, pc->data[i].tele, pc->data[i].addr);
	}
}


//Contact 删除指定联系人


int FindByName(const Contact* pc, char name[])
{
	int i = 0;
	//遍历查找
	//找到返回下标
	//没找到返回 -1
	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 (0 == pc->sz)
	{
		printf("通讯录为空!无法删除!\n");


	    return;
	}


	printf("请输入你要查找的联系人的姓名 =>\n");


	char name[NAME_MAX] = { 0 };//初始化


	scanf("%s", name);//输入要查找的联系人的姓名


	//1、查找
	int pos = FindByName(pc, name);


	if (-1 == pos)
	{
		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");
}


//Contact 查找指定联系人
void SearchContact(Contact* pc)
{
	assert(pc);


	if (0 == pc->sz)
	{
		printf("通讯录为空!无法查找!\n");


		return;
	}


	char name[NAME_MAX] = { 0 };


	printf("输入你要查找的联系人的姓名=>\n");


	scanf("%s", &name);


	int pos = FindByName(pc, name);


	if (-1 == pos)
	{
		printf("联系人不存在!\n");


		return;
	}


	printf("%-10s %-5s %-5s %-15s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");


	printf("%-10s %-5s %-5d %-15s %-20s\n", pc->data[pos].name, pc->data[pos].sex,
		pc->data[pos].age, pc->data[pos].tele, pc->data[pos].addr);


	printf("搜索联系人信息成功!\n");
}


//Contact 修改指定联系人信息
void ModifyContact(Contact* pc)
{
	assert(pc);


	if (0 == pc->sz)
	{
		printf("通讯录为空!无法修改!\n");


		return;
	}
	//查找
	char name[NAME_MAX] = { 0 };


	printf("输入你要查找的联系人的姓名=>\n");


	scanf("%s", &name);


	int pos = FindByName(pc, name);


	if (-1 == pos)
	{
		printf("联系人不存在!\n");


		return;
	}


	//修改


	printf("请输入你想修改该联系人的信息 =>\n");


	printf("请输入姓名 =>\n");
	scanf("%s", pc->data[pos].name);


	printf("请输入性别 =>\n");
	scanf("%s", pc->data[pos].sex);


	printf("请输入年龄 =>\n");
	scanf("%d", &pc->data[pos].age);


	printf("请输入电话号码 =>\n");
	scanf("%s", pc->data[pos].tele);


	printf("请输入地址 =>\n");
	scanf("%s", pc->data[pos].addr);


	printf("修改联系人信息成功!\n");
}


//Contact 通讯录信息排序
void SortContact(Contact* pc)
{
	assert(pc);


	if (0 == pc->sz)
	{
		printf("通讯录为空!无法排序!\n");


		return;
	}


	//以名字排序
	int i, j;
	Ploinfo tmp;
	for (i = 0; i < pc->sz - 1; i++)
	{
		for (j = 0; j < pc->sz - 1 - i; j++)
		{
			if (0 < strcmp(pc->data[j].name, pc->data[j + 1].name))
			{
				tmp = pc->data[j];
				pc->data[j] = pc->data[j + 1];
				pc->data[j + 1] = tmp;
			}
		}
	}


	printf("排序成功!\n");
}


//Contact 通讯录信息清空
void ClearContact(Contact* pc)
{
	InitContact(pc);
}

libreta de direcciones.c

Aquí hay una interfaz de menú para seleccionar funciones, es muy simple y no daré muchos detalles.

#include "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.清空(clear)    0.退出(exit)      ***\n");
	printf("**********************************************\n");
}


void test()
{
	int input = 0;
	//创建通讯录
	Contact cot;
	//初始化通讯录
	InitContact(&cot);
	do
	{
		menu();


		printf("请选择功能 =>\n");


		scanf("%d", &input);


		switch (input)
		{
		case EXIT:
			printf("退出通讯录\n");
			break;
		case ADD:
			//添加联系人
			AddContact(&cot);
			break;
		case DEL:
			DelContact(&cot);
			break;
		case SEARCH:
			SearchContact(&cot);
			break;
		case MODIFY:
			ModifyContact(&cot);
			break;
		case SORT:
			SortContact(&cot);
			break;
		case PRINT:
			PrintContact(&cot);
			break;
		case CLEAR:
			ClearContact(&cot);
		default:
			printf("输入错误!请重新输入\n");
			break;
		}
	} while (input);
}


int main()
{
	test();


	return 0;
}

2. Versión dinámica de la libreta de direcciones.

    La versión dinámica de la libreta de direcciones es una actualización basada en la libreta de direcciones anterior. La llamada versión dinámica puede cambiar dinámicamente el espacio de la libreta de direcciones. La ventaja de esta versión es que puede reducir en gran medida el desperdicio de espacio y evitar un almacenamiento insuficiente. espacio. .

    No moveré todo el código aquí, solo separaré las partes modificadas de la versión estática de la libreta de direcciones para explicarlo.

    Implicará el conocimiento de la gestión dinámica de la memoria. Si es nuevo en el lenguaje C y necesita comprender este conocimiento, puede aprender más al respecto. No importa si no lo comprende. También explicaré brevemente el principio.

contacto.h

#define DEFAULT_SZ 3//初始状态的容量大小

//动态的版本
typedef struct Contact
{
	Ploinfo* data; //data不再是数组,而是指定为一个指针,在contact.c中直接向内存申请空间
	int sz;   //统计联系人的个数
	int capacity;//容量
}Contact;

//contact 销毁
void DestroyContact(Contact* pc);

contacto.c

Agregue las funciones DestroyContact y Check_capacity

Modificar la función InitContact

 Todas las instrucciones están en el código.

//contact初始化
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;//sz指的是联系人个数,初始化为0
	pc->capacity = DEFAULT_SZ;
	pc->data = (Ploinfo*)malloc(pc->capacity * sizeof(Ploinfo));//malloc开辟一个动态的空间,含有capacity个联系人信息的空间
	if (pc->data == NULL)
	{
		perror("InitContact::malloc");//如果pc->data是NULL perror会在屏幕上打印出错误信息 InitContact::malloc 这个格式是给计算机减负,能快速定位错误的语句具体在哪个位置
		                              //同时也是一个保险 当你代码运行时发现错误时,能快速锁定错误位置进行修正
		return 1;
	}

	memset(pc->data, 0, pc->capacity * sizeof(Ploinfo));//初始化 前三个信息的位置 都为0

}

//contact销毁
void DestroyContact(Contact* pc)
{
	assert(pc);
	free(pc->data);//动态开辟了空间,在不需要用通讯录时,需要把空间释放
	pc->data = NULL;
	pc->capacity = 0;//归零
	pc->sz = 0;//归零
}

//检查capacity是否等于sz,也就是在检查空间是否已满,需不需要增加空间
Check_capacity(Contact* pc)
{
	assert(pc);

	if (pc->capacity == pc->sz)
	{
		Ploinfo* tmp = (Ploinfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(Ploinfo));//realloc 的目的就是动态增加开始malloc开辟的空间
		if (tmp != NULL)
		{
			pc->data = tmp;
		}
		pc->capacity += 2;//不要一次只添加一个联系人所占的空间,一次加多点,也不加太多,加两个联系人的空间
	}
}

//Contact函数的使用 —— 添加联系人
void AddContact(Contact* pc)
{
	//静态版本
	/*assert(pc);
	if (pc->sz == MAX)
	{
		printf("通讯录容量已满!无法添加!\n");

		return;
	}*/

	Check_capacity(pc);//添加联系人之前,需要先调用这个函数检查一下空间是否足够,不够就扩容

	printf("请输入姓名 =>\n");
	scanf("%s", pc->data[pc->sz].name);

	printf("请输入性别 =>\n");
	scanf("%s", pc->data[pc->sz].sex);

	printf("请输入年龄 =>\n");
	scanf("%d", &pc->data[pc->sz].age);

	printf("请输入电话号码 =>\n");
	scanf("%s", pc->data[pc->sz].tele);

	printf("请输入地址 =>\n");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;//添加联系人成功 sz++ 联系人数量增加

	printf("添加联系人成功!\n");
}

libreta de direcciones.c

La función DestroyContact solo se agrega a la opción de salida en el menú.


3. Versión de archivo de la libreta de direcciones

La versión del archivo es una actualización de la versión dinámica. La información almacenada en las dos versiones anteriores se destruirá después de salir de la libreta de direcciones y no se podrá guardar. La libreta de direcciones seguirá vacía la próxima vez que la ejecute. La versión del archivo le permite para ingresar a la libreta de direcciones por primera vez. La información se guarda en un archivo específico. La próxima vez que abra la libreta de direcciones, la información se lee del archivo especificado en la libreta de direcciones y se guarda. Esta es la versión del archivo del directorio.

Conocimientos relacionados con operaciones de archivos en lenguaje C.

contacto.h

//Contact 通讯录信息在销毁之前以文件形式保存
void SaveContact(Contact* pc);

contacto.c

Check_capacity(Contact* pc)
{
	assert(pc);

	if (pc->capacity == pc->sz)
	{
		Ploinfo* tmp = (Ploinfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(Ploinfo));
		if (tmp != NULL)
		{
			pc->data = tmp;
		}
		pc->capacity += 2;
	}
}

//读取文件
LoadContact(Contact* pc)
{
	//1.打开文件
	FILE* pf = fopen("C.txt", "rb");
	if (pf == NULL)
	{
		perror("LoadContact::fopen");

		return;
	}
	//2.读取文件
	Ploinfo tmp = { 0 };//创建一个存放读取信息的变量

	while (fread(&tmp, sizeof(Ploinfo), 1, pf))
	{
		Check_capacity(pc);//第二次打开通讯录时,sz(联系人个数)和capacity(容量)都为0,从C.txt读取到的信息需要放到data里面去,就必须先开辟空间
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}

	//3.关闭文件
}

//contact初始化
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
	pc->data = (Ploinfo*)malloc(pc->capacity * sizeof(Ploinfo));
	if (pc->data == NULL)
	{
		perror("InitContact::malloc");
		return 1;
	}

	memset(pc->data, 0, pc->capacity * sizeof(Ploinfo));

	//关闭通讯录,再次打开,我们需要读取C.txt里面的联系人信息
	//再创建一个函数
	LoadContact(pc);

}

//contact销毁
void DestroyContact(Contact* pc)
{
	assert(pc);
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
}

//Contact 通讯录信息在销毁之前以文件形式保存
void SaveContact(const Contact* pc)
{
	//1.打开文件
	//打开一个文件 可以在Contact 的文件路径下创建一个文件 也可以直接fopen一个文件
	FILE* ptr = fopen("C.txt", "wb");//我这里是命名的文件是txt的文件后缀名,当然这个后缀名可以随便写 wb是以二进制打开文件

	//考虑到ptr可能为NULL,防止这个函数无法正常运行,需要加个保险措施
	if (ptr == NULL)
	{
		perror("SaveContact::fopen");//方便定位错误位置
		return;
	}

	//2.写文件
	int i = 0;
	for (i = 0;i < pc->sz;i++)
	{
		fwrite(pc->data + i, sizeof(Ploinfo), 1, ptr);//在销毁通讯录之前,把联系人信息已经保存到 C.txt 里面了
	}

	//3.关闭文件
	fclose(ptr);
	ptr = NULL;
}

libreta de direcciones.c

#include "contact.h"

void menu()
{
	printf("**********************************************\n");
	printf("***     1.添加(add)      2.删除(del)       ***\n");
	printf("***     3.搜索(search)   4.修改(modify)    ***\n");
	printf("***     5.打印(print)    6.清空(clear)     ***\n");
	printf("***     7.排序(sort)     0.退出(exit)      ***\n");
	printf("**********************************************\n");
}

void test()
{
	int input = 0;
	//创建通讯录
	Contact cot;
	//初始化通讯录
	InitContact(&cot);
	do
	{
		menu();

		printf("请选择功能 =>\n");

		scanf("%d", &input);

		switch (input)
		{
		case EXIT:
			printf("退出通讯录\n");
			SaveContact(&cot);//销毁通讯录之前先保存联系人信息
			DestroyContact(&cot);
			break;
		case ADD:
			//添加联系人
			AddContact(&cot);
			break;
		case DEL:
			DelContact(&cot);
			break;
		case SEARCH:
			SearchContact(&cot);
			break;
		case MODIFY:
			ModifyContact(&cot);
			break;
		case PRINT:
			PrintContact(&cot);
			break;
		case CLEAR:
			ClearContact(&cot);
		case 7:
			SortContact(&cot);
			break;
		default:
			printf("输入错误!请重新输入\n");
			break;
		}
	} while (input);
}

int main()
{
	test();

	return 0;
}

4. Resumen

La libreta de direcciones estática implica la versión de conocimiento del lenguaje C: estructura de declaración de rama y bucle operador de función de cadena matriz de función de puntero

Las actualizaciones de la libreta de direcciones involucran la versión de conocimiento del lenguaje C: estructura de declaración de rama y bucle operador de función de cadena matriz de función de puntero

                                                  Gestión de memoria dinámica

Las actualizaciones de la libreta de direcciones involucran la versión de conocimiento del lenguaje C: estructura de declaración de rama y bucle operador de función de cadena matriz de función de puntero

                                                  Operaciones de archivos de gestión de memoria dinámica

Aunque las libretas de direcciones pasan muy desapercibidas hoy en día, para los principiantes en lenguaje C, poder implementar estos tres tipos de libretas de direcciones de manera competente e independiente es suficiente para demostrar que sus habilidades en lenguaje C están básicamente calificadas y pueden intentar implementar más lenguaje C en el futuro. futuro.Pequeños proyectos para consolidar tus habilidades de programación y ejercitar tu pensamiento en programación.


¡¡¡trabaja duro!!!

Supongo que te gusta

Origin blog.csdn.net/cdtu_mid/article/details/131763803
Recomendado
Clasificación