当前位置: 首页 > news >正文

【数据结构】顺序表实现通讯录

在这里插入图片描述

前言
在上一节中我们实现了顺序表,现在我们将使用顺序表完成通讯录的实现。(注:本人水平有限,“小屎山”有些许bug,代码冗余且语无伦次,望谅解!😅)


文章目录

  • 一、数据结构设计
  • 二、初始化和内存管理
    • 初始化
    • 动态扩容
  • 三、基础功能实现:增删改查
    • 添加联系人
    • 删除联系人
    • 修改联系人
    • 查找联系人
    • 显示通讯录
  • 四、文件操作
    • 保存至文件
    • 从文件读取
  • 五、所有代码
    • contact.h
    • contact.c
    • main.c

一、数据结构设计

首先,定义一个结构体Contact来存储单个联系人的信息,包括姓名、性别、年龄和手机号。

typedef struct Contact {char name[NAME_MAX]; //姓名char sex[SEX_MAX];   //性别int age;             //年龄char phone[PHONE_MAX];//手机号
}Contact;

然后,定义一个结构体SeqList(序列表)用于存储所有联系人信息。该结构体包含一个指向Contact结构体数组的指针data,以及两个整数,size表示当前有效数据个数,capacity表示当前数组容量。

typedef struct SeqList {Contact* data; //通讯录信息int size;  //有效数据个数int capacity;  //通讯录总容量
}ConList;

二、初始化和内存管理

初始化

在程序开始之前,我们需要进行初始化操作,即为SeqList中的data分配内存,并设置初始值。

int ContactInit(ConList* list) {   assert(list);Contact* tmp = (Contact*)malloc(sizeof(Contact));if (tmp==NULL) {printf("内存分配失败\n");return -1;}list->data = tmp;list->size = 0;list->capacity = 1;return 0;
}

动态扩容

如果SeqList中的data数组已满,我们需要进行扩容。

int resizeConList(ConList* list) {assert(list);int newCapacity = list->capacity * 2;Contact* newData = (Contact*)realloc(list->data, sizeof(Contact) * newCapacity);if (newData == NULL) {printf("内存分配失败\n");return -1;}list->data = newData;list->capacity = newCapacity;return 0;
}

三、基础功能实现:增删改查

添加联系人

添加联系人时,需要先检查是否有足够的空间,如果没有则扩容。然后,通过标准输入获取联系人信息。

