实战项目精选

一、比特币地址验证 

项目概况

编写一个以比特币地址为参数的程序,并检查该地址是否有效。比特币地址使用base58编码,该Base58是用于比特币中使用的一种独特的编码方式,主要用于产生比特币的钱包地址。相比Base64,Base58不使用数字"0",字母大写"O",字母大写"I",和字母小写"l",以及"+"和"/"符号。

通过这种编码,比特币地址可编码25个字节:

1、第一个字节是版本号,此任务的版本号为零;

2、接下来的20个字节是一个ripemd-160摘要,但是对于这个任务,您不必知道:您可以将它们视为纯粹的任意数据;

3、最后四个字节是校验和检查。它们是前21个字节的双sha-256摘要的前四个字节。

要检查比特币地址,必须读取前21个字节,计算校验和,并检查它是否与最后4个字节对应。

程序可以返回布尔值,也可以在无效时引发异常。 

项目源码

#include <stdio.h>
#include <string.h>
//用来加密的头文件
#include <openssl/sha.h>

//coin_err表示最终结果
const char *coin_err;
//对coin_err进行赋值的函数
#define bail(s) { coin_err = s; return 0; }
//对字符串base58编码
int unbase58(const char *s, unsigned char *out){
//定义一个常量字符串,包含所有的合法字符	
static const char *tmpl = "123456789"		"ABCDEFGHJKLMNPQRSTUVWXYZ"	
"abcdefghijkmnopqrstuvwxyz";
//定义循环变量	
int i,j, c;	
//用来记录匹配字符串的地址	
const char *p;	
//对输出字符串out进行初始化	
memset(out, 0, 25);	
//对原始字符串进行遍历	
for (i = 0; s[i]; i++) {
//查找给定字符的第一次匹配的地方		
if (!(p = strchr(tmpl, s[i]))) 
//如果没有合法字符,代表是一个bad地址			
bail("bad char"); 
//c表示在进制转换时的进位		
c = p - tmpl;		
//用来处理表示58进制结果的out字符串,编码25个字节		
for (j = 25; j--; )  
//采用58进制			
c += 58 * out[j];			
//256进制的计算过程			
out[j] = c % 256;			
c /= 256;		
} 
//地址太长,所以编码失败,返回0		
if (c) bail("address too long");	
}	

return 1;
}
//判断是否为58进制编码
int valid(const char *s) {    
//dec表示经过58进制编码后的字符串	
unsigned char dec[32], d1[SHA256_DIGEST_LENGTH], d2[SHA256_DIGEST_LENGTH];   
//表示的状态:是否为有效地址	
coin_err = "";	
//如果不符合58进制,直接返回0	
if (!unbase58(s, dec)) return 0;	
//双哈希,采用两次
SHA256加密哈希算法	SHA256(SHA256(dec, 21, d1), SHA256_DIGEST_LENGTH, d2);	
//比较dec从第21个字符开始后的与d2的前四个字符
if (memcmp(dec + 21, d2, 4)) 
//如果不相等就是属于不合法的		
bail("bad digest");    
//正常返回,即是该地址有效	
return 1;
}
int main (void) { 
//给定需要判断的字符串地址	
const char *s[] = {		
"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9",		                   	   
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I",		
0 };
//循环变量	
int i;	
//对每个字符串进行判断	
for (i = 0; s[i]; i++) { 
//计算该地址是否有效		
int status = valid(s[i]); 
//输出结果		
printf("%s: %s\n", s[i], status ? "Ok" : coin_err);	
}	

return 0;
}

运行结果


查看完整项目

二、生成随机国际象棋

项目概况

这项任务的目的是以FEN格式生成一个随机的棋盘。位置不一定要符合现实情况,甚至不一定符合平衡性,但必须遵守以下规则:

1、每种颜色只有一个国王(一个黑国王和一个白国王);

2、两个国王不能被安排在相邻的格子上;

3、升变方格上不能有兵(第八条横线上没有白色兵,第一条横线上没有黑色兵);

4、包括国王在内,每种颜色最多可放置32个。双方之间没有数量平衡的要求;挑选棋子不必遵守常规的国际象棋规则:可以有五个马,二十个车……只要总个数不超过三十二。

5、现在轮到白色棋子的回合,假定双方都失去了易位,不能使用吃过路兵(En passant)的移动方式(因此,FEN应以w--01结束)

最终显示如下所示:

(注:由于是随机值,所以每次运行结果可能不一样)

项目源码

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
//进行宏定义,即TRUE表示1
#define TRUE 1
#define FALSE 0
//类型装换由于C语言中没有bool类型,所以用int代替
typedef int bool;
//生成的棋盘格子
char grid[8][8];

//生成King的坐标
void placeKings() {
int r1, r2, c1, c2;
//死循环的
for (;;) {
//随机生成两个坐标,因为是8*8的方格所以横纵坐标都对8取模
//第一个king的坐标
r1 = rand() % 8;
c1 = rand() % 8;
//第二个king的坐标
r2 = rand() % 8;
c2 = rand() % 8;
if (r1 != r2 && abs(r1 - r2) > 1 && abs(c1 - c2) > 1) {
//如果符合条件那么赋予两个King,为了区分开,一个大写K,一个小写k
grid[r1][c1] = 'K'; 
grid[r2][c2] = 'k';
//直接return,函数结束
return;
}
}
}

//随机生成位置棋子
void placePieces(const char *pieces, bool isPawn) {
int n, r, c;
int numToPlace = rand() % strlen(pieces);
//循环刚才取得的随机数次
for (n = 0; n < numToPlace; ++n) {
//随机生成一个坐标,对8取模
do {
r = rand() % 8;
c = rand() % 8;
}
//如果当前位置上没有棋子为空且升变方格上不能是兵
while (grid[r][c] != 0 || (isPawn && (r == 7 || r == 0)));
//做给定(r,c)坐标位置上的棋子
grid[r][c] = pieces[n];
}
}
//转化为FEN格式
void toFen() {
char fen[80], ch;
/**
(r,c)表示棋盘坐标
countEmpty:空格子的个数
index:fen格式串的下标索引
**/
int r, c, countEmpty = 0, index = 0;
//8*8的棋盘
for (r = 0; r < 8; ++r) {
for (c = 0; c < 8; ++c) {
//取得当前坐标的棋子
ch = grid[r][c];
//如果ch是0的话,说明是空格子,打印.
printf("%2c ", ch == 0 ? '.' : ch);
//如果ch是空格子,那么countEmpty计数+1
if (ch == 0) {
countEmpty++; 
}
else {
if (countEmpty > 0) {
//fen字符串的当前位置 置为0,因为0的ascii码是48
fen[index++] = countEmpty + 48;
//然后重新将countEmpty置为0
countEmpty = 0;
}
//将ch赋值为fen的当前字符
fen[index++] = ch;
}
}
//在每一行结束在处理一遍,跟上面代码相同
if (countEmpty > 0) {
fen[index++] = countEmpty + 48;
countEmpty = 0;
}
//fen字符串设置为

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

C语言入门自学指南 文章被收录于专栏

本专刊由牛客官方团队打造,从一个入门者的角度写下这篇C语言自学指南,内容丰富详实,每一道例题也都是精挑细选,不管是C语言小白抑或是“老司机”,都能在本刊中有所收获。 本专刊购买后即可解锁所有章节,故不可以退换哦~

全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务