哈希表变形 -- 位图

位图

位图可以表示数字存在与否
布隆过滤器可以表示字符串存在与否

#pragma once
#include <stdint.h>

typedef struct Bitmap{
    uint64_t* data;
    uint64_t capacity;
} Bitmap;

int BitmapTest(Bitmap* bm, uint64_t index);

void BitmapInit(Bitmap* bm, uint64_t capacity);

void BitmapDestroy(Bitmap* bm);

void BitmapSet(Bitmap* bm, uint64_t index);

void BitmapUnset(Bitmap* bm, uint64_t index);

void BitmapFill(Bitmap* bm);

void BitmapClear(Bitmap* bm);
#include "bitmap.h"
#include <stdlib.h>
#include <string.h>

uint64_t GetSize(uint64_t capacity){
    uint64_t size = capacity / (sizeof(uint64_t)*8) + 1;
    return size;
}

void BitmapInit(Bitmap* bm, uint64_t capacity){
    if(bm == NULL){
        return;
    }
    //N/(sizeof(uint64_t)*8)+1
    bm->capacity = capacity;
    uint64_t size = capacity / (sizeof(bm->data[0])*8) + 1;
    bm->data = (uint64_t*)malloc(sizeof(uint64_t)*size);
    memset(bm->data, 0, sizeof(uint64_t)*size);
    return;
}

void BitmapDestroy(Bitmap* bm){
    if(bm == NULL){
        return;
    }
    bm->capacity = 0;
    free(bm->data);
    return;
}

void  GetOffset(uint64_t index, uint64_t* n, uint64_t* offset){
    *n = index / (sizeof(uint64_t)*8);
    *offset = index % (sizeof(uint64_t)*8);
    return;
}

//测试某一位是否为1
int BitmapTest(Bitmap* bm, uint64_t index){
    if(bm == NULL || index >= bm->capacity){
        return 0;
    }
    uint64_t n, offset;
    GetOffset(index, &n, &offset);
    uint64_t ret = bm->data[n] & (0x1ul << offset);
    return ret > 0 ? 1 : 0;
}

//给某一位设置为1
void BitmapSet(Bitmap* bm, uint64_t index){
    if( bm == NULL || index >= bm->capacity ){
        return;
    }
    uint64_t n, offset;
    GetOffset(index, &n, &offset);
    bm->data[n] |= (0x1ul << offset);
    return;
}

//给某一位赋值为0
void BitmapUnset(Bitmap* bm, uint64_t index){
    if( bm == NULL || index >= bm->capacity ){
        return;
    }
    uint64_t n, offset;
    GetOffset(index, &n, &offset);
    bm->data[n] &= ~(0x1ul << offset);
    return;
}

//全1
void BitmapFill(Bitmap* bm){
    if(bm == NULL){
        return;
    }
    uint64_t size = GetSize(bm->capacity);
    memset(bm->data,0xff ,sizeof(uint64_t)*size);
    return;
}