int ContactAdd(ConList* list) {assert(list);char sign = 'N';do {if (list->size >= list->capacity) {int ret = resizeConList(list);if (ret == -1) {printf("通讯录扩大失败\n");return -1;}}printf("请输入姓名:>");scanf(" %20s", list->data[list->size].name); // 限制输入长度printf("请输入性别:>");scanf(" %7s", list->data[list->size].sex); // 限制输入长度printf("请输入年龄:>");if (scanf("%d", &(list->data[list->size].age)) != 1) {printf("无效的年龄输入\n");return -1;}printf("请输入手机号:>");scanf(" %20s", list->data[list->size].phone); // 限制输入长度list->size++;ContactShow(list);printf("Y 继续添加   N 结束   请输入:>");scanf(" %c", &sign); // 注意空格,用于吸收前一个输入后可能残留的换行符printf("***********************************\n");} while (sign == 'Y' || sign == 'y');return 0;
}

删除联系人

删除联系人时,需要输入要删除的联系人的序号。

int ContactDel(ConList* list) {assert(list);ContactShow(list);int input = 0;//要删除联系人序号char sign = 0;do {printf("\n");printf("选择要删除的联系人的序号:>");scanf("%d", &input);for (int i = input; i < list->size; i++) {list->data[i - 1] = list->data[i];}list->size--;ContactShow(list);printf("Y 继续删除  N 结束  请输入:>");scanf(" %c", &sign);} while (sign=='Y'||sign=='y');return 0;
}

修改联系人

修改联系人与添加联系人类似,但需要先定位到要修改的联系人。

int ContactModify(ConList* list) {assert(list);ContactShow(list);int input = 0;//要修改的联系人序号char sign = 0;do {printf("\n");printf("选择要修改的联系人序号:>");scanf("%d", &input);//联系人信息修改printf("请输入姓名:>");scanf(" %20s", list->data[input-1].name); printf("请输入性别:>");scanf(" %7s", list->data[input - 1].sex);printf("请输入年龄:>");if (scanf("%d", &(list->data[input - 1].age)) != 1) {printf("无效的年龄输入\n");return -1;}printf("请输入手机号:>");scanf(" %20s", list->data[input - 1].phone); ContactShow(list);printf("Y 继续修改  N 结束  请输入:>");scanf(" %c",&sign);} while (sign == 'Y' || sign == 'y');return 0;
}

查找联系人

可以通过姓名或手机号进行查找。

int ContactFind(ConList* list) {assert(list);int input = 0;char keyword[21] = {0};//联系人关键字int sign = 0;//联系人是否找到判断do {sign = 0;printf("选择查找联系人方式  1 姓名查找  2 手机号查找  0 退出查找:>");scanf("%d", &input);if (!input) return 0;//退出查找printf("请输入查找关键字:>");scanf(" %20s", keyword);  // 限制输入长度switch (input) {case 1:      // 按姓名查找for (int i = 0; i < list->size; i++) {if (strcmp(list->data[i].name, keyword) == 0) {printf("找到联系人:%d\n", i + 1);sign = 1;break;}}break;case 2:       // 按手机号查找for (int i = 0; i < list->size; i++) {if (strcmp(list->data[i].phone, keyword) == 0) {printf("找到联系人的序号:%d\n", i + 1);sign = 1;break;}}break;default:printf("无效的选项\n");break;}} while (input);if (!sign) {printf("未找到联系人\n");}return 0;
}

显示通讯录

int ContactShow(ConList* list) {assert(list);int count = 1;//序号printf("--------------------------------------------------------------\n");printf("|序号|        姓名        |  性别  |年龄|       手机号       |\n");while (count <= list->size) {printf("--------------------------------------------------------------\n");printf("|%-4d|%-20s|%-8s|%-4d|%-20s|\n",count,list->data[count - 1].name, list->data[count - 1].sex, list->data[count - 1].age,list->data[count - 1].phone);count++;}printf("--------------------------------------------------------------\n");return 0;
}

四、文件操作

保存至文件

使用二进制模式将所有联系人信息保存到文件。

int ContactSave(ConList* list) {assert(list);FILE* file = fopen("contact.dat", "wb");if (file == NULL) {printf("无法创建或打开文件\n");return -1;}// 写入通讯录的大小(元素数量)fwrite(&(list->size), sizeof(int), 1, file);// 写入通讯录的数据fwrite(list->data, sizeof(Contact), list->size, file);fclose(file);file=NULL;return 0;
}

从文件读取

与保存操作相反,从文件中读取所有联系人信息。

int ContactLoad(ConList* list) {assert(list);FILE* file = fopen("contact.dat", "rb+");if (file == NULL) {printf("无法打开文件\n");return -1;}// 读取通讯录的大小(元素数量)fread(&(list->size), sizeof(int), 1, file);// 根据读取到的大小动态分配内存if (list->size) {Contact* tmp = (Contact*)realloc(list->data, sizeof(Contact) * list->size);if (tmp == NULL) {printf("内存分配失败\n");fclose(file);return -1;}list->data = tmp;// 读取通讯录的数据fread(list->data, sizeof(Contact), list->size, file);list->capacity = list->size; // 在这个简单示例中,将容量设置为大小}fclose(file);return 0;
}

五、所有代码

contact.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>#define NAME_MAX 20 
#define SEX_MAX 7   
#define PHONE_MAX 20typedef struct Contact {char name[NAME_MAX]; //姓名char sex[SEX_MAX];   //性别int age;             //年龄char phone[PHONE_MAX];//手机号
}Contact;typedef struct SeqList {Contact* data; //通讯录信息int size;  //有效数据个数int capacity;  //通讯录总容量
}ConList;//添加联系人
int ContactAdd(ConList* list);
//删除联系人
int ContactDel(ConList* list);
//修改联系人
int ContactModify(ConList* list);
//查找指定联系人
int ContactFind(ConList* list);//通讯录的初始化
int ContactInit(ConList* list);
//通讯录扩容
int resizeConList(ConList* list);
//通讯录销毁
void ContactDestroy(ConList* list);
//查看通讯录
int ContactShow(ConList* list);//检测contact.dat存不存在,如果不存在就创建一个
int checkAndCreateFile(const char* filename);
//保存通讯录到文件
int ContactSave(ConList* list);
//从文件中读取通讯录
int ContactLoad(ConList* list);

contact.c

#include"contact.h"int ContactInit(ConList* list) {   assert(list);Contact* tmp = (Contact*)malloc(sizeof(Contact));if (tmp==NULL) {printf("内存分配失败\n");return -1;}list->data = tmp;list->size = 0;list->capacity = 1;return 0;
}int resizeConList(ConList* list) {assert(list);int newCapacity = list->capacity * 2;Contact* newData = (Contact*)realloc(list->data, sizeof(Contact) * newCapacity);//通常扩容选择1.5倍或者2倍进行扩容if (newData == NULL) {printf("内存分配失败\n");return -1;}list->data = newData;list->capacity = newCapacity;return 0;
}int ContactAdd(ConList* list) {assert(list);char sign = 'N';do {if (list->size >= list->capacity) {int ret = resizeConList(list);if (ret == -1) {printf("通讯录扩大失败\n");return -1;}}printf("请输入姓名:>");scanf(" %20s", list->data[list->size].name); // 限制输入长度printf("请输入性别:>");scanf(" %7s", list->data[list->size].sex); // 限制输入长度printf("请输入年龄:>");if (scanf("%d", &(list->data[list->size].age)) != 1) {printf("无效的年龄输入\n");return -1;}printf("请输入手机号:>");scanf(" %20s", list->data[list->size].phone); // 限制输入长度list->size++;ContactShow(list);printf("Y 继续添加   N 结束   请输入:>");scanf(" %c", &sign); // 注意空格,用于吸收前一个输入后可能残留的换行符printf("***********************************\n");} while (sign == 'Y' || sign == 'y');return 0;
}int ContactShow(ConList* list) {assert(list);int count = 1;//序号printf("--------------------------------------------------------------\n");printf("|序号|        姓名        |  性别  |年龄|       手机号       |\n");while (count <= list->size) {printf("--------------------------------------------------------------\n");printf("|%-4d|%-20s|%-8s|%-4d|%-20s|\n",count,list->data[count - 1].name, list->data[count - 1].sex, list->data[count - 1].age,list->data[count - 1].phone);count++;}printf("--------------------------------------------------------------\n");return 0;
}int ContactDel(ConList* list) {assert(list);ContactShow(list);int input = 0;//要删除联系人序号char sign = 0;do {printf("\n");printf("选择要删除的联系人的序号:>");scanf("%d", &input);for (int i = input; i < list->size; i++) {list->data[i - 1] = list->data[i];}list->size--;ContactShow(list);printf("Y 继续删除  N 结束  请输入:>");scanf(" %c", &sign);} while (sign=='Y'||sign=='y');return 0;
}int ContactModify(ConList* list) {assert(list);ContactShow(list);int input = 0;//要修改的联系人序号char sign = 0;do {printf("\n");printf("选择要修改的联系人序号:>");scanf("%d", &input);//联系人信息修改printf("请输入姓名:>");scanf(" %20s", list->data[input-1].name); printf("请输入性别:>");scanf(" %7s", list->data[input - 1].sex);printf("请输入年龄:>");if (scanf("%d", &(list->data[input - 1].age)) != 1) {printf("无效的年龄输入\n");return -1;}printf("请输入手机号:>");scanf(" %20s", list->data[input - 1].phone); ContactShow(list);printf("Y 继续修改  N 结束  请输入:>");scanf(" %c",&sign);} while (sign == 'Y' || sign == 'y');return 0;
}int ContactFind(ConList* list) {assert(list);int input = 0;char keyword[21] = {0};//联系人关键字int sign = 0;//联系人是否找到判断do {sign = 0;printf("选择查找联系人方式  1 姓名查找  2 手机号查找  0 退出查找:>");scanf("%d", &input);if (!input) return 0;//退出查找printf("请输入查找关键字:>");scanf(" %20s", keyword);  // 限制输入长度switch (input) {case 1:      // 按姓名查找for (int i = 0; i < list->size; i++) {if (strcmp(list->data[i].name, keyword) == 0) {printf("找到联系人:%d\n", i + 1);sign = 1;break;}}break;case 2:       // 按手机号查找for (int i = 0; i < list->size; i++) {if (strcmp(list->data[i].phone, keyword) == 0) {printf("找到联系人的序号:%d\n", i + 1);sign = 1;break;}}break;default:printf("无效的选项\n");break;}} while (input);if (!sign) {printf("未找到联系人\n");}return 0;
}void ContactDestroy(ConList* list) {assert(list);// 释放动态分配的数组内存if (list->data != NULL) {free(list->data);}// 将各成员变量设置为初始状态list->data = NULL;list->size = 0;list->capacity = 0;
}int ContactSave(ConList* list) {assert(list);FILE* file = fopen("contact.dat", "wb");if (file == NULL) {printf("无法创建或打开文件\n");return -1;}// 写入通讯录的大小(元素数量)fwrite(&(list->size), sizeof(int), 1, file);// 写入通讯录的数据fwrite(list->data, sizeof(Contact), list->size, file);fclose(file);file=NULL;return 0;
}int ContactLoad(ConList* list) {assert(list);FILE* file = fopen("contact.dat", "rb+");if (file == NULL) {printf("无法打开文件\n");return -1;}// 读取通讯录的大小(元素数量)fread(&(list->size), sizeof(int), 1, file);// 根据读取到的大小动态分配内存if (list->size) {Contact* tmp = (Contact*)realloc(list->data, sizeof(Contact) * list->size);if (tmp == NULL) {printf("内存分配失败\n");fclose(file);return -1;}list->data = tmp;// 读取通讯录的数据fread(list->data, sizeof(Contact), list->size, file);list->capacity = list->size; // 在这个简单示例中,将容量设置为大小}fclose(file);return 0;
}int checkAndCreateFile(const char* filename) {FILE* file;// 尝试以读模式打开文件file = fopen(filename, "r");// 检查文件是否已经存在if (file != NULL) {// 文件存在,关闭文件fclose(file);printf("contact.dat存在\n");return 0;  // 返回0表示文件已存在,无需创建}else {// 文件不存在,以写模式创建一个新文件file = fopen(filename, "w");if (file != NULL) {fclose(file);printf("文件创建成功\n");return 1;  // 返回1表示文件成功创建}else {// 文件创建失败,可能是因为权限或磁盘空间不足等原因printf("文件创建失败\n");return -1;  // 返回-1表示文件创建失败}}
}

main.c

#include"contact.h"void menu() {printf("-------------------------------------\n");printf("-----1 添加联系人   2 删除联系人-----\n");printf("-----3 修改联系人   4 查找联系人-----\n");printf("-------------0 退出通讯录------------\n");printf("-------------------------------------\n");}int main() {ConList list;ContactInit(&list);//通讯录初始化checkAndCreateFile("contact.dat");//检测contact.dat存不存在,如果不存在就创建一个//从文件中读取通讯录ContactLoad(&list);int input = 0;do {menu();printf("\n");printf("选择操作:>");scanf("%d",&input);switch(input){case 1:ContactAdd(&list);break;case 2:ContactDel(&list);break;case 3:ContactModify(&list);break;case 4:ContactFind(&list);break;default:break;}} while (input);ContactSave(&list);//保存通讯录到文件ContactDestroy(&list);//通讯录销毁return 0;
}