void BitmapClear(Bitmap* bm){
    if(bm == NULL){
        return;
    }
    uint64_t size = GetSize(bm->capacity);
    memset(bm->data,0x0 ,sizeof(uint64_t)*size);
    return;
}
<think>好的,用户让我用C++ Builder和UniGui写一个带验证码的用户登录页面,还要设计相关的数据表。首先,我得先理清楚需求,用户可能需要一个完整的解决方案,包括前端界面、后端验证以及数据库设计。 首先,数据表设计。用户登录通常需要用户名、密码,可能还需要邮箱或者手机号,但这里用户没特别提到,所以基本字段应该包括用户ID、用户名、密码(需要加密存储)、验证码相关字段吗?不过验证码一般是临时存在session或者缓存里,可能不需要存在数据库里。不过用户表还是需要设计,比如主键、用户名、密码哈希、盐值,可能还有状态、创建时间等。 接下来是验证码的实现。UniGui是基于Delphi的框架,用C++ Builder的话可能需要调用Delphi的代码或者找合适的组件。生成验证码图片可以用TImage控件,然后生成随机字符串,绘制到图片上,并加入一些干扰线或点,防止机器识别。生成的验证码需要存储,可以用Session来保存,方便验证时比对。 然后是登录页面的布局。UniGui通常用UniForm作为页面,添加UniEdit控件用于输入用户名、密码、验证码,UniImage显示验证码图片,可能需要一个刷新按钮让用户重新获取验证码。按钮的事件处理,比如登录按钮的点击事件,需要验证输入的信息是否正确,包括验证码是否匹配,用户名密码是否有效。 密码的安全性很重要,不能明文存储,所以需要哈希处理,比如使用bcrypt或者SHA-256加盐。数据库中的密码字段应该是哈希后的值,盐值也需要存储。 另外,用户可能还需要考虑数据库连接,比如用FireDAC连接MySQL或其他数据库。在登录验证时,需要查询用户表,比对用户名对应的密码哈希值是否正确。 需要注意的是,验证码的生成和存储应该在服务端进行,避免客户端被篡改。每次生成验证码时,将验证码字符串存入Session,用户提交时从Session取出比对。 可能还需要处理验证码的过期时间,比如设置Session的存活时间,或者定时清除过期的验证码。另外,防止暴力破解,可以限制登录尝试次数,记录登录日志等。 总结步骤:设计用户表结构,创建UniGui项目,设计登录界面,实现验证码生成和显示,处理登录按钮的验证逻辑,包括验证码检查、用户名密码验证,数据库查询,密码哈希比对,最后处理登录成功或失败的反馈。 需要检查是否有遗漏的部分,比如数据库连接配置,错误处理,用户输入验证(如防止SQL注入),前端输入校验(比如非空检查)等。可能用户还希望有记住我功能,但需求里没提到,暂时不考虑。最后,示例代码需要涵盖主要部分,如验证码生成、登录验证、数据库查询等,确保用户能根据示例搭建起基本框架。</think>以下是一个基于C++ Builder + UniGUI实现带验证码的登录页面方案,包含数据库设计和关键代码示例: --- ### 一、数据库设计(MySQL示例) ```sql CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password_hash CHAR(60) NOT NULL, -- 推荐BCrypt加密 salt CHAR(29) NOT NULL, is_active BOOLEAN DEFAULT 1, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 验证码建议存储在Session中,若需持久化可另建表: CREATE TABLE login_attempts ( id INT PRIMARY KEY AUTO_INCREMENT, session_id VARCHAR(100), captcha_code VARCHAR(10), expire_time DATETIME ); ``` --- ### 二、登录页面实现步骤 #### 1. 创建UniGUI项目 - 新建UniGUI Application - 主窗体改名为`LoginForm` #### 2. 界面设计(代码示例) ```cpp // LoginForm.h TUniEdit *edtUsername; // 用户名输入框 TUniEdit *edtPassword; // 密码输入框 TUniEdit *edtCaptcha; // 验证码输入框 TUniImage *imgCaptcha; // 验证码图片 TUniButton *btnLogin; // 登录按钮 TUniButton *btnRefresh; // 刷新验证码按钮 ``` #### 3. 验证码生成代码 ```cpp // 生成随机验证码(4位字母+数字) String GenerateCaptchaCode(int length = 4) { String chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; String code; for(int i=0; i<length; i++){ code += chars[Random(chars.Length()) + 1]; } return code; } // 生成验证码图片 void __fastcall TLoginForm::GenerateCaptchaImage() { String captchaCode = GenerateCaptchaCode(); // 存储到Session UniSession->AddJS("sessionStorage.setItem('captcha', '"+captchaCode+"');"); // 创建位图并绘制验证码 std::unique_ptr<TBitmap> bmp(new TBitmap); bmp->Width = 120; bmp->Height = 40; // 绘制干扰线、背景色等... bmp->Canvas->Font->Size = 20; bmp->Canvas->TextOut(10, 10, captchaCode); // 转换为Base64显示 imgCaptcha->Picture->Assign(bmp.get()); } ``` #### 4. 登录验证逻辑 ```cpp // 登录按钮点击事件 void __fastcall TLoginForm::btnLoginClick(TObject *Sender) { String username = edtUsername->Text.Trim(); String password = edtPassword->Text; String inputCaptcha = edtCaptcha->Text.ToUpperCase(); // 验证码校验 String sessionCaptcha = UniSession->GetJSVar("sessionStorage.getItem('captcha')"); if(inputCaptcha != sessionCaptcha){ ShowMessage("验证码错误"); return; } // 数据库验证 TFDQuery *qry = new TFDQuery(NULL); try { qry->Connection = FDConnection1; // 配置好的数据库连接 qry->SQL->Text = "SELECT * FROM users WHERE username = :username"; qry->ParamByName("username")->Value = username; qry->Open(); if(qry->IsEmpty()){ ShowMessage("用户不存在"); } else { // BCrypt验证密码 String storedHash = qry->FieldByName("password_hash")->AsString; if(CheckBCryptHash(password, storedHash)){ // 登录成功处理 UniSession->SetCookie("AuthToken", GenerateAuthToken()); UniApplication->Redirect("MainForm"); } else { ShowMessage("密码错误"); } } } __finally { delete qry; } } ``` --- ### 三、安全增强建议 1. 密码加密:使用BCrypt算法(推荐使用`System.NetEncoding`或第三方库) 2. 防止暴力破解: - 限制尝试次数(如5次错误锁定15分钟) - 记录登录日志 3. 验证码优化: - 添加干扰线、扭曲变形 - 设置60秒自动过期 4. 使用HTTPS传输 5. 输入过滤:防止SQL注入 --- ### 四、部署注意事项 1. 配置数据库连接池 2. 设置Session超时时间 3. 定期清理验证码记录表 4. 启用CSRF保护 如果需要更详细的代码示例(如BCrypt实现、数据库连接配置),可以告诉我具体需要哪一部分的细节补充。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值