在这里插入图片描述
如果你喜欢这篇文章,点赞👍+评论+关注⭐️哦!
欢迎大家提出疑问,以及不同的见解。

相关文章:

【数据结构】顺序表实现通讯录

前言 在上一节中我们实现了顺序表&#xff0c;现在我们将使用顺序表完成通讯录的实现。&#xff08;注&#xff1a;本人水平有限&#xff0c;“小屎山”有些许bug&#xff0c;代码冗余且语无伦次&#xff0c;望谅解&#xff01;&#x1f605;&#xff09; 文章目录 一、数据结构…...

JMeter 随机数生成器简介:使用 Random 和 UUID 算法

在压力测试中&#xff0c;经常需要生成随机值来模拟用户行为。JMeter 提供了多种方式来生成随机值&#xff0c;本文来具体介绍一下。 随机数函数 JMeter 提供了多个用于生成随机数的函数&#xff0c;其中最常用的是 __Random 函数。该函数可以生成一个指定范围内的随机整数或…...

vue3 更换 elemnt-ui / element-plus 版本npm命令

1. 安装 / 更换 element-ui 版本 [ 在 后面指定想要安装的版本 ] //卸载当前版本 npm uninstall element-ui //安装指定版本 npm i element-ui2.4.8 -S --legacy-peer-deps 2. 安装 / 更换 element-plus 版本 [ 在 后面指定想要安装的版本 ] npm install element-plus2.3…...

react.js 手写响应式 reactive

Redux 太繁琐&#xff0c;Mbox 很酷但我们可能没必要引入新的包&#xff0c;那就让我们亲自在 react.js 中通过代理实现一套钩子来达到类似 vue 的响应式状态&#xff1a; 实现 reactive hooks 代理类声明 代理状态的类应当提供可访问的状态&#xff0c;和订阅变化的接口。 …...

代码随想录打卡第四十六天|完全背包 ● 518. 零钱兑换 II ● 377. 组合总和 Ⅳ

完全背包理论 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品都有无限个&#xff08;也就是可以放入背包多次&#xff09;&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 完全背包和01背包问题唯一…...

【BP-Adaboost预测】基于BP神经网络的Adaboost的单维时间序列预测研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

Origami Studio for Mac:塑造未来,掌握原型设计之巅

在当今高度竞争的设计领域&#xff0c;原型设计的重要性不言而喻。它不仅是沟通想法&#xff0c;也是测试和改进设计的关键环节。而现在&#xff0c;一款强大的原型设计工具——Origami Studio for Mac&#xff0c;正在席卷设计界&#xff0c;以其独特的功能和卓越的性能&#…...

UML类图中各箭头表示总结

UML类图中各箭头表示总结 1、泛化2、实现3、依赖4、关联5、聚合6、组合 在UML类图中&#xff0c;箭头关系是用来表示类之间的关系的。箭头关系的种类有以下几种&#xff1a; 1、泛化 泛化&#xff1a;表示类之间的继承关系。箭头从子类指向父类。箭头&#xff1a;实线空心三角…...

神经网络量化----为了部署而特别设计

引言:一般神经网络量化有两个目的: 为了加速,在某些平台上浮点数计算比较耗费时间,替换为整形可以加快运算为了部署,某些平台上只支持整形运算,比如在芯片中如果是第1个目的,则使用常规的量化手段就可以满足,将浮点数运算变成整形运算+较少的浮点运算 但是如果是第2个目…...

代码随想录算法训练营Day60|单调栈01

代码随想录算法训练营Day60|单调栈01 文章目录 代码随想录算法训练营Day60|单调栈01一、739. 每日温度二、496.下一个更大元素 I 一、739. 每日温度 class Solution {public int[] dailyTemperatures(int[] temperatures) {//单调栈int lenstemperatures.length;int result[]n…...

openMP学习笔记 -编程模型

OpenMP模型 gcc编译openmp指令&#xff1a;gcc test.cpp -o test -fopenmp 定积分计算 函数面积 给定一个定积分&#xff0c;计算其面积&#xff1a; ∫ 0 1 4.0 ( 1 x 2 ) d x \int^{1}_{0}{\frac{4.0}{(1x^2)}dx} ∫01​(1x2)4.0​dx omp 概念 并行区域 并行区域用于…...

【Hive SQL 每日一题】环比增长率、环比增长率、复合增长率

文章目录 环比增长率同比增长率复合增长率测试数据需求说明需求实现 环比增长率 环比增长率是指两个相邻时段之间某种指标的增长率。通常来说&#xff0c;环比增长率是比较两个连续时间段内某项数据的增长量大小的百分比。 环比增长率反映了两个相邻时间段内某种经济指标的变…...

Java设计模式之外观模式(Facade Pattern)

外观模式&#xff08;Facade Pattern&#xff09;是一种结构型设计模式&#xff0c;它提供了一个统一的接口&#xff0c;用于访问子系统中的一组接口。外观模式通过隐藏子系统的复杂性&#xff0c;简化了客户端与子系统之间的交互&#xff0c;提供了一个更简单、更直观的接口。…...

【大疆智图】大疆智图(DJI Terra 3.0.0)安装及使用教程

大疆智图是一款以二维正射影像与三维模型重建为主的软件,同时提供二维多光谱重建、激光雷达点云处理、精细化巡检等功能。它能够将无人机采集的数据可视化,实时生成高精度、高质量三维模型,满足事故现场、工程监测、电力巡线等场景的展示与精确测量需求。 文章目录 1. 安装D…...

腾讯地图基本使用(撒点位,点位点击,弹框等...功能) 搭配Vue3

腾讯地图的基础注册账号 展示地图等基础功能在专栏的上一篇内容 大家有兴趣可以去看一看 今天说的是腾讯地图的在稍微一点的基础操作 话不多说 直接上代码 var marker ref(null) var map var center ref(null) // 地图初始化 const initMap () > {//定义地图中心点坐标…...

散列表:Word文档中的单词拼写检查功能是如何实现的?

文章来源于极客时间前google工程师−王争专栏。 一旦我们在Word里输入一个错误的英文单词&#xff0c;它就会用标红的方式提示“编写错误”。Word的这个单词拼写检查功能&#xff0c;虽然很小但却非常实用。这个功能是如何实现的&#xff1f; 散列别&#xff08;Hash Table&am…...

智慧公厕蜕变多功能城市智慧驿站公厕的创新

随着城市发展的不断推进&#xff0c;对公共设施的便利性和智能化要求也日益提高。为满足市民对高品质、便捷、舒适的公共厕所的需求&#xff0c;智慧公厕行业的领航厂家广州中期科技有限公司&#xff0c;全新推出了一体化智慧公厕驿站。凭借着“高科技碳中和物联网创意设计新经…...

R语言清洗与处理数据常用代码段

去掉数据框df的某一列&#xff1a; # 删除不必要的变量 data$unnecessary_var <- NULL 选择需要的列进行读入数据框&#xff1a; # 选择需要的列 selected_cols <- c("col1", "col2", "col3") data <- fread("data.csv", s…...

centos 7.9 安装python 3.10的tls问题,

本地开发升级成了py3.10.6,服务器测试时安装py3.10.4 发现无法正常使用pip3 pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available. 印象中py3的高版本依赖高版本的openssl,centos 7下默认的openssl为1.0.x, 问题很简…...

pytorch,tf维度理解RNN

input_t input_t.squeeze(1) 这行代码用于从 input_t 中去除尺寸为1的维度。在深度学习中&#xff0c;经常会出现具有额外尺寸为1的维度&#xff0c;这些维度通常是为了匹配模型的期望输入维度而添加的。 在这里&#xff0c;input_t可能具有形状 (batch_size, 1, feature_dim…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...

es6+和css3新增的特性有哪些

一&#xff1a;ECMAScript 新特性&#xff08;ES6&#xff09; ES6 (2015) - 革命性更新 1&#xff0c;记住的方法&#xff0c;从一个方法里面用到了哪些技术 1&#xff0c;let /const块级作用域声明2&#xff0c;**默认参数**&#xff1a;函数参数可以设置默认值。3&#x…...

鸿蒙HarmonyOS 5军旗小游戏实现指南

1. 项目概述 本军旗小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;采用DevEco Studio实现&#xff0c;包含完整的游戏逻辑和UI界面。 2. 项目结构 /src/main/java/com/example/militarychess/├── MainAbilitySlice.java // 主界面├── GameView.java // 游戏核…...

【1】跨越技术栈鸿沟:字节跳动开源TRAE AI编程IDE的实战体验

2024年初&#xff0c;人工智能编程工具领域发生了一次静默的变革。当字节跳动宣布退出其TRAE项目&#xff08;一款融合大型语言模型能力的云端AI编程IDE&#xff09;时&#xff0c;技术社区曾短暂叹息。然而这一退场并非终点——通过开源社区的接力&#xff0c;TRAE在WayToAGI等…...