Question: 刚读了一个俄罗斯方块的完整代码，学得代码不错，但很多不懂，请高手给点注释，越详细越好。

引用 16 楼 chenby186119 的回复:[quote=引用 15 楼 zhao4zhong1 的回复:] ……接上帖/*  * 将新形状的方块放置在游戏板上，并返回此方块号  */ int MkNextBox(int box_numb) {      int mask=128,t_boardx,t_boardy,n,m;     t_boardx=(Curbox_x-Sys_x)/BSIZE;     t_boardy=(Curbox_y-Sys_y)/BSIZE;     for(n=0;n<4;n++)     {         for(m=0;m<4;m++)         {             if( ((shapes[current_box_numb].box[n/2]) & mask) )             {                 Table_board[t_boardy+n][t_boardx+m].var=1;/*这里设置游戏板*/                 Table_board[t_boardy+n][t_boardx+m].color=shapes[current_box_numb].color;/*这里设置游戏板*/             }             mask=mask/(2);             if(mask==0)mask=128;         }     }     setFullRow(t_boardy);     Curbox_x=Sys_x+Begin_boxs_x*BSIZE,Curbox_y=Sys_y;/*再次初始化座标*/     if(box_numb==-1) box_numb=rand()%MAX_BOX;     current_box_numb=box_numb;     flag_newbox=false;     return(rand()%MAX_BOX); }  /*  *  擦除(x,y)位置开始的编号为box_numb的box.  */ void EraseBox(int x,int y,int box_numb) {     int mask=128,t_boardx,t_boardy,n,m;     setfillstyle(SOLID_FILL,BgColor);     for(n=0;n<4;n++)     {         for(m=0;m<4;m++)    /*看最左边四个单元*/         {             if( ((shapes[box_numb].box[n/2]) & mask) )/*最左边有方块并且当前游戏板也有方块*/             {                 bar(x+m*BSIZE,y+n*BSIZE,x+m*BSIZE+BSIZE,y+n*BSIZE+BSIZE);                 line(x+m*BSIZE,y+n*BSIZE,x+m*BSIZE+BSIZE,y+n*BSIZE);                 line(x+m*BSIZE,y+n*BSIZE,x+m*BSIZE,y+n*BSIZE+BSIZE);                 line(x+m*BSIZE,y+n*BSIZE+BSIZE,x+m*BSIZE+BSIZE,y+n*BSIZE+BSIZE);                 line(x+m*BSIZE+BSIZE,y+n*BSIZE,x+m*BSIZE+BSIZE,y+n*BSIZE+BSIZE);             }             mask=mask/(2);             if(mask==0)mask=128;         }     }  }     void ErasePreBox(int x,int y,int box_numb) { 	int	mask=128,t_boardx,t_boardy,n,m; 	setfillstyle(SOLID_FILL,BgColor); 	for(n=0;n<4;n++) 	{ 		for(m=0;m<4;m++)	/*看最左边四个单元*/ 		{ 			if(	((shapes[box_numb].box[n/2]) & mask) )/*最左边有方块并且当前游戏板也有方块*/ 			{ 				bar(x+m*BSIZE,y+n*BSIZE,x+m*BSIZE+BSIZE,y+n*BSIZE+BSIZE);  			} 			mask=mask/(2); 			if(mask==0)mask=128; 		} 	}  }  /* 判断是否可以移动  * x,y为当前方块位置  * box_numb为方块号  * direction 方向标志  *	返回true 和false  #define MoveLeft -1  #define MoveRight 1  #define MoveDown 0  */ int	MoveAble(int x,int y,int box_numb,int direction) { 	int	n,m,t_boardx,t_boardy;			/*t_boardx 当前方块最左边在游戏板的位置*/ 	int	mask = 128; 	if(direction==MoveLeft)				/*如果向左移*/ 	{ 		//mask=128; 		x-=BSIZE; 		t_boardx=(x-Sys_x)/BSIZE; 		t_boardy=(y-Sys_y)/BSIZE; 		for(n=0;n<4;n++) 		{ 			for(m=0;m<4;m++)	/*看最左边四个单元*/ 			{ 				if((shapes[box_numb].box[n/2]) & mask)/*最左边有方块并且当前游戏板也有方块*/ 				{ 					if((x+BSIZE*m)<Sys_x)return(false);/*碰到最左边了*/ 					else if(Table_board[t_boardy+n][t_boardx+m].var) /*左移一个方块后，此4*4的区域与游戏板有冲突*/ 					{ 						return(false); 					} 				} 				mask=mask/(2); 				if(mask==0)mask=128; 			} 		} 		return(true); 	} 	else if(direction==MoveRight)		/*如果向右移*/ 	{ 		x+=BSIZE; 		t_boardx=(x-Sys_x)/BSIZE; 		t_boardy=(y-Sys_y)/BSIZE; 		//mask=128; 		for(n=0;n<4;n++) 		{ 			for(m=0;m<4;m++)	/*看最右边四个单元*/ 			{ 				if((shapes[box_numb].box[n/2]) & mask)/*最右边有方块并且当前游戏板也有方块*/ 				{ 					if((x+BSIZE*m)>=(Sys_x+BSIZE*Horizontal_boxs) )return(false);/*碰到最右边了*/ 					else if( Table_board[t_boardy+n][t_boardx+m].var) 					{ 						return(false); 					} 				} 				mask=mask/(2); 				if(mask==0)mask=128; 			} 		} 		return(true); 	} 	else if(direction==MoveDown)		/*如果向下移*/ 	{ 		y+=BSIZE; 		t_boardx=(x-Sys_x)/BSIZE; 		t_boardy=(y-Sys_y)/BSIZE; 		//mask=128; 		for(n=0;n<4;n++) 		{ 			for(m=0;m<4;m++)	/*看最下边四个单元*/ 			{ 				if((shapes[box_numb].box[n/2]) & mask)/*最下边有方块并且当前游戏板也有方块*/ 				{ 					if((y+BSIZE*n)>=(Sys_y+BSIZE*Vertical_boxs)	||	Table_board[t_boardy+n][t_boardx+m].var) 					{ 						flag_newbox=true; 						break; 					} 				} 				mask=mask/(2); 				/*mask依次为:10000000,01000000,00100000,00010000 							 00001000,00000100,00000010/00000001 				 */ 				if(mask==0)mask=128; 			} 		} 		if(flag_newbox) 		{ 			return(false); 		} 		else 			return(true); 	} 	else if(direction==MoveRoll)		/*转动*/ 	{ 		t_boardx=(x-Sys_x)/BSIZE; 		t_boardy=(y-Sys_y)/BSIZE; 		//mask=128; 		for(n=0;n<4;n++) 		{ 			for(m=0;m<4;m++)	/*看最下边四个单元*/ 			{ 				if((shapes[box_numb].box[n/2]) & mask)/*最下边有方块并且当前游戏板也有方块*/ 				{ 					if((y+BSIZE*n)>=(Sys_y+BSIZE*Vertical_boxs)	)return(false);/*碰到最下边了*/ 					if((x+BSIZE*n)>=(Sys_x+BSIZE*Horizontal_boxs) )return(false);/*碰到最左边了*/ 					if((x+BSIZE*m)>=(Sys_x+BSIZE*Horizontal_boxs) )return(false);/*碰到最右边了*/  					else if( Table_board[t_boardy+n][t_boardx+m].var) 					{ 						return(false); 					} 				} 				mask=mask/(2); 				if(mask==0)mask=128; 			} 		} 		return(true); 	} 	else 	{ 		return(false); 	}  }  /*  *显示指定的方块  */ void show_box(int x,int	y,int box_numb,int color) { 	int	i,ii,ls_x=x; 	if(box_numb<0 || box_numb>=MAX_BOX)/*指定的方块不存在*/ 		box_numb=MAX_BOX/2; 	setfillstyle(SOLID_FILL,color); /*********************************  *	 移位来判断第哪一位是1  *	 方块是每1行用半个字节来表示  *	 128d=1000 0000b  *********************************/ 	for(ii=0;ii<2;ii++) 	{ 		int	mask=128; 		for(i=0;i<8;i++) 		{ 			if(i%4==0 && i!=0)				/*表示转到方块的下一行了*/ 			{ 				y+=BSIZE; 				x=ls_x; 			} 					   if((shapes[box_numb].box[ii])&mask) 			{ 				bar(x,y,x+BSIZE,y+BSIZE); 				line(x,y,x+BSIZE,y); 				line(x,y,x,y+BSIZE); 				line(x,y+BSIZE,x+BSIZE,y+BSIZE); 				line(x+BSIZE,y,x+BSIZE,y+BSIZE); 			} 			x+=BSIZE; 			mask/=2; 		} 		y+=BSIZE; 		x=ls_x; 	} }   void main() { 	int	GameOver=0; 	int	key,nextbox; 	int	Currentaction=0;/*标记当前动作状态*/ 	int	gd=VGA,gm=VGAHI,errorcode;  	initgraph(&gd,&gm,"D:\\BC\\BGI"); 	errorcode =	graphresult(); 	if (errorcode != grOk) 	{ 		printf("\nNotice:Graphics error: %s\n", grapherrormsg(errorcode)); 		printf("Press any key to quit!"); 		getchar(); 		exit(1); 	} 	setbkcolor(BgColor); 	setcolor(FgColor); 	randomize();	//初始化随机数生成器 	SetTimer(newtimer);  	initialize(Sys_x,Sys_y,Horizontal_boxs,Vertical_boxs);/*初始化*/   	nextbox=MkNextBox(-1);  	show_box(Curbox_x,Curbox_y,current_box_numb,shapes[current_box_numb].color); 	show_box(LeftWin_x,Curbox_y+200,nextbox,shapes[nextbox].color); 	show_intro(Sys_x,Curbox_y+320); 	getchar();	//按任意键开始游戏 	while(1) 	{ 		/* Currentaction=0; 		flag_newbox=false; 		检测是否有按键*/ 		if (bioskey(1)){key=bioskey(0);		} 		else			{			key=0;		}  		switch(key) 		{ 			case VK_LEFT: 				if(MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveLeft)) 				{EraseBox(Curbox_x,Curbox_y,current_box_numb);Curbox_x-=BSIZE;Currentaction=MoveLeft;} 				break; 			case VK_RIGHT: 				if(MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveRight)) 				{EraseBox(Curbox_x,Curbox_y,current_box_numb);Curbox_x+=BSIZE;Currentaction=MoveRight;} 				break; 			case VK_DOWN: 				if(MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveDown)) 				{EraseBox(Curbox_x,Curbox_y,current_box_numb);Curbox_y+=BSIZE;Currentaction=MoveDown;} 				else flag_newbox=true; 				break; 			case VK_UP:/*旋转方块*/ 				if(MoveAble(Curbox_x,Curbox_y,shapes[current_box_numb].next,MoveRoll)) 				{EraseBox(Curbox_x,Curbox_y,current_box_numb);current_box_numb=shapes[current_box_numb].next; 					Currentaction=MoveRoll; 				} 				break;  			case VK_ESC: 				GameOver=1; 				break; 			default: 				break; 		}  		if(Currentaction) 		{	/*表示当前有动作,移动或转动*/ 			show_box(Curbox_x,Curbox_y,current_box_numb,shapes[current_box_numb].color); 			Currentaction=0; 		}  			/*按了往下键，但不能下移,就产生新方块*/ 		if(flag_newbox) 		{ 			/*这时相当于方块到底部了,把其中出现点满一行的清去，置0*/ 			ErasePreBox(LeftWin_x,Sys_y+200,nextbox); 			nextbox=MkNextBox(nextbox); 			show_box(LeftWin_x,Curbox_y+200,nextbox,shapes[nextbox].color); 			if(!MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveDown))/*刚一开始,游戏结束*/ 			{ 				show_box(Curbox_x,Curbox_y,current_box_numb,shapes[current_box_numb].color); 				GameOver=1; 			} 			else 			{ 				flag_newbox=false; 			} 			Currentaction=0; 		} 		else	/*自由下落*/ 		{ 			if (Currentaction==MoveDown	|| TimerCounter> (20-speed*2)) 			{ 				if(MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveDown)) 				{ 					EraseBox(Curbox_x,Curbox_y,current_box_numb);Curbox_y+=BSIZE; 					show_box(Curbox_x,Curbox_y,current_box_numb,shapes[current_box_numb].color); 				} 				TimerCounter=0; 			} 		}  		if(GameOver	)/*|| flag_newbox==-1*/ 		{ 			printf("game over,thank you! your score is %d",score); 			getchar(); 			break; 		} 	} 	getchar();	//按任意键退出界面 	KillTimer(); 	closegraph(); }   大哥，小弟十分感激你的源代码，俄罗斯方块的源代码很多，不过我想把我发的代码思路弄清楚，麻烦你给我发的代码写注释好吗？跪求。[/quote]能加个QQ吗？我的QQ：525591507。

引用 15 楼 zhao4zhong1 的回复:……接上帖/*  * 将新形状的方块放置在游戏板上，并返回此方块号  */ int MkNextBox(int box_numb) {      int mask=128,t_boardx,t_boardy,n,m;     t_boardx=(Curbox_x-Sys_x)/BSIZE;     t_boardy=(Curbox_y-Sys_y)/BSIZE;     for(n=0;n<4;n++)     {         for(m=0;m<4;m++)         {             if( ((shapes[current_box_numb].box[n/2]) & mask) )             {                 Table_board[t_boardy+n][t_boardx+m].var=1;/*这里设置游戏板*/                 Table_board[t_boardy+n][t_boardx+m].color=shapes[current_box_numb].color;/*这里设置游戏板*/             }             mask=mask/(2);             if(mask==0)mask=128;         }     }     setFullRow(t_boardy);     Curbox_x=Sys_x+Begin_boxs_x*BSIZE,Curbox_y=Sys_y;/*再次初始化座标*/     if(box_numb==-1) box_numb=rand()%MAX_BOX;     current_box_numb=box_numb;     flag_newbox=false;     return(rand()%MAX_BOX); }  /*  *  擦除(x,y)位置开始的编号为box_numb的box.  */ void EraseBox(int x,int y,int box_numb) {     int mask=128,t_boardx,t_boardy,n,m;     setfillstyle(SOLID_FILL,BgColor);     for(n=0;n<4;n++)     {         for(m=0;m<4;m++)    /*看最左边四个单元*/         {             if( ((shapes[box_numb].box[n/2]) & mask) )/*最左边有方块并且当前游戏板也有方块*/             {                 bar(x+m*BSIZE,y+n*BSIZE,x+m*BSIZE+BSIZE,y+n*BSIZE+BSIZE);                 line(x+m*BSIZE,y+n*BSIZE,x+m*BSIZE+BSIZE,y+n*BSIZE);                 line(x+m*BSIZE,y+n*BSIZE,x+m*BSIZE,y+n*BSIZE+BSIZE);                 line(x+m*BSIZE,y+n*BSIZE+BSIZE,x+m*BSIZE+BSIZE,y+n*BSIZE+BSIZE);                 line(x+m*BSIZE+BSIZE,y+n*BSIZE,x+m*BSIZE+BSIZE,y+n*BSIZE+BSIZE);             }             mask=mask/(2);             if(mask==0)mask=128;         }     }  }     void ErasePreBox(int x,int y,int box_numb) { 	int	mask=128,t_boardx,t_boardy,n,m; 	setfillstyle(SOLID_FILL,BgColor); 	for(n=0;n<4;n++) 	{ 		for(m=0;m<4;m++)	/*看最左边四个单元*/ 		{ 			if(	((shapes[box_numb].box[n/2]) & mask) )/*最左边有方块并且当前游戏板也有方块*/ 			{ 				bar(x+m*BSIZE,y+n*BSIZE,x+m*BSIZE+BSIZE,y+n*BSIZE+BSIZE);  			} 			mask=mask/(2); 			if(mask==0)mask=128; 		} 	}  }  /* 判断是否可以移动  * x,y为当前方块位置  * box_numb为方块号  * direction 方向标志  *	返回true 和false  #define MoveLeft -1  #define MoveRight 1  #define MoveDown 0  */ int	MoveAble(int x,int y,int box_numb,int direction) { 	int	n,m,t_boardx,t_boardy;			/*t_boardx 当前方块最左边在游戏板的位置*/ 	int	mask = 128; 	if(direction==MoveLeft)				/*如果向左移*/ 	{ 		//mask=128; 		x-=BSIZE; 		t_boardx=(x-Sys_x)/BSIZE; 		t_boardy=(y-Sys_y)/BSIZE; 		for(n=0;n<4;n++) 		{ 			for(m=0;m<4;m++)	/*看最左边四个单元*/ 			{ 				if((shapes[box_numb].box[n/2]) & mask)/*最左边有方块并且当前游戏板也有方块*/ 				{ 					if((x+BSIZE*m)<Sys_x)return(false);/*碰到最左边了*/ 					else if(Table_board[t_boardy+n][t_boardx+m].var) /*左移一个方块后，此4*4的区域与游戏板有冲突*/ 					{ 						return(false); 					} 				} 				mask=mask/(2); 				if(mask==0)mask=128; 			} 		} 		return(true); 	} 	else if(direction==MoveRight)		/*如果向右移*/ 	{ 		x+=BSIZE; 		t_boardx=(x-Sys_x)/BSIZE; 		t_boardy=(y-Sys_y)/BSIZE; 		//mask=128; 		for(n=0;n<4;n++) 		{ 			for(m=0;m<4;m++)	/*看最右边四个单元*/ 			{ 				if((shapes[box_numb].box[n/2]) & mask)/*最右边有方块并且当前游戏板也有方块*/ 				{ 					if((x+BSIZE*m)>=(Sys_x+BSIZE*Horizontal_boxs) )return(false);/*碰到最右边了*/ 					else if( Table_board[t_boardy+n][t_boardx+m].var) 					{ 						return(false); 					} 				} 				mask=mask/(2); 				if(mask==0)mask=128; 			} 		} 		return(true); 	} 	else if(direction==MoveDown)		/*如果向下移*/ 	{ 		y+=BSIZE; 		t_boardx=(x-Sys_x)/BSIZE; 		t_boardy=(y-Sys_y)/BSIZE; 		//mask=128; 		for(n=0;n<4;n++) 		{ 			for(m=0;m<4;m++)	/*看最下边四个单元*/ 			{ 				if((shapes[box_numb].box[n/2]) & mask)/*最下边有方块并且当前游戏板也有方块*/ 				{ 					if((y+BSIZE*n)>=(Sys_y+BSIZE*Vertical_boxs)	||	Table_board[t_boardy+n][t_boardx+m].var) 					{ 						flag_newbox=true; 						break; 					} 				} 				mask=mask/(2); 				/*mask依次为:10000000,01000000,00100000,00010000 							 00001000,00000100,00000010/00000001 				 */ 				if(mask==0)mask=128; 			} 		} 		if(flag_newbox) 		{ 			return(false); 		} 		else 			return(true); 	} 	else if(direction==MoveRoll)		/*转动*/ 	{ 		t_boardx=(x-Sys_x)/BSIZE; 		t_boardy=(y-Sys_y)/BSIZE; 		//mask=128; 		for(n=0;n<4;n++) 		{ 			for(m=0;m<4;m++)	/*看最下边四个单元*/ 			{ 				if((shapes[box_numb].box[n/2]) & mask)/*最下边有方块并且当前游戏板也有方块*/ 				{ 					if((y+BSIZE*n)>=(Sys_y+BSIZE*Vertical_boxs)	)return(false);/*碰到最下边了*/ 					if((x+BSIZE*n)>=(Sys_x+BSIZE*Horizontal_boxs) )return(false);/*碰到最左边了*/ 					if((x+BSIZE*m)>=(Sys_x+BSIZE*Horizontal_boxs) )return(false);/*碰到最右边了*/  					else if( Table_board[t_boardy+n][t_boardx+m].var) 					{ 						return(false); 					} 				} 				mask=mask/(2); 				if(mask==0)mask=128; 			} 		} 		return(true); 	} 	else 	{ 		return(false); 	}  }  /*  *显示指定的方块  */ void show_box(int x,int	y,int box_numb,int color) { 	int	i,ii,ls_x=x; 	if(box_numb<0 || box_numb>=MAX_BOX)/*指定的方块不存在*/ 		box_numb=MAX_BOX/2; 	setfillstyle(SOLID_FILL,color); /*********************************  *	 移位来判断第哪一位是1  *	 方块是每1行用半个字节来表示  *	 128d=1000 0000b  *********************************/ 	for(ii=0;ii<2;ii++) 	{ 		int	mask=128; 		for(i=0;i<8;i++) 		{ 			if(i%4==0 && i!=0)				/*表示转到方块的下一行了*/ 			{ 				y+=BSIZE; 				x=ls_x; 			} 					   if((shapes[box_numb].box[ii])&mask) 			{ 				bar(x,y,x+BSIZE,y+BSIZE); 				line(x,y,x+BSIZE,y); 				line(x,y,x,y+BSIZE); 				line(x,y+BSIZE,x+BSIZE,y+BSIZE); 				line(x+BSIZE,y,x+BSIZE,y+BSIZE); 			} 			x+=BSIZE; 			mask/=2; 		} 		y+=BSIZE; 		x=ls_x; 	} }   void main() { 	int	GameOver=0; 	int	key,nextbox; 	int	Currentaction=0;/*标记当前动作状态*/ 	int	gd=VGA,gm=VGAHI,errorcode;  	initgraph(&gd,&gm,"D:\\BC\\BGI"); 	errorcode =	graphresult(); 	if (errorcode != grOk) 	{ 		printf("\nNotice:Graphics error: %s\n", grapherrormsg(errorcode)); 		printf("Press any key to quit!"); 		getchar(); 		exit(1); 	} 	setbkcolor(BgColor); 	setcolor(FgColor); 	randomize();	//初始化随机数生成器 	SetTimer(newtimer);  	initialize(Sys_x,Sys_y,Horizontal_boxs,Vertical_boxs);/*初始化*/   	nextbox=MkNextBox(-1);  	show_box(Curbox_x,Curbox_y,current_box_numb,shapes[current_box_numb].color); 	show_box(LeftWin_x,Curbox_y+200,nextbox,shapes[nextbox].color); 	show_intro(Sys_x,Curbox_y+320); 	getchar();	//按任意键开始游戏 	while(1) 	{ 		/* Currentaction=0; 		flag_newbox=false; 		检测是否有按键*/ 		if (bioskey(1)){key=bioskey(0);		} 		else			{			key=0;		}  		switch(key) 		{ 			case VK_LEFT: 				if(MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveLeft)) 				{EraseBox(Curbox_x,Curbox_y,current_box_numb);Curbox_x-=BSIZE;Currentaction=MoveLeft;} 				break; 			case VK_RIGHT: 				if(MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveRight)) 				{EraseBox(Curbox_x,Curbox_y,current_box_numb);Curbox_x+=BSIZE;Currentaction=MoveRight;} 				break; 			case VK_DOWN: 				if(MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveDown)) 				{EraseBox(Curbox_x,Curbox_y,current_box_numb);Curbox_y+=BSIZE;Currentaction=MoveDown;} 				else flag_newbox=true; 				break; 			case VK_UP:/*旋转方块*/ 				if(MoveAble(Curbox_x,Curbox_y,shapes[current_box_numb].next,MoveRoll)) 				{EraseBox(Curbox_x,Curbox_y,current_box_numb);current_box_numb=shapes[current_box_numb].next; 					Currentaction=MoveRoll; 				} 				break;  			case VK_ESC: 				GameOver=1; 				break; 			default: 				break; 		}  		if(Currentaction) 		{	/*表示当前有动作,移动或转动*/ 			show_box(Curbox_x,Curbox_y,current_box_numb,shapes[current_box_numb].color); 			Currentaction=0; 		}  			/*按了往下键，但不能下移,就产生新方块*/ 		if(flag_newbox) 		{ 			/*这时相当于方块到底部了,把其中出现点满一行的清去，置0*/ 			ErasePreBox(LeftWin_x,Sys_y+200,nextbox); 			nextbox=MkNextBox(nextbox); 			show_box(LeftWin_x,Curbox_y+200,nextbox,shapes[nextbox].color); 			if(!MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveDown))/*刚一开始,游戏结束*/ 			{ 				show_box(Curbox_x,Curbox_y,current_box_numb,shapes[current_box_numb].color); 				GameOver=1; 			} 			else 			{ 				flag_newbox=false; 			} 			Currentaction=0; 		} 		else	/*自由下落*/ 		{ 			if (Currentaction==MoveDown	|| TimerCounter> (20-speed*2)) 			{ 				if(MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveDown)) 				{ 					EraseBox(Curbox_x,Curbox_y,current_box_numb);Curbox_y+=BSIZE; 					show_box(Curbox_x,Curbox_y,current_box_numb,shapes[current_box_numb].color); 				} 				TimerCounter=0; 			} 		}  		if(GameOver	)/*|| flag_newbox==-1*/ 		{ 			printf("game over,thank you! your score is %d",score); 			getchar(); 			break; 		} 	} 	getchar();	//按任意键退出界面 	KillTimer(); 	closegraph(); }   大哥，小弟十分感激你的源代码，俄罗斯方块的源代码很多，不过我想把我发的代码思路弄清楚，麻烦你给我发的代码写注释好吗？跪求。

仅供参考： /*  *俄罗斯方块源程序  */ #include <stdio.h> #include <stdlib.h> #include <dos.h> #include <graphics.h> #include <bios.h>  #ifdef __cplusplus     #define __CPPARGS ... #else     #define __CPPARGS #endif  /*定义按键码*/ #define VK_LEFT  0x4b00 #define VK_RIGHT 0x4d00 #define VK_DOWN  0x5000 #define VK_UP    0x4800 #define VK_ESC   0x011b  /*设置中断号*/ #define TIMER 0x1c  /*定义常量*/ #define MAX_BOX 19          /*总共有19种各形态的方块*/ #define BSIZE 20            /*方块的边长是20个象素*/ #define Sys_x 160           /*显示方块界面的左上角x座标*/ #define Sys_y 25            /*显示方块界面的左上角y座标*/ #define Horizontal_boxs 10  /*水平的方向以方块为单位的长度*/ #define Vertical_boxs 15    /*垂直的方向以方块为单位的长度,也就说长是15个方块*/ #define Begin_boxs_x Horizontal_boxs/2  /*产生第一个方块时出现的起始位置*/  #define FgColor CYAN    //前景色 #define BgColor BLACK   //背景颜色  #define LeftWin_x Sys_x+Horizontal_boxs*BSIZE+46        /*右边状态栏的x座标*/  #define false 0 #define true 1  /*移动的方向*/ #define MoveLeft 1 #define MoveRight 2 #define MoveDown 3 #define MoveRoll 4  /*以后坐标的每个方块可以看作是像素点是BSIZE*BSIZE的正方形*/ /*定义全局变量*/ int current_box_numb;   /*保存当前方块编号*/ int Curbox_x=Sys_x+Begin_boxs_x*BSIZE,Curbox_y=Sys_y;/*x,y是保存方块的当前坐标的*/ int flag_newbox=false;  /*是否要产生新方块的标记0*/ int speed=0;            /*下落速度*/ int score=0;            /*总分*/ int speed_step=30;       /*每等级所需要分数*/ void interrupt (*oldtimer)(__CPPARGS);/* 指向原来时钟中断处理过程入口的中断处理函数指针 */  struct BOARD            /*游戏底板结构,表示每个点所具有的属性*/ {     int var;            /*当前状态 只有0和1,1表示此点已被占用*/     int color;          /*颜色,游戏底板的每个点可以拥有不同的颜色.增强美观*/ }Table_board[Vertical_boxs][Horizontal_boxs];  /*方块结构*/ struct SHAPE {     char box[2];            /*一个字节等于8位,每4位来表示一个方块的一行                               如:box[0]="0x88",box[1]="0xc0"表示的是:                               1000                               1000                               1100                               0000*/     int color;              /*每个方块的颜色*/     int next;               /*下个方块的编号*/ };   /*初始化方块内容.即定义MAX_BOX个SHAPE类型的结构数组，并初始化*/ struct SHAPE shapes[MAX_BOX]= { /*  *   口     口口口   口口      口  *   口     口         口  口口口  *   口口              口  */     {0x88,  0xc0,   CYAN,   1},     {0xe8,  0x0,    CYAN,   2},     {0xc4,  0x40,   CYAN,   3},     {0x2e,  0x0,    CYAN,   0},  /*  *   口        口口 口口口  *   口 口     口       口  * 口口 口口口 口  */     {0x44,  0xc0,   MAGENTA,  5},     {0x8e,  0x0,    MAGENTA,  6},     {0xc8,  0x80,   MAGENTA,  7},     {0xe2,  0x0,    MAGENTA,  4},  /*  *   口  *   口口         口口  *     口       口口  */     {0x8c,  0x40,   YELLOW, 9},     {0x6c,  0x0,    YELLOW, 8},  /*  *   口        口口  * 口口          口口  * 口  */     {0x4c,  0x80,   BROWN,  11},     {0xc6,  0x0,    BROWN,  10},  /*  *   口       口                口  * 口口口     口口   口口口   口口  *            口       口       口  */     {0x4e,  0x0,    WHITE,  13},     {0x8c,  0x80,   WHITE,  14},     {0xe4,  0x0,    WHITE,  15},     {0x4c,  0x40,   WHITE,  12},  /* 口  * 口  * 口       口口口口  * 口  */     {0x88,  0x88,   RED,    17},     {0xf0,  0x0,    RED,    16},  /*  * 口口  * 口口  */     {0xcc,  0x0,    BLUE,   18} };   unsigned int TimerCounter=0;  /*定时计数器变量*/  /* 新的时钟中断处理函数 */ void interrupt newtimer(__CPPARGS) {     (*oldtimer)();   /* call the old routine */     TimerCounter++;/* increase the global counter */ }  //时钟中断处理 void SetTimer(void interrupt(*IntProc)(__CPPARGS)) {     oldtimer=getvect(TIMER);    //获取中断号为TIMER的中断处理函数的入口地址     disable();  //关中断,以屏蔽其他中断     setvect(TIMER,IntProc); //设置中断向量，调用中断处理函数     enable();  //开中断，以响应其他中断 }   /* 恢复原有的时钟中断处理过程 */ void KillTimer() {     disable();     setvect(TIMER,oldtimer);     enable(); }   //显示帮助信息 void show_intro(int xs,int ys) {  char stemp[50];  setcolor (WHITE);  //设置边框为白色  rectangle(xs,ys,xs+239,ys+100);  sprintf(stemp," -Roll  -Downwards");  stemp[0]=24;   //↑  stemp[8]=25;  //↓  setcolor(YELLOW);  //设置文本颜色为黄色  outtextxy(xs+40,ys+30,stemp);   sprintf(stemp," -Turn Left   -Turn Right");  stemp[0]=27;   //←  stemp[13]=26;  //→   outtextxy(xs+40,ys+45,stemp);  outtextxy(xs+40,ys+60,"Esc-Exit ");  setcolor(FgColor); }  //显示分数 void ShowScore(int score) {     int x,y;     char score_str[5];/*保存游戏得分*/     setfillstyle(SOLID_FILL,BgColor);     x=LeftWin_x;     y=100;     bar(x-BSIZE,y,x+BSIZE*3,y+BSIZE*3);     sprintf(score_str,"%3d",score);     outtextxy(x,y,"SCORE");     outtextxy(x,y+10,score_str); }  //显示级别 void ShowLevel(int speed) {     int x,y;     char speed_str[5];/*保存速度值*/     setfillstyle(SOLID_FILL,BgColor);     x=LeftWin_x;     y=150;     bar(x-BSIZE,y,x+BSIZE*3,y+BSIZE*3);     /*确定一个以(x1,y1)为左上角,(x2,y2)为右下角的矩形窗口, 再按规定图模和颜色填充。*/     sprintf(speed_str,"%3d",speed+1);     outtextxy(x,y,"Level");     outtextxy(x,y+10,speed_str);     /*输出字符串指针speed_str所指的文本在规定的(x, y)位置*/     outtextxy(x,y+50,"Nextbox"); }   /**********初始化界面*******  *参数说明:  *      x,y为左上角坐标  *      m,n对应于Vertical_boxs,Horizontal_boxs  *      分别表示纵横方向上方块的个数(以方块为单位)  *      BSIZE Sys_x Sys_y  **********************************/ void initialize(int x,int y,int m,int n) {      int i,j,oldx;     oldx=x;     for(j=0;j<n;j++)     {         for(i=0;i<m;i++)         {              Table_board[j][i].var=0;             Table_board[j][i].color=BgColor;             line(x,y,x+BSIZE,y);             line(x,y,x,y+BSIZE);             line(x,y+BSIZE,x+BSIZE,y+BSIZE);             line(x+BSIZE,y,x+BSIZE,y+BSIZE);             x+=BSIZE;         }         y+=BSIZE;         x=oldx;     }     Curbox_x=x;     Curbox_y=y;/*x,y是保存方块的当前坐标的*/     flag_newbox=false;  /*是否要产生新方块的标记0*/     speed=0;            /*下落速度*/     score=0;            /*总分*/     ShowScore(score);     ShowLevel(speed);  }   /*   删除一行满的情况  *   这里的y为具体哪一行为满  */ int DelFullRow(int y) {     /*该行游戏板往下移一行*/     int n,top=0;                /*top保存的是当前最高点,出现一行全空就表示为最点了,移动是到最高点结束*/     register m,totoal;     for(n=y;n>=0;n--)/*从当前行往上看*/     {         totoal=0;         for(m=0;m<Horizontal_boxs;m++)         {             if(!Table_board[n][m].var)totoal++;             /*没占有方格+1*/             if(Table_board[n][m].var!=Table_board[n-1][m].var)  /*上行不等于下行就把上行传给下行 xor关系*/             {                 Table_board[n][m].var=Table_board[n-1][m].var;                 Table_board[n][m].color=Table_board[n-1][m].color;             }         }         if(totoal==Horizontal_boxs)                     /*发现上面有连续的空行提前结束*/         {             top=n;             break;         }     }     return(top);                /*返回最高点*/ }   /*找到一行满的情况*/ void setFullRow(int t_boardy) {     int n,full_numb=0,top=0;            /*top保存的是当前方块的最高点*/     register m; /* t_boardy 口       5          口       6    口口口口口口   7 n  口口口口口口   8  */     for(n=t_boardy+3;n>=t_boardy;n--)     {         if(n<0 || n>=Vertical_boxs ){continue;} /*超过低线了*/         for(m=0;m<Horizontal_boxs;m++)          /*水平的方向*/         {             if(!Table_board[n+full_numb][m].var)break;      /*发现有一个是空就跳过该行*/         }         if(m==Horizontal_boxs)                  /*找到满行了*/         {             if(n==t_boardy+3)                   /*第一次献给了n,最高的*/                 top=DelFullRow(n+full_numb);        /*清除游戏板里的该行,并下移数据*/             else                 DelFullRow(n+full_numb);             full_numb++;                        /*统计找到的行数*/          }     }     if(full_numb)     {         int oldx,x=Sys_x,y=BSIZE*top+Sys_y;         oldx=x;         score=score+full_numb*10;              /*加分数*/         /*这里相当于重显调色板*/         for(n=top;n<t_boardy+4;n++)         {             if(n>=Vertical_boxs)continue;   /*超过低线了*/             for(m=0;m<Horizontal_boxs;m++)  /*水平的方向*/             {                 if(Table_board[n][m].var)                     setfillstyle(SOLID_FILL,Table_board[n][m].color);/*Table_board[n][m].color*/                 else                     setfillstyle(SOLID_FILL,BgColor);                  bar(x,y,x+BSIZE,y+BSIZE);                 line(x,y,x+BSIZE,y);                 line(x,y,x,y+BSIZE);                 line(x,y+BSIZE,x+BSIZE,y+BSIZE);                 line(x+BSIZE,y,x+BSIZE,y+BSIZE);                 x+=BSIZE;             }             y+=BSIZE;             x=oldx;         }         ShowScore(score);         if(speed!=score/speed_step)           {speed=score/speed_step; ShowLevel(speed);}         else           {ShowLevel(speed);}     } }  未完待续……

引用 11 楼 ml0719787 的回复:[quote=引用 9 楼 chenby186119 的回复:] [quote=引用 8 楼 ml0719787 的回复:] [quote=引用 6 楼 chenby186119 的回复:] [quote=引用 2 楼 ml0719787 的回复:] 忘记说了，我的是linux环境下的 你能看下这些代码，写些注释吗，这些代码思想很有特点，可能对你有很大收获。[/quote] 其实最痛苦的是看别人的代码和理解别人的思路，我先看看，关键是你哪个地方不懂[/quote]  你把代码复制到VS2010编译器，有问号的地方就是不太明白的地方。[/quote] 没有那个 只有studio 和 linux环境[/quote]  VS任意版本都行啊。 ALT+F8，不就对齐缩进了吗？我的QQ：525591507，加我吧。

引用 7 楼 zhao4zhong1 的回复:代码功能归根结底不是别人帮自己看或讲解或注释出来的；而是被自己静下心来花足够长的时间和精力亲自动手单步或设断点或对执行到某步获得的中间结果显示或写到日志文件中一步一步分析出来的。 提醒：再牛×的老师也无法代替学生自己领悟和上厕所！ 单步调试和设断点调试是程序员必须掌握的技能之一。  我也知道，但时间紧急，我只能求助于高手们了，你能动手写些注释吗，感激不尽。跪求注释。

引用 9 楼 chenby186119 的回复:[quote=引用 8 楼 ml0719787 的回复:] [quote=引用 6 楼 chenby186119 的回复:] [quote=引用 2 楼 ml0719787 的回复:] 忘记说了，我的是linux环境下的 你能看下这些代码，写些注释吗，这些代码思想很有特点，可能对你有很大收获。[/quote] 其实最痛苦的是看别人的代码和理解别人的思路，我先看看，关键是你哪个地方不懂[/quote]  你把代码复制到VS2010编译器，有问号的地方就是不太明白的地方。[/quote] 没有那个 只有studio 和 linux环境

引用 8 楼 ml0719787 的回复:[quote=引用 6 楼 chenby186119 的回复:] [quote=引用 2 楼 ml0719787 的回复:] 忘记说了，我的是linux环境下的 你能看下这些代码，写些注释吗，这些代码思想很有特点，可能对你有很大收获。[/quote] 其实最痛苦的是看别人的代码和理解别人的思路，我先看看，关键是你哪个地方不懂[/quote] 看着太烦了，代码没有缩进，没有高亮什么的，痛苦

引用 8 楼 ml0719787 的回复:[quote=引用 6 楼 chenby186119 的回复:] [quote=引用 2 楼 ml0719787 的回复:] 忘记说了，我的是linux环境下的 你能看下这些代码，写些注释吗，这些代码思想很有特点，可能对你有很大收获。[/quote] 其实最痛苦的是看别人的代码和理解别人的思路，我先看看，关键是你哪个地方不懂[/quote]  你把代码复制到VS2010编译器，有问号的地方就是不太明白的地方。

引用 6 楼 chenby186119 的回复:[quote=引用 2 楼 ml0719787 的回复:] 忘记说了，我的是linux环境下的 你能看下这些代码，写些注释吗，这些代码思想很有特点，可能对你有很大收获。[/quote] 其实最痛苦的是看别人的代码和理解别人的思路，我先看看，关键是你哪个地方不懂

引用 2 楼 ml0719787 的回复:忘记说了，我的是linux环境下的 你能看下这些代码，写些注释吗，这些代码思想很有特点，可能对你有很大收获。

引用 1 楼 ml0719787 的回复:其实看别人的代码没有自己写的爽，俄罗斯方块主要用几个模块构成，大致可以分成，旋转 定时 和 刷新 整个界面可以用一个二维数组来实现，或者直接用坐标来实现，我写的时候是用坐标的，然后按自己的构想去更新界面，每次小图形下落都更新背景，定时很简单，调用alarm这样的定时器就可以实现，小图形其实也是个二维数组，每次判断 小图形对应于背景的相对坐标，忘记说了，好想一共16个小图形 先用二维数组构造好，每次都rand一个出来，基本这样很简单的就出来了，还有就是这个二维数组是否越界问题，比如下面有图形或者到边界了什么的，随便想吧  说了那么多 也不知道你看明白没，反正这是我写的时候的思路 你能看下这些代码，定些注释吗？这些代码对我重要。

引用 楼主 chenby186119 的回复:#include <Windows.h> #include <ctime> #include <cstdlib> #include <cstdio> #include <iostream>  const int Width = 12;//游戏界面的宽度 const int Height = 22;//游戏界面的高度 const int startX = 20;//开始绘制界面的点 const int startY = 0;  bool isChecking = false;//在算消分的时候按键是无效的 int g_Board[Height][Width] = {0};//游戏界面的数组,数组的初始化。  void DeleteRow(int row) {   //删除数组中某行 row >=0 && row < Height 	for(int i = row; i > 0; --i) 	{ 		for(int j = 0; j < Width; ++j) 		{ 			g_Board[i][j] = g_Board[i-1][j]; //把上一行放到下一行 		} 	}  	for(int j = 0; j < Width; ++j)//这一循环的作用？ 	{ 		g_Board[0][j] = 0; 	} }  int GetRandomShape( int seed )//随机产生方块的19种形变 { 	return time(NULL) / seed % 19;//这个函数如果是time（null）返回的则是当前时间（确切的来说这么说是不正确的，其实time返回的是从格林威治时间1970年1月1日0点0分0秒到现在的秒数，你这个程序中可以这么理解 }  //判断是否越界 bool IsOut(int x, int y) { 	return x <= startX || y <= startY || x > startX + 2*Width || y > startY + Height ;//这里为什么是2*Width }  //隐藏光标，头文件<windows.h>  void HideCursor()  {  	CONSOLE_CURSOR_INFO cursor_info = {1, 0}; //后边的0代表光标不可见  	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);  }   //移动光标到固定位置 void SetCursor(int x, int y) { 	COORD coord; 	coord.X = x; 	coord.Y = y; 	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);//是个宏,代表标准输出，可以看作显示器 }  struct Blocks { 	char blockShape[2];//{(char)0x88, (char)0xc0, 1}一共三种。 	int next;//旋转后的图形编号,也就数组中的下标，下一形变编号。 };  Blocks blocks[19] =  { 	//1000 1110 1100 0010 	//1000 1000 0100 1110 	//1100 0000 0100 0000 	//0000 0000 0000 0000 	{(char)0x88, (char)0xc0, 1},//竖着看，看1组合成的方向。 	{(char)0xe8, (char)0x00, 2}, 	{(char)0xc4, (char)0x40, 3}, 	{(char)0x2e, (char)0x00, 0},  	//0100 1000 1100 1110 	//0100 1110 1000 0010 	//1100 0000 1000 0000 	//0000 0000 0000 0000 	{(char)0x44, (char)0xc0, 5}, 	{(char)0x8e, (char)0x00, 6}, 	{(char)0xc8, (char)0x80, 7}, 	{(char)0xe2, (char)0x00, 4},  	//1000 0110 	//1100 1100 	//0100 0000 	//0000 0000 	{(char)0x8c, (char)0x40, 9}, 	{(char)0x6c, (char)0x00, 8},  	//0100 1100 	//1100 0110 	//1000 0000 	//0000 0000 	{(char)0x4c, (char)0x80, 11}, 	{(char)0xc6, (char)0x00, 10},  	//0100 1000 1110 0100 	//1110 1100 0100 1100 	//0000 1000 0000 0100 	//0000 0000 0000 0000 	{(char)0x4e, (char)0x00, 13}, 	{(char)0x8c, (char)0x80, 14}, 	{(char)0xe4, (char)0x00, 15}, 	{(char)0x4c, (char)0x40, 12},  	//1000 1111 	//1000 0000 	//1000 0000 	//1000 0000 	{(char)0x88, (char)0x88, 17}, 	{(char)0xf0, (char)0x00, 16}, 	//1100 	//1100 	//0000 	//0000 	{(char)0xcc, (char)0x00, 18} };  void DrawFrame(int x, int y, int FrameWidth, int FrameHeight) { 	int i;  	for (i = 0; i < FrameWidth; ++i)  	{ 		SetCursor(x+2*i+2, y);//顶 x+2*i+2?为什么还加2呢？ 		printf("%s", "*");  		SetCursor(x+2*i+2, y+FrameHeight+1);//底 		printf("%s", "|"); 	}  	for (i = 0; i < FrameHeight; ++i)  	{ 		SetCursor(x, y + i + 1);//左 		printf("%s", "^");  		SetCursor(x + FrameWidth*2 + 2, y+i+ 1);//右 		printf("%s", "#"); 	}  	SetCursor(x, y); 	printf("%s", "@");  //左上角  	SetCursor(x, y+FrameHeight+1); 	printf("%s", "$");//左下角  	SetCursor(x + FrameWidth*2+2, y); 	printf("%s", "%");//右上角    	SetCursor(x + FrameWidth*2+2, y + FrameHeight+1); 	printf("%s", "~");//右下角 }  struct Shape { 	Blocks m_block; 	int m_x, m_y;//这个m_x, m_y是什么呢？坐标？ };  bool Collision(Shape& shape, int x, int y);//在x,y处开始显示方块  void ShowShape(Shape& shape) { 	for ( int i = 0; i < 2 ; ++i) 	{ 		unsigned int num = 128;//1000 0000，这个数字的作用？  		for (int j = 0; j < 8; ++j) 		{ 			int row = i * 2 + j / 4;//？  			if ( shape.m_block.blockShape[i] & num )//? 			{ 				SetCursor(shape.m_x + (j%4) * 2, shape.m_y + row ); 				printf("%s", "*");//此处为方块字符，由于文章内容不能含有方块字符，所以用*代替 			} 			num = num >> 1;//右移一位。为什么右移一位呢？ 		} 	} }  bool CreateShape(Shape& shape, int id, int x, int y) { 	shape.m_block = blocks[id];//blocks[19] 	shape.m_x = x; 	shape.m_y = y;  	if (Collision(shape, 0, 0))//? 	{ 		return false; 	}  	ShowShape(shape);  	return true; }  //消除原来位置的方块 void EraseShape(Shape& shape)//EraseShape { 	for ( int i = 0; i < 2; ++i) 	{ 		unsigned int num = 128;  		for (int j = 0; j < 8; ++j) 		{ 			int row = i * 2 + j / 4;//这个表达式？  			if ( shape.m_block.blockShape[i] & num ) 			{ 				SetCursor(shape.m_x + (j%4) * 2, shape.m_y + row ); 				printf("%s", " "); 			} 			num = num >> 1;//？ 为什么要这样做。右移一位，偶数为原来的一半，奇数为减一的一半。 		} 	} }  //判断是否碰撞,这里传入的x,y是偏移量 bool Collision(Shape& shape, int x, int y) { 	for (int i = 0; i < 2; ++i) 	{ 		unsigned int num = 128;  		for (int j = 0; j < 8; ++j) 		{ 			int row = i * 2 + j / 4; 			int nx = shape.m_x + x*2 + (j%4) * 2; 			int ny = shape.m_y + y + row;  			if (shape.m_block.blockShape[i] & num) 			{ 				//判断是否会撞到墙壁 				//判断与数组内的成员是否相撞 				if (IsOut(nx, ny)) 				{ 					return true; 				} 				else if (g_Board[ny-startY-1][(nx-startX-2)/2])//？ 				{ 					return true; 				} 			}  			num = num >> 1; 		} 	}  	return false; }  //这里传入的x,y是偏移量 bool ChangePositon(Shape& shape, int x, int y) { 	if (Collision(shape, x, y)) 	{ 		return false; 	}  	EraseShape(shape);  	shape.m_x += 2*x; 	shape.m_y += y;  	ShowShape(shape);  	return true; }  void FixBoard(Shape& shape) {    	//固定在游戏板上了 	isChecking = true; 	int maxY = 0;//一行全满，则删除。  	for ( int i = 0; i < 2; ++i) 	{ 		unsigned int num = 128;  		for (int j = 0; j < 8; ++j) 		{ 			int row = i * 2 + j / 4; 			int nx = shape.m_x + (j%4) * 2;//? 			int ny = shape.m_y + row;//?  			if (shape.m_block.blockShape[i] & num) 			{ 				maxY = ny - startY - 1; 				g_Board[maxY][(nx-startX-2)/2] = 1;//? 			}  			num = num >> 1; 		} 	}  	//开始准备消行，只需要统计落下的最后4行 	int fullNumber = 0; 	int nextRow = maxY;  	for (int i = 0; i < 4; ++i) 	{ 		bool flag = true;  		for (int j = 0; j < Width; ++j) 		{ 			if (!g_Board[nextRow][j]) 			{ 				flag = false; 				break; 			} 		}  		if (flag) 		{ 			++fullNumber;  			for (int j = 0; j < Width; ++j) 			{ 				SetCursor(j*2+startX + 2, startY+nextRow+1);//? 				printf("%s", "口"); 			}  			DeleteRow(nextRow); 		} 		else 		{ 			nextRow -= 1; 			if (nextRow < 0) 			{ 				break; 			} 		} 	}  	Sleep(100);  	if (fullNumber) 	{ 		for (int i = 0; i < Height; ++i) 		{ 			for (int j = 0; j < Width; ++j) 			{ 				SetCursor(startX+j*2+2, startY+i+1);  				if (g_Board[i][j])//? 				{ 					printf("%s", "*");//此处也是方块字符。用*代替。 				} 				else 				{ 					printf("%s", "　"); 				} 			} 		} 	}  	isChecking = false; }  void RotateShape(Shape& shape) { 	Shape temp; 	temp.m_x = shape.m_x; 	temp.m_y = shape.m_y; 	temp.m_block = blocks[shape.m_block.next];  	if (Collision(temp, 0, 0)) 	{ 		return; 	}  	EraseShape(shape); 	shape.m_block = blocks[shape.m_block.next]; 	ShowShape(shape);  	//return; }  int main(void) { 	HideCursor(); 	DrawFrame(startX, startY, Width, Height);  	Shape shape; 	CreateShape(shape, GetRandomShape(2), startX+8, startY+1);  	DWORD oldTime = ::GetTickCount(); 	DWORD lastKeyDownTime = GetTickCount(); 	DWORD deltaTime = 0, newTime;  	while (true) 	{ 		newTime = ::GetTickCount(); 		deltaTime += newTime - oldTime; 		oldTime = newTime;  		if ( deltaTime > 500 )//deltaTime下落速度。 		{ 			deltaTime = 0;  			//如果下移失败，证明到底或者撞到已有的部分了 			if (!ChangePositon(shape, 0, 1)) 			{ 				FixBoard(shape);  				if (!CreateShape(shape, GetRandomShape(2), startX+8, startY+1)) 				{ 					break; 				} 			} 		}  		if (GetTickCount() - lastKeyDownTime >= 100)  		{ 			if (!isChecking)  			{ 				lastKeyDownTime = GetTickCount();  				if (GetAsyncKeyState(VK_UP))  				{ 					RotateShape(shape); 				} 				if (GetAsyncKeyState(VK_LEFT))  				{ 					ChangePositon(shape, -1, 0); 				} 				if (GetAsyncKeyState(VK_RIGHT))  				{ 					ChangePositon(shape, 1, 0); 				} 				if (GetAsyncKeyState(VK_DOWN))  				{ 					if(!ChangePositon(shape, 0, 2) ) 					{ 						ChangePositon(shape, 0, 1); 					} 				} 			} 		} 	}  	return 0; }   你能写些注释吗，我想认真看下这些代码。

我最近也写了一个俄罗斯方块。详细注释的： http://blog.csdn.net/qingdujun/article/details/17055879

忘记说了，我的是linux环境下的


Question: 请问，linux下termios应该怎样设置，才能实现字节的二进制接收

linux下串口的控制，没人做过吗


Question: while (getchar() != EOF)循环怎么结束？

linux: Ctrl+D   windows: Ctrl+Z  一般不都是用回车结束么? while ((ch=getchar()) != '\n') {    //... }

ctrl+d

因为scanf函数是有返回值的，他的返回值是读入数据的个数，操作系统里EOF默认是int的1，所以可以这样判断：  while(scanf("%c", &c)==1){  }  也可这样判断： while(scanf("%c", &c) != EOF){ }  都是一个道理。  怎样让操作系统知道你已经输入完毕了呢？ --通过向OS发送控制信号：  SIGINT   ^C   (default action: terminate the process) SIGQUIT  ^\   (default action: terminate the process and dump to a core file) SIGSUSP  ^Z   (default action: suspend the process)   OS会捕获信号，然后判断并作出处理。

引用 2 楼 mujiok2003 的回复:linux: ctrl + D  windows: ctrl + Z

linux: ctrl + D

Windows和Linux下的EOF的字符输入不一样，反正你就试试CTRL-C／CTRL-D/CTRL-Z等组合键。  引用 楼主 kxteb0cc 的回复: 百度EOF解释为程序结束标示符，他的值我在本机中打印出是-1，getchar != EOF就是说输入字符不等于-1吧？为嘛我输入-1程序还是不能结束呢？或者我的理解不对，请高手指点下，谢谢


Question: linux下用C语言写的聊天程序中的一个问题

多谢提醒，当时也确实考虑过包体的定义问题，不过我这里是write错误，接发消息应该没有问题。。  引用 7 楼 zhao4zhong1 的回复:不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊！ http://topic.csdn.net/u/20120210/09/51109ed0-07b9-41f2-b487-a51597f2ca01.html

当执行if(!fork())时，说明!fork()值为真，也就是非0，那fork()的值肯定就是0了，这样下面执行的就是子进程啊。。  引用 6 楼 carlos1520 的回复:你没有判断fork返回值，根据返回值确定是主进程还是子进程。 你的 if(!fork()) 这样创建下来 主进程和子进程都进入下面的代码段中。

由于时间比较紧张，代码还有很多需要完善的地方，大家先帮忙看看吧

客户端代码  #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h>		//基本系统数据类型 #include <sys/socket.h>		//提供socket函数和相关数据结构 #include <netinet/in.h>		//定义了数据结构struct sockaddr_in; #include <unistd.h>			//提供通用的文件、目录、程序和进程操作的函数 #include <errno.h>			//处理出错机制 #include <netinet/tcp.h>    #define MAXDATASIZE 128 #define PORT 3000 static int sockfd;  int main(int argc, char ** argv) { 	int sockfd,nbytes; 	char buf[MAXDATASIZE]; 	char name[10],password[10],str[50],s1[50]; 	 	struct sockaddr_in srvaddr,clientaddr; 	 	char *p,*p1,*p2; 	char bufp[10]; 	char mes[1024];  	 	if (argc != 2) 	{ 		printf ("Usage error\n"); 		exit(1); 	} 	 	//创建套接字 	sockfd = socket(AF_INET,SOCK_STREAM,0); 	if(sockfd == -1) 	{ 		printf ("can not create socket\n"); 		exit(1); 	} 	 	//分配服务器的套接字地址 	bzero(&srvaddr,sizeof(srvaddr)); 	srvaddr.sin_family = AF_INET; 	srvaddr.sin_port = htons(PORT); 	if (inet_aton("127.0.0.1",&srvaddr.sin_addr) == 0) 	{ 		printf ("addr convert error\n"); 		exit(1); 	} 	 	//对远程服务器发起连接请求 	if(connect(sockfd,(struct sockaddr *)&srvaddr,sizeof(struct sockaddr)) == -1) 	{ 		printf ("connect error\n"); 		close(sockfd); 		exit(1); 	} 	 	 	/*读取用户命令字，case 用户注册*/ 	if (strcmp("register",argv[1]) == 0) 	{ 		printf ("please input username:"); 		scanf ("%s",name); 		printf ("please input userpassword:"); 		scanf ("%s",password); 		 		bzero(buf, sizeof(buf)); 		sprintf (buf,"%s%s%s%s%s",argv[1]," ",name," ",password); 		 		printf ("%s\n",buf); 		 		write(sockfd,buf,strlen(buf)); 		 		if((nbytes = read(sockfd,buf,MAXDATASIZE)) == -1) 		{ 			printf ("read error\n"); 			close(sockfd); 			exit(1); 		} 		buf[nbytes] = '\0'; 		printf ("server response: %s\n", buf); 		 	} 	 	/*读取用户命令字——用户登录*/ 	else if (strcmp(argv[1],"login") ==0) 	{ 		printf ("please input your name:"); 		scanf ("%s",name); 		printf ("please input your password:"); 		scanf ("%s",password); 		 		bzero(buf,sizeof(buf)); 		sprintf (buf,"%s%s%s%s%s",argv[1]," ",name," ",password); 		 		write(sockfd,buf,sizeof(buf)); 		 		 		if((nbytes = read(sockfd,buf,MAXDATASIZE)) == -1) 		{ 			printf ("read error\n"); 			close(sockfd); 			exit(1); 		} 		buf[nbytes] = '\0'; 		//printf ("%d\n",nbytes); 		printf ("server response: %s\n", buf); 		 		nbytes = read(sockfd,buf,MAXDATASIZE);	 		 		//这里创建子进程保证用户在登录状态(没有任何功能选择)时可以收到其他用户的消息，注:若此时收到消息要先输入chat 朋友名,再进行聊天 		if (!fork()) 		{ 			bzero(buf,sizeof(buf)); 			nbytes = read(sockfd,buf,MAXDATASIZE); 			 			if(nbytes == -1) 			{ 				printf ("read error\n");		 				exit(1); 			} 			buf[nbytes] = '\0'; 			//printf ("%d\n",nbytes); 			printf ("%s\n",buf); 			strcpy(bufp,buf); 			p = strtok(buf," "); 			p1 = strtok(NULL," "); 			p2 = strtok(NULL," "); 			if (strcmp(p,"chat") == 0) 			{ 				printf ("\n%s:%s\n\n",p1,p2); 			} 			exit(0); 			 				 		} 		printf ("please input your choose:\n"); 		printf ("********************************\n"); 		printf ("chat	logout	search	cancel\n"); 		printf ("********************************\n"); 		 		for(;;) 		{ 			scanf ("%s",s1); 			 			if (strcmp(s1,"chat") == 0) 			{ 					 					printf ("please choose your friend:"); 					scanf ("%s",name); 					 					while(1) 					{ 						if (!fork()) 						{ 							for(;;) 							{ 								//子进程用于接收消息，父进程发送消息 								bzero(buf,sizeof(buf)); 								if((nbytes = read(sockfd,buf,MAXDATASIZE)) == -1) 								{ 								 									printf ("read error\n");		 									exit(1); 								} 								 								strcpy(bufp,buf); 								p = strtok(buf," "); 								p1 = strtok(NULL," "); 								p2 = strtok(NULL," "); 								if (strcmp(p,"chat") == 0) 								{ 									printf ("\n%s:%s\n\n",p1,p2); 							 								} 									 							} 							exit(0); 			 						} 						//printf ("please input content:"); 						bzero(mes,sizeof(mes)); 						scanf("%s",str); 						printf ("\n"); 						 						bzero(buf,sizeof(buf)); 						 						sprintf (buf,"%s%s%s%s%s",s1," ",name," ",str); 						write(sockfd,buf,sizeof(buf));	 				 					} 			} 		} 	}  	close(sockfd); 	 	return 0; }   引用 3 楼 xingat110 的回复:客户端呢？

客户端呢？

服务器一直都可以收到这两个客户端发送的消息，这说明他们一直处于连接状态的吧。。  引用 1 楼 user-4 的回复:长链接的话，加一个心跳机制吧！ 保证socket套接字一直是有效的！

长链接的话，加一个心跳机制吧！ 保证socket套接字一直是有效的！


Question: 大家探讨一些“编程好比盖房子”这个话题

我看過一本書,內容有一句話,寫得好,寫得快  本來認為寫得快,代碼自然沒那麼好,注解沒那麼多  然後,我就試試慢慢寫,排位,代碼,注解,都慢慢得寫,寫清楚,寫好它  最後發現,還真的快多了,DEBUG少了,每個功能清晰,整個代碼有條理,方便維護,修改及理解  如果應用到盖房子上,就是要打好地基,不然再建上去就會~倒!!!!!!!!!!!!!!!!!!!!

说的很对,理论上是这样的

软件设计上的很多很多思想都是从建筑上得来的。

代码大全上有各种 metaphor.  软件可以推倒重来, 建筑不行.  模块化的思想差不多吧, 又何止建筑呢.

埃！现在这个社会本来就是浮躁的！

我们为什么都会问这样的一些自己可以想到的话题.  因为我们不太自信,或者太屌丝,或者没有或者了,,,

有相似之处，任何事物都有其共性，也有其独特的一面，不能捕风捉影，看到一点相似性就认为两个事情是相通的。 要弄清楚这个问题，必须深入了解

有一点不同，就是搬砖在这里不累，一个ctrl-c和ctrl-v就能搬好多

计算机领域中“隐喻”总是不那么给力。

依稀记得有本书上说过，说编程好比任何一样事物都不够贴切。 而且以盖房子、XXX、XXX至少三个比喻为例做了逐一分析。

一语中的！  引用 楼主 N_sev7 的回复:RT 我总听到有人说编程好比盖房子 像使用java的人员只管了解结构功能， 然后像建筑师一样设计好房子的结构 然后就是调用就OK了 像我们这些写底层的，就有点造砖，造建材的一样 随着编程技术的发展，貌似越来越多人看中的不在是建材的质量 更注重楼房的好看与否  以上是给我的感觉，总结：比如完全不恰当  大家说说自己的看法


Question: 浮点计算 高精度

有定点数的库。

要求很准确就使用double 或者自定义高精度数

转换成 int 类型计算

用10进制小数不能精确表示某些三进制小数0.1(3)=0.33333333333……(10) 同理，用二进制小数也不能精确表示某些10进制小数。

引用 1 楼 turingo 的回复:(double)1 + (double)0.1  引用 楼主 asdwt123 的回复:大家都知道浮点运算。c语言里float有效位是5或6，现在编写一个浮点程序。比如就计算1+0.1，怎么让它自动转换成高精度运算的程序使得输出尽可能精确 引用 2 楼 worldy 的回复:要求很准确就使用double 或者自定义高精度数++++


Question: （数据压缩）RAR算法的原理以及用C的实现与执行。

如果要强行研究可口可乐配方，可以自己研究下分子结构看看，(*^__^*) 嘻嘻……

引用 1 楼 gqjjqg 的回复:RAR是一种专利文件格式，基本不可能直接拿到压缩算法，可以发邮件问下作者压缩算法原理。 解压缩的算法估计可以拿到，最多也就出一个RAR解压算法的报告。  你的导师 布置的这个任务不太合理，7-ZIP 比RAR好用很多，压缩比也高多了。而且还是个开源的，有源码，有原理，要研究也研究这个。 是的，如果要强行研究，可以自己研究下反汇编看看，(*^__^*) 嘻嘻……

引用 4 楼 zhao4zhong1 的回复:建议反问老师要可口可乐配方！这个才叫有挑战性！！  这个要顶，哈哈，一个导师无聊的想法说不定误了学生一辈子...

建议反问老师要可口可乐配方！这个才叫有挑战性！！

引用 2 楼 zhao4zhong1 的回复:[quote=引用 1 楼 gqjjqg 的回复:] RAR是一种专利文件格式，基本不可能直接拿到压缩算法，可以发邮件问下作者压缩算法原理。 解压缩的算法估计可以拿到，最多也就出一个RAR解压算法的报告。  你的导师 布置的这个任务不太合理，7-ZIP 比RAR好用很多，压缩比也高多了。而且还是个开源的，有源码，有原理，要研究也研究这个。 英雄所见略同。[/quote]  有可能他们老师认为开源的没有难度

引用 1 楼 gqjjqg 的回复:RAR是一种专利文件格式，基本不可能直接拿到压缩算法，可以发邮件问下作者压缩算法原理。 解压缩的算法估计可以拿到，最多也就出一个RAR解压算法的报告。  你的导师 布置的这个任务不太合理，7-ZIP 比RAR好用很多，压缩比也高多了。而且还是个开源的，有源码，有原理，要研究也研究这个。 英雄所见略同。


Question: 求帮画个仿真图   在线等

[quote=引用 1 楼 turingo 的回复:] Keil环境本身就是可以软件仿真的。  我想要proteus的仿真图   能不能帮我连下

Keil环境本身就是可以软件仿真的。  引用 楼主 u012887645 的回复:#include<reg52.h> //头文件 unsigned char key=0xff;   //定义一个变量用于存放按键值 void readkey();   //读按键子函数,获取键值 void main()    //主函数 { while(1) {    readkey(); //读按键值 if(key!=0xff) //判断是否有按键按下 P2=~key;//这里取反：是因为LED为共阴，显示所按下的值    } } void readkey() //读键盘子函数 { P0=0xfe; //将第一列拉低，扫描是否有按键按下，第一列键值为：0，4，8，C key=P0;  //读取键盘值 if(key!=0xfe) //若key！=0xfe，说明有按键按下，则返回 return;    //否则继续扫描下一列 P0=0xfd; key=P0; if(key!=0xfd) return; P0=0xfb; key=P0; if(key!=0xfb) return; P0=0xf7; key=P0; if(key!=0xf7) return; key=0xff; }


Question: 关于线程间数据同步问题，求助

引用 10 楼 zhao4zhong1 的回复:[quote=引用 9 楼 lm_whales 的回复:] 系统时钟，大约18.2 毫秒来一次，而且还可能用来做线程切换用。 错！ 应该是每（1/18.2）秒[/quote] ++ 好像是这样的 那就是 55ms 了。

引用 9 楼 lm_whales 的回复:系统时钟，大约18.2 毫秒来一次，而且还可能用来做线程切换用。 错！ 应该是每（1/18.2）秒

设计有问题吧！多线程就少用全局变量来做！调用接口获取参数多好！ 而且你全局变量的改变又导致了局部变量的变化！这是自己给自己添堵吧！ 换思路吧！

系统时钟，大约18.2 毫秒来一次，而且还可能用来做线程切换用。

声音处理定时器主要用来延时。 定时器不可能精确做到20ms延时  媒体定时器可以做到 1ms 延时，要好的多。  另外 媒体定时器的回调函数，不要做太多处理，也不要等待睡眠； 只是开或者关声音，和设置声音频率即可。  媒体定时器，就是用来处理多媒体播放的，比定时器要好得多。 用驱动程序，可以开1us 定时器，比系统定时器要好的多，  发包，解包这些，完全不需要那么准确。 只要保证时间到的时候，有数据可用即可。 ---可以打个提前量----

引用 5 楼 AnYidan 的回复:20ms 应该用低层的中断做吧 有介绍低层中断的文章链接么

引用 4 楼 lm_whales 的回复:声音处理，要用媒体定时器，或者驱动程序来做， 20ms 的定时器，是非常不靠谱的。 有对媒体定时器，或者驱动实现的文章么 最后发包还是要通过应用层的吧，这样不是还有之前的问题么

20ms 应该用低层的中断做吧

仅供参考//循环向a函数每次发送200个字节长度（这个是固定的）的buffer, //a函数中需要将循环传进来的buffer，组成240字节（也是固定的）的新buffer进行处理， //在处理的时候每次从新buffer中取两个字节打印 #ifdef WIN32     #pragma warning(disable:4996) #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef WIN32     #include <windows.h>     #include <process.h>     #include <io.h>     #define  MYVOID             void     #define  vsnprintf          _vsnprintf #else     #include <unistd.h>     #include <sys/time.h>     #include <pthread.h>     #define  CRITICAL_SECTION   pthread_mutex_t     #define  MYVOID             void * #endif //Log{ #define MAXLOGSIZE 20000000 #define MAXLINSIZE 16000 #include <time.h> #include <sys/timeb.h> #include <stdarg.h> char logfilename1[]="MyLog1.log"; char logfilename2[]="MyLog2.log"; static char logstr[MAXLINSIZE+1]; char datestr[16]; char timestr[16]; char mss[4]; CRITICAL_SECTION cs_log; FILE *flog; #ifdef WIN32 void Lock(CRITICAL_SECTION *l) {     EnterCriticalSection(l); } void Unlock(CRITICAL_SECTION *l) {     LeaveCriticalSection(l); } void sleep_ms(int ms) {     Sleep(ms); } #else void Lock(CRITICAL_SECTION *l) {     pthread_mutex_lock(l); } void Unlock(CRITICAL_SECTION *l) {     pthread_mutex_unlock(l); } void sleep_ms(int ms) {     usleep(ms*1000); } #endif void LogV(const char *pszFmt,va_list argp) {     struct tm *now;     struct timeb tb;      if (NULL==pszFmt||0==pszFmt[0]) return;     vsnprintf(logstr,MAXLINSIZE,pszFmt,argp);     ftime(&tb);     now=localtime(&tb.time);     sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday);     sprintf(timestr,"%02d:%02d:%02d",now->tm_hour     ,now->tm_min  ,now->tm_sec );     sprintf(mss,"%03d",tb.millitm);     printf("%s %s.%s %s",datestr,timestr,mss,logstr);     flog=fopen(logfilename1,"a");     if (NULL!=flog) {         fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr);         if (ftell(flog)>MAXLOGSIZE) {             fclose(flog);             if (rename(logfilename1,logfilename2)) {                 remove(logfilename2);                 rename(logfilename1,logfilename2);             }         } else {             fclose(flog);         }     } } void Log(const char *pszFmt,...) {     va_list argp;      Lock(&cs_log);     va_start(argp,pszFmt);     LogV(pszFmt,argp);     va_end(argp);     Unlock(&cs_log); } //Log} #define ASIZE    200 #define BSIZE    240 #define CSIZE      2 char Abuf[ASIZE]; char Cbuf[CSIZE]; CRITICAL_SECTION cs_HEX ; CRITICAL_SECTION cs_BBB ; struct FIFO_BUFFER {     int  head;     int  tail;     int  size;     char data[BSIZE]; } BBB; int No_Loop=0; void HexDump(int cn,char *buf,int len) {     int i,j,k;     char binstr[80];      Lock(&cs_HEX);     for (i=0;i<len;i++) {         if (0==(i%16)) {             sprintf(binstr,"%03d %04x -",cn,i);             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);         } else if (15==(i%16)) {             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);             sprintf(binstr,"%s  ",binstr);             for (j=i-15;j<=i;j++) {                 sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');             }             Log("%s\n",binstr);         } else {             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);         }     }     if (0!=(i%16)) {         k=16-(i%16);         for (j=0;j<k;j++) {             sprintf(binstr,"%s   ",binstr);         }         sprintf(binstr,"%s  ",binstr);         k=16-k;         for (j=i-k;j<i;j++) {             sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');         }         Log("%s\n",binstr);     }     Unlock(&cs_HEX); } int GetFromRBuf(int cn,CRITICAL_SECTION *cs,FIFO_BUFFER *fbuf,char *buf,int len) {     int lent,len1,len2;      lent=0;     Lock(cs);     if (fbuf->size>=len) {         lent=len;         if (fbuf->head+lent>BSIZE) {             len1=BSIZE-fbuf->head;             memcpy(buf     ,fbuf->data+fbuf->head,len1);             len2=lent-len1;             memcpy(buf+len1,fbuf->data           ,len2);             fbuf->head=len2;         } else {             memcpy(buf     ,fbuf->data+fbuf->head,lent);             fbuf->head+=lent;         }         fbuf->size-=lent;     }     Unlock(cs);     return lent; } MYVOID thdB(void *pcn) {     char        *recv_buf;     int          recv_nbytes;     int          cn;     int          wc;     int          pb;      cn=(int)pcn;     Log("%03d thdB              thread begin...\n",cn);     while (1) {         sleep_ms(10);         recv_buf=(char *)Cbuf;         recv_nbytes=CSIZE;         wc=0;         while (1) {             pb=GetFromRBuf(cn,&cs_BBB,&BBB,recv_buf,recv_nbytes);             if (pb) {                 Log("%03d recv %d bytes\n",cn,pb);                 HexDump(cn,recv_buf,pb);                 sleep_ms(1);             } else {                 sleep_ms(1000);             }             if (No_Loop) break;//             wc++;             if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc);         }         if (No_Loop) break;//     } #ifndef WIN32     pthread_exit(NULL); #endif } int PutToRBuf(int cn,CRITICAL_SECTION *cs,FIFO_BUFFER *fbuf,char *buf,int len) {     int lent,len1,len2;      Lock(cs);     lent=len;     if (fbuf->size+lent>BSIZE) {         lent=BSIZE-fbuf->size;     }     if (fbuf->tail+lent>BSIZE) {         len1=BSIZE-fbuf->tail;         memcpy(fbuf->data+fbuf->tail,buf     ,len1);         len2=lent-len1;         memcpy(fbuf->data           ,buf+len1,len2);         fbuf->tail=len2;     } else {         memcpy(fbuf->data+fbuf->tail,buf     ,lent);         fbuf->tail+=lent;     }     fbuf->size+=lent;     Unlock(cs);     return lent; } MYVOID thdA(void *pcn) {     char        *send_buf;     int          send_nbytes;     int          cn;     int          wc;     int           a;     int          pa;      cn=(int)pcn;     Log("%03d thdA              thread begin...\n",cn);     a=0;     while (1) {         sleep_ms(100);         memset(Abuf,a,ASIZE);         a=(a+1)%256;         if (16==a) {No_Loop=1;break;}//去掉这句可以让程序一直循环直到按Ctrl+C或Ctrl+Break或当前目录下存在文件No_Loop         send_buf=(char *)Abuf;         send_nbytes=ASIZE;         Log("%03d sending %d bytes\n",cn,send_nbytes);         HexDump(cn,send_buf,send_nbytes);         wc=0;         while (1) {             pa=PutToRBuf(cn,&cs_BBB,&BBB,send_buf,send_nbytes);             Log("%03d sent %d bytes\n",cn,pa);             HexDump(cn,send_buf,pa);             send_buf+=pa;             send_nbytes-=pa;             if (send_nbytes<=0) break;//             sleep_ms(1000);             if (No_Loop) break;//             wc++;             if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc);         }         if (No_Loop) break;//     } #ifndef WIN32     pthread_exit(NULL); #endif } int main() { #ifdef WIN32     InitializeCriticalSection(&cs_log);     InitializeCriticalSection(&cs_HEX );     InitializeCriticalSection(&cs_BBB ); #else     pthread_t threads[2];     int threadsN;     int rc;     pthread_mutex_init(&cs_log,NULL);     pthread_mutex_init(&cs_HEX,NULL);     pthread_mutex_init(&cs_BBB,NULL); #endif     Log("Start===========================================================\n");      BBB.head=0;     BBB.tail=0;     BBB.size=0;  #ifdef WIN32     _beginthread((void(__cdecl *)(void *))thdA,0,(void *)1);     _beginthread((void(__cdecl *)(void *))thdB,0,(void *)2); #else     threadsN=0;     rc=pthread_create(&(threads[threadsN++]),NULL,thdA,(void *)1);if (rc) Log("%d=pthread_create %d error!\n",rc,threadsN-1);     rc=pthread_create(&(threads[threadsN++]),NULL,thdB,(void *)2);if (rc) Log("%d=pthread_create %d error!\n",rc,threadsN-1); #endif      if (!access("No_Loop",0)) {         remove("No_Loop");         if (!access("No_Loop",0)) {             No_Loop=1;         }     }     while (1) {         sleep_ms(1000);         if (No_Loop) break;//         if (!access("No_Loop",0)) {             No_Loop=1;         }     }     sleep_ms(3000);     Log("End=============================================================\n"); #ifdef WIN32     DeleteCriticalSection(&cs_BBB );     DeleteCriticalSection(&cs_HEX );     DeleteCriticalSection(&cs_log); #else     pthread_mutex_destroy(&cs_BBB);     pthread_mutex_destroy(&cs_HEX);     pthread_mutex_destroy(&cs_log); #endif     return 0; }

尽量减少线程间耦合


Question: C语言左移右移操作符算法反推

秒的精度为2秒

http://bbs.csdn.net/topics/390660970 date = ((year - 1980)<<9) + (month <<5) + day;  其中：year >=1980  time = (hour <<11) + (minute <<5) + (second >>1);   现在我知道，date = 17273, time = 33976 17273(10)                 33976(10) 100001101111001(2)        1000010010111000(2) 100001 1011 11001(2)        10000 100101 11000(2)     33-  11-   25              16:    37:   24  +1980                                      <<1   2013-  11-   25              16:    37:   48

引用 1 楼 user-2 的回复:date = ((year - 1980)<<9) + (month <<5) + day; 其中：year >=1980 time = (hour <<11) + (minute <<5) + (second >>1);  year=date>>9+1980 month=date & mMask>>5;//mMask的看Moth占几位，占的位上写上1，就是mMask day=date & mMaskA;//mMaskA同上  谢谢，month 那里 是应该 date >> 5 & nMask ?还是像你写的。这样。 还有 那个second 为什么是 右移一位，那数不就不对了吗


Question: 关于结构的赋值问题

Designated Initializer是C99引入的新特性，用于初始化稀疏（Sparse）结构体和稀疏数组很方便。有些时候结构体或数组中只有某一个或某几个成员需要初始化，其它成员都用0初始化即可，用Designated Initializer语法可以针对每个成员做初始化（Memberwise Initialization），例如：  struct complex_struct z1 = { .y = 4.0 }; /* z1.x=0.0, z1.y=4.0 */  所以说，这样语法是没错的，应该是你的编译器不支持这样特性。

gcc下编译通过，运行输出0 估计是楼主的编译器不支持这样赋值。

看的是 c primer 这本书。里面就是这么说的。

struct book p1 = { 0}; p1.c = 10; p1.b = 20;    换一个本书

楼主看的什么书？这种结构体初始化方法不是标准的，GNU带这样的扩展

编译器 没支持这个特性呗


Question: typedef可以同时为一个类型起两个别名？

不跟其它关键字标志符一样。  引用 5 楼 chybeyond123456789 的回复:[quote=引用 3 楼 max_min_ 的回复:] 这个，多个都没有问题的阿！只要不重复就好！ 不重复是什么意思啊，不跟其它关键字的别名重复吗？[/quote]

定义100个都可以

#include<stdio.h>  typedef int my_int1, my_int2;  int main(){ 	my_int1 a = 1; 	my_int2 b = 2; 	printf("%d,%d",a,b); 	return 0; }  输出： 1,2 typedef只是起了别名而已，编译器实际编译的时候，不是通过别名编译的，而是通过别名找到 typedef sometype alias1, alias2; 这个声明里的sometype进行编译。  typedef struct {     int x;     int y; }name1, name2; name1 a;  实际编译的是： struct{int x, int y} a;  -----------------------------

引用 3 楼 max_min_ 的回复:这个，多个都没有问题的阿！只要不重复就好！ 不重复是什么意思啊，不跟其它关键字的别名重复吗？

类型别名，有时候方便代码逻辑理解

这个，多个都没有问题的阿！只要不重复就好！

楼主好奇心很强

别名没有限制的，例如： typedef unsigned char int8u_t; typedef unsigned char u8; typedef unsigned char byte;  引用 楼主 syrchina 的回复: typedef struct {     int x;     int y; }name1, name2;//同时声明两个也可以？编译器是具体怎么操作的？   typedef struct {     int x;     int y; }name1, *pname1;//以前常用这种方式，想来应该是类似的   请高手指点迷津，谢谢

引用 10 楼 zhao4zhong1 的回复://char (*(*x[3])())[5];//x是什么类型的变量? // //分析C语言声明，关键是搞清楚这个变量是个什么东西（函数、指针、数组）， //是函数那么剩下的就是他的参数和返回值， //是指针那剩下部分是说明他指向什么， //是数组剩下的部分就是说明数组的成员是什么类型。 //解析C语言声明规则： //从左侧第一个标识符开始，按照优先级进行结合。*表示是..的指针，const表示只读的，volatile表示可变的，[]表示是数组，()表示是函数。   感谢赵老师大公无私亲力亲为不厌其烦勤勤恳恳兢兢业业的指点

//char (*(*x[3])())[5];//x是什么类型的变量? // //分析C语言声明，关键是搞清楚这个变量是个什么东西（函数、指针、数组）， //是函数那么剩下的就是他的参数和返回值， //是指针那剩下部分是说明他指向什么， //是数组剩下的部分就是说明数组的成员是什么类型。 //解析C语言声明规则： //从左侧第一个标识符开始，按照优先级进行结合。*表示是..的指针，const表示只读的，volatile表示可变的，[]表示是数组，()表示是函数。 // //x和[3]结合说明是一个大小为3的数组，该数组指向了一个指针，该指针指向一个函数，该函数的无参数，返回一个指针，该指针指向一个大小为5的char型数组 #include <stdio.h> #include <typeinfo.h> char num[5]; char (*x00())[5] {     return # } int main() {     char (*x000)[5];//返回值     char (*(x00)())[5];//函数原型，参数为空，返回值为指针     char (*(*x0)())[5];//数组的元素，是个函数指针     char (*(*x[3])())[5];//是个数组，大小为3      x0 = x00;     x[0] = x0;     x[1] = x0;     x[2] = x0;     printf("typeid(x).name() is %s\n",typeid(x).name());     return 0; } //typeid(x).name() is char (* (__cdecl**)(void))[5]

借宝地问一个相关问题，为什么下了语句在VS2008中编译通不过？  typedef struct{} (*PFUN)();


Question: typedef 定义结构体 多级指针问题

//在堆中开辟一个2×3×4×5的4维int数组 #include <stdio.h> #include <malloc.h> int ****p; int h,i,j,k; void main() {     p=(int ****)malloc(2*sizeof(int ***));     if (NULL==p) return;     for (h=0;h<2;h++) {         p[h]=(int ***)malloc(3*sizeof(int **));         if (NULL==p[h]) return;         for (i=0;i<3;i++) {             p[h][i]=(int **)malloc(4*sizeof(int *));             if (NULL==p[h][i]) return;             for (j=0;j<4;j++) {                 p[h][i][j]=(int *)malloc(5*sizeof(int));                 if (NULL==p[h][i][j]) return;             }         }     }     for (h=0;h<2;h++) {         for (i=0;i<3;i++) {             for (j=0;j<4;j++) {                 for (k=0;k<5;k++) {                     p[h][i][j][k]=h*60+i*20+j*5+k;                 }             }         }     }     for (h=0;h<2;h++) {         for (i=0;i<3;i++) {             for (j=0;j<4;j++) {                 for (k=0;k<5;k++) {                     printf(" %3d",p[h][i][j][k]);                 }                 printf("\n");             }             printf("--------------------\n");         }         printf("=======================\n");     }     for (h=0;h<2;h++) {         for (i=0;i<3;i++) {             for (j=0;j<4;j++) {                 free(p[h][i][j]);             }             free(p[h][i]);         }         free(p[h]);     }     free(p); } //   0   1   2   3   4 //   5   6   7   8   9 //  10  11  12  13  14 //  15  16  17  18  19 //-------------------- //  20  21  22  23  24 //  25  26  27  28  29 //  30  31  32  33  34 //  35  36  37  38  39 //-------------------- //  40  41  42  43  44 //  45  46  47  48  49 //  50  51  52  53  54 //  55  56  57  58  59 //-------------------- //======================= //  60  61  62  63  64 //  65  66  67  68  69 //  70  71  72  73  74 //  75  76  77  78  79 //-------------------- //  80  81  82  83  84 //  85  86  87  88  89 //  90  91  92  93  94 //  95  96  97  98  99 //-------------------- // 100 101 102 103 104 // 105 106 107 108 109 // 110 111 112 113 114 // 115 116 117 118 119 //-------------------- //======================= //

动态内存申请和释放配对的，不释放指不定什么时候就会出现内存泄露滴

二级指针已经够头大的了，三级指针我能说个靠吗，楼主你如果没晕的话，我你

还有个问题是如果我在子函数中使用calloc或者malloc 但是不用free函数释放的话,子函数执行完之后,calloc或者malloc 开辟的空间应该不会自动被释放的吧? 是的，结果会造成内存泄漏。  指针可以用，不能乱用，否则到最后会把自己搞晕的

languagePtr pLanguage;  //定义结构体指针 languagePtr *ppLanguage; //这是定义二级指针么 languagePtr **ppppLanguage; //这是定义三级指针么  回答：是的

什么的需要导致你想到用多级指针啊！ 这样你会坑了你自己的！换个别的思路吧！

不建议用两级以上的指针，最后总要确保malloc/free是配对的。  引用 楼主 summit677 的回复:定义结构体指针: typedef struct language { int id; char name[66]; char ISOCode[34]; } *languagePtr;   以下定义是什么意思:  languagePtr pLanguage;  //定义结构体指针 languagePtr *ppLanguage; //这是定义二级指针么 languagePtr **ppppLanguage; //这是定义三级指针么    还有个问题是如果我在子函数中使用calloc或者malloc 但是不用free函数释放的话,子函数执行完之后,calloc或者malloc 开辟的空间应该不会自动被释放的吧? 例如:  void main() { int iError; int *temp languagePtr **ppppLanguage; ppppLanguage=(languagePtr **)malloc(sizeof(languagePtr *));  iError=getLanguage(ppppLanguage); *temp=*ppppLanguage; free(ppppLanguage); } getLanguage(languagePtr **ppppLanguage) { int i=10; languagePtr *ppLanguage=NULL; *ppppLanguage=ppLanguage=(languagePtr *)calloc(i+ 1, sizeof(languagePtr )); for(j=0;j<i;j++) { languagePtr pLanguage= (languagePtr )calloc(1, sizeof(language)); *ppLanguage++ = pLanguage; } };   这个程序会有什么问题???

用多级指针的不一定都是高手

不要做A语言代码修改为B语言代码的无用功。 也不要做用A语言代码直接调用B语言代码库这样复杂、这样容易出错的傻事。 只需让A、B语言代码的输入输出重定向到文本文件，或修改A、B语言代码让其通过文本文件输入输出。 即可很方便地让A、B两种语言之间协调工作。

是的，两级以上的指针从没用过。楼主要干嘛？

是用C++ 写一个dll 访问数据库,然后labview调用dll. 但是labview的数据格式事和C不同的.


Question: SAPI中SetOutput调用问题

好吧，C的接口实在没有调通，只有封了一层，改用C++调用了

直接从MSDN上查找答案吧，参考http://msdn.microsoft.com/en-us/library/ms720410(v=vs.85).aspx  引用 楼主 tnt230 的回复:SAPI的C接口调用。  代码如下  ISpStream *pWavStream; ISpVoice *pVoice; CoInitialize(NULL); if(  S_OK != CoCreateInstance(&CLSID_SpVoice,  					NULL,  					CLSCTX_ALL,  					&IID_ISpVoice,	 					(void **)&pVoice) 					 	) { 	apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "pVoice init failed");				 }  if( S_OK != CoCreateInstance(&CLSID_SpStream,  					NULL,  					CLSCTX_ALL,  					&IID_ISpStream,	 					(void **)&pWavStream) 					 	) {     apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "pWavStream init failed");	 }  hr =pVoice->lpVtbl->SetOutput(pVoice,pWavStream,TRUE);    SetOutput调用的返回码是0x80045001。 找不到对应的错误原因，这样调用有问题吗？ pWavStream这个参数用法是否正确？

引用 1 楼 turingo 的回复:直接从MSDN上查找答案吧，参考http://msdn.microsoft.com/en-us/library/ms720410(v=vs.85).aspx  [quote=引用 楼主 tnt230 的回复:] SAPI的C接口调用。  代码如下  ISpStream *pWavStream; ISpVoice *pVoice; CoInitialize(NULL); if(  S_OK != CoCreateInstance(&CLSID_SpVoice,  					NULL,  					CLSCTX_ALL,  					&IID_ISpVoice,	 					(void **)&pVoice) 					 	) { 	apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "pVoice init failed");				 }  if( S_OK != CoCreateInstance(&CLSID_SpStream,  					NULL,  					CLSCTX_ALL,  					&IID_ISpStream,	 					(void **)&pWavStream) 					 	) {     apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "pWavStream init failed");	 }    hr =pVoice->lpVtbl->SetOutput(pVoice,pWavStream,TRUE);    SetOutput调用的返回码是0x80045001。 找不到对应的错误原因，这样调用有问题吗？ pWavStream这个参数用法是否正确？[/quote]      不明白为什么，C++的版本调用时OK的，但用C接口调用不行。 我只是想重新定位音频流到内存而已


Question: 写了修改文件内容的程序，printf打印可以正常打印出想要的结果，为什么文件里的内容总是不会被修改

检查写函数接口的返回值！确认是否写成功吧！

引用 1 楼 truelance 的回复:有2个问题 1. 用a+方式打开文件，所有的写操作都是在文件结尾添加。如果想修改已有文件内容，需要用r+方式打开 2. 使用读写方式打开的文件，在读操作之后进行写操作，或者写操作之后进行读操作，必须先调用下面函数之一 fflush, fseek, fsetpos, rewind 文件打开方式试了很多种， r+ rt+ 都不行 。 代码里少沾了一句话 。                 printf("%ld %s",i,line);                  fputs(line,fp); 我在fputs(line,fp);之前 有一个fseek(fp,-sizeof(line),SET_CUR); 这样的方式不知道是不是你说的那样  但是文件里面的内容没有变化。

所谓修改删除文件a某位置的内容，其实是读打开文件a，再将‘a中修改删除位置之前的内容＋修改删除的内容＋a中修改删除位置之后的内容’保存到文件b，关闭文件a，删除文件a，将文件b改名为与之前文件a相同的名字，仅此而已。  fopen, _wfopen Open a file.  FILE *fopen( const char *filename, const char *mode );  FILE *_wfopen( const wchar_t *filename, const wchar_t *mode );  Function Required Header Compatibility  fopen <stdio.h> ANSI, Win 95, Win NT  _wfopen <stdio.h> or <wchar.h> Win NT    For additional compatibility information, see Compatibility in the Introduction.  Libraries  LIBC.LIB Single thread static library, retail version  LIBCMT.LIB Multithread static library, retail version  MSVCRT.LIB Import library for MSVCRT.DLL, retail version    The c, n, and t mode options are Microsoft extensions for fopen and _fdopen and should not be used where ANSI portability is desired.  Return Value  Each of these functions returns a pointer to the open file. A null pointer value indicates an error.   Parameters  filename  Filename  mode  Type of access permitted  Remarks  The fopen function opens the file specified by filename. _wfopen is a wide-character version of fopen; the arguments to _wfopen are wide-character strings. _wfopen and fopen behave identically otherwise.  Generic-Text Routine Mappings  TCHAR.H Routine  _UNICODE & _MBCS Not Defined _MBCS Defined _UNICODE Defined  _tfopen fopen fopen _wfopen    The character string mode specifies the type of access requested for the file, as follows:  "r"  Opens for reading. If the file does not exist or cannot be found, the fopen call fails.  "w"  Opens an empty file for writing. If the given file exists, its contents are destroyed.  "a"  Opens for writing at the end of the file (appending) without removing the EOF marker before writing new data to the file; creates the file first if it doesn’t exist.  "r+"  Opens for both reading and writing. (The file must exist.)  "w+"  Opens an empty file for both reading and writing. If the given file exists, its contents are destroyed.  "a+"  Opens for reading and appending; the appending operation includes the removal of the EOF marker before new data is written to the file and the EOF marker is restored after writing is complete; creates the file first if it doesn’t exist.  When a file is opened with the "a" or "a+" access type, all write operations occur at the end of the file. The file pointer can be repositioned using fseek or rewind, but is always moved back to the end of the file before any write operation is carried out. Thus, existing data cannot be overwritten.  The "a" mode does not remove the EOF marker before appending to the file. After appending has occurred, the MS-DOS TYPE command only shows data up to the original EOF marker and not any data appended to the file. The "a+" mode does remove the EOF marker before appending to the file. After appending, the MS-DOS TYPE command shows all data in the file. The "a+" mode is required for appending to a stream file that is terminated with the CTRL+Z EOF marker.  When the "r+", "w+", or "a+" access type is specified, both reading and writing are allowed (the file is said to be open for “update”). However, when you switch between reading and writing, there must be an intervening fflush, fsetpos, fseek, or rewind operation. The current position can be specified for the fsetpos or fseek operation, if desired.  In addition to the above values, the following characters can be included in mode to specify the translation mode for newline characters:  t  Open in text (translated) mode. In this mode, CTRL+Z is interpreted as an end-of-file character on input. In files opened for reading/writing with "a+", fopen checks for a CTRL+Z at the end of the file and removes it, if possible. This is done because using fseek and ftell to move within a file that ends with a CTRL+Z, may cause fseek to behave improperly near the end of the file.   Also, in text mode, carriage return–linefeed combinations are translated into single linefeeds on input, and linefeed characters are translated to carriage return–linefeed combinations on output. When a Unicode stream-I/O function operates in text mode (the default), the source or destination stream is assumed to be a sequence of multibyte characters. Therefore, the Unicode stream-input functions convert multibyte characters to wide characters (as if by a call to the mbtowc function). For the same reason, the Unicode stream-output functions convert wide characters to multibyte characters (as if by a call to the wctomb function).  b  Open in binary (untranslated) mode; translations involving carriage-return and linefeed characters are suppressed.   If t or b is not given in mode, the default translation mode is defined by the global variable _fmode. If t or b is prefixed to the argument, the function fails and returns NULL.   For more information about using text and binary modes in Unicode and multibyte stream-I/O, see Text and Binary Mode File I/O and Unicode Stream I/O in Text and Binary Modes.  c  Enable the commit flag for the associated filename so that the contents of the file buffer are written directly to disk if either fflush or _flushall is called.  n  Reset the commit flag for the associated filename to “no-commit.” This is the default. It also overrides the global commit flag if you link your program with COMMODE.OBJ. The global commit flag default is “no-commit” unless you explicitly link your program with COMMODE.OBJ.  Valid characters for the mode string used in fopen and _fdopen correspond to oflag arguments used in _open and _sopen, as follows.  Characters in mode String Equivalent oflag Value for _open/_sopen   a _O_WRONLY | _O_APPEND (usually _O_WRONLY | _O_CREAT | _O_APPEND)  a+ _O_RDWR | _O_APPEND (usually _O_RDWR | _O_APPEND | _O_CREAT )  r _O_RDONLY  r+ _O_RDWR  w _O_WRONLY (usually _O_WRONLY | _O_CREAT | _O_TRUNC)  w+ _O_RDWR (usually _O_RDWR | _O_CREAT | _O_TRUNC)  b _O_BINARY  t _O_TEXT  c None  n None    Example  /* FOPEN.C: This program opens files named "data"  * and "data2".It  uses fclose to close "data" and  * _fcloseall to close all remaining files.  */  #include <stdio.h>  FILE *stream, *stream2;  void main( void ) {    int numclosed;     /* Open for read (will fail if file "data" does not exist) */    if( (stream  = fopen( "data", "r" )) == NULL )       printf( "The file 'data' was not opened\n" );    else       printf( "The file 'data' was opened\n" );     /* Open for write */    if( (stream2 = fopen( "data2", "w+" )) == NULL )       printf( "The file 'data2' was not opened\n" );    else       printf( "The file 'data2' was opened\n" );     /* Close stream */    if( fclose( stream ) )       printf( "The file 'data' was not closed\n" );     /* All other files are closed: */    numclosed = _fcloseall( );    printf( "Number of files closed by _fcloseall: %u\n", numclosed ); }   Output  The file 'data' was opened The file 'data2' was opened Number of files closed by _fcloseall: 1   Stream I/O Routines  See Also   fclose, _fdopen, ferror, _fileno, freopen, _open, _setmode

用gdb调试一下吧，既然printf能出结果，就说明的写操作没有写进去，你可以找找写的那一不是不是没有执行

不能是sizeof()啊，应该是strlen()


Question: 请问下面这个程序，除了ctrl+z结束循环外，怎样正常退出循环？

引用 6 楼 wusuopuBUPT 的回复:引用 3 楼 aoshuanghanmei 的回复:我这是HOJ上的题，题目里没有说遇到什么特定字符结束循环，只是说输入在end of file时结束。所以很困扰该怎样结束循环，除了强制结束的方法。OJ的题目多数是这样做的。但我这样做是不能跳出循环，给数据结果的啊。。。

因为scanf函数是有返回值的，他的返回值是读入数据的个数，操作系统里EOF默认是int的1，所以可以这样判断： while(scanf("%c", &c)==1){  }  也可这样判断： while(scanf("%c", &c) != EOF){ }  都是一个道理。  怎样让操作系统知道你已经输入完毕了呢？ --通过向OS发送控制信号： SIGINT   ^C   (default action: terminate the process) SIGQUIT  ^\   (default action: terminate the process and dump to a core file) SIGSUSP  ^Z   (default action: suspend the process)  OS会捕获信号，然后判断并作出处理。

while(scanf("%c", &c)==1){  .... }

while(scanf("%c", &c) != EOF) //这里的判断就是遇到EOF结束循环的阿  //可以在输入的时候判断c的值   while(scanf("%c", &c) != EOF) {   //do something    if( c== 'q')   {      break;   } }

ctrl + c ... ctrl + d ...


Question: 简单的hook，求指导，新手求学

搞定了，入门还是得从全局钩子开始，第一个参数MSDN上有，我用了鼠标钩子和键盘钩子，第二个参数是钩子处理函数名，第三个参数可以用getmoudelhandle("dll的文件名")，第四个参数0，然后具体的操作在钩子的处理函数里面写，比如键盘函数里面按一下F2就退出就可以if(wparam==VK_F2){ unhookwindowshookex(setwindowshook的返回值)； }

不明觉厉，马克

引用 4 楼 u012982053 的回复:[quote=引用 1 楼 zhao4zhong1 的回复:] 在http://www.codeproject.com搜“hook” 实例网上很多的。 学会在网上找资源。 同新手。出校门才发现在学校的时间真心爽啊。。。表找我要联系方式啊。 我羞愧得很 菜鸟一个 还是初级菜鸟。。。[/quote]嘿嘿，网上虽然资料多，但是不能让我了解一个大的层次架构，仅仅就是想验证怎么挂接上某个进程

MFC的 我喜欢先在网上搜出要使用的函数  再看msdn 如果没怎么弄懂就看中文版的

引用 1 楼 zhao4zhong1 的回复:在http://www.codeproject.com搜“hook” 实例网上很多的。 学会在网上找资源。 同新手。出校门才发现在学校的时间真心爽啊。。。表找我要联系方式啊。 我羞愧得很 菜鸟一个 还是初级菜鸟。。。

引用 2 楼 u012982053 的回复:http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990%28v=vs.85%29.aspx 怀恋才学hook的时候， 跟同学开玩笑， 直接黑了他的键盘和鼠标消息这个我看了，不过他没有个完整的例子，新手学嘛，很吃力，大哥，方便留个联系方式吗？

在http://www.codeproject.com搜“hook”


Question: C 指针问题

计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  想要从本质上理解C指针，必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针，原本看似复杂的东西就会变得非常简单！ 指针即地址。“地址又是啥？”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认：  有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物；  而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。  不要企图依赖输出指针相关表达式的值【比如printf("%p\n",...)】来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=...】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 （Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。） 想要从本质上理解C指针，必须学习C和汇编的对应关系。” 不是一回事！  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  十字链表交换任意两个节点C源代码（C指针应用终极挑战）http://download.csdn.net/detail/zhao4zhong1/5532495

这点是不是与指针的定义有冲突呢？亲？ --这要看你的编译平台。  我分别在window x64 和linux gentoo下编译： 都会报这样的warning： gcc -O0 -g3 -Wall -c -fmessage-length=0 -o main.o "..\\main.c"  ..\main.c:2:6: warning: return type of 'main' is not 'int' [-Wmain] ..\main.c: In function 'main': ..\main.c:7:4: warning: assignment from incompatible pointer type [enabled by default] ..\main.c:8:2: warning: format '%ld' expects argument of type 'long int', but argument 2 has type 'long int *' [-Wformat] ..\main.c:10:2: warning: format '%ld' expects argument of type 'long int', but argument 2 has type 'long int *' [-Wformat]  不过，运行结果就不同了 1.windows: please input a number: 2 the result 1 is 2686744 the result 2 is 2686748 //地址相差4字节  2.linux： please input a number: 2 the result 1 is 140737002356916 the result 2 is 140737002356924 //地址相差8字节   所以，这还是要取决于你的编译器中long型的size。

根据"ILP32"数据模型，int。long。和point都是32位4字节，你在编译的时候如果打开警告选项，编译器会提示类型不符，但可以编译。

你可以做一个强制类型转换。 p=(long *)&i;  long和int是否都是4个字节，这个取决于编译器。

不会冲突的，long只是说明指针指向的类型。不管什么类型的指针，长度都是4（对一般编译器来说）。你那两句打印出的是个地址！


Question: 写了一段代码，提示段错误，核心已转存

gdb 调试

看不懂你要做什么，你定义的stu[n]是干嘛用的？ 另外： 在第30行  if(p[m].birthday!=NULL){printf("指针p[%d].birthday内存分配成功\n",m);}else {printf("指针p[%d].info内存分配失败\n"),m;}  编译时出现 警告： 格式 ‘%d’ expects a matching ‘int’ argument [-Wformat]  这里的m不是int类型吗……gcc编译器在这里究竟发生了什么   看清楚这里写的语句，m实在printf的外边，怎么跟%d匹配？正确的语句：if(p[m].birthday!=NULL){printf("指针p[%d].birthday内存分配成功\n",m);}else {printf("指针p[%d].info内存分配失败\n",m）;}

非法读写内存

修改了一下 现在不会出现核心已转存问题，但是出现了低级错误  #include <stdio.h>//基本 #include <stdlib.h>//malloc #include <string.h>//strcmp  struct data{ 	int year,month,day; 	long tel; 	int add; };  struct student{ 	char name[20]; 	int num; 	char sex[2]; 	struct data* birthday; 	struct data* info; };  int main(){ 	int i,m,n; 	//--------输入人数-------- 	printf("输入一维数组的个数: \n"); 	scanf("%d",&n); 	struct student* p,stu[n]; 	//--------内存分配-------- 	p=malloc(sizeof(struct student)*n); 	if(p!=NULL){printf("指针p内存分配成功\n");}else {printf("指针p内存分配失败\n");} 	for(m=0;m<n;m++){ 	p[m].birthday=malloc(sizeof(struct data)); 	if(p[m].birthday!=NULL){printf("指针p[%d].birthday内存分配成功\n",m);}else {printf("指针p[%d].info内存分配失败\n"),m;} 	p[m].info=malloc(sizeof(struct data)); 	if(p[m].info!=NULL){printf("指针p[%d].info内存分配成功\n",m);}else {printf("指针p[%d].info内存分配失败\n",m);} 	} 	printf("-----------检测分配完成------------\n"); 	//--------数据输入-------- 	for(m=0;m<n;m++){ 		printf("正在输入第%d个学生的信息: ",m+1); 		printf("输入名字:\n"); 		scanf("%s",p[m].name); 		printf("输入学号:\n"); 		scanf("%d",&p[m].num); 		printf("输入性别M/F:\n"); 		scanf("%s",p[m].sex); 		printf("输入出生年月日:\n"); 		scanf("%d%d%d",&p[m].birthday->year,&p[m].birthday->month,&p[m].birthday->day); 		printf("输入电话号码:\n"); 		scanf("%ld",&p[m].info->tel); 		printf("输入地区号码:\n"); 		scanf("%d",&p[m].info->add); 	} 	//------输出内容 	printf("\n------现在打印所有信息------\n"); 	printf("\t姓名\t学号\t性别\t年月日\t\t电话号码\n"); 	for(i=0;i<n;i++){ 		printf("第%d个:",i+1); 		printf("%5s\t%d\t%s\t%d\\%d\\%d\t%d-%ld\n",(p+i)->name,(p+i)->num,(p+i)->sex,(p+i)->birthday->year,(p+i)->birthday->month,(p+i)->birthday->day,(p+i)->info->add,(p+i)->info->tel); 	} 	//------释放，清空 	for(m=0;m<n;m++){ 	free(p[m].birthday); 	free(p[m].info); 	p[m].info=NULL; 	p[m].birthday=NULL; 	} 	free(p); 	p=NULL; 	return 0; }     在第30行  if(p[m].birthday!=NULL){printf("指针p[%d].birthday内存分配成功\n",m);}else {printf("指针p[%d].info内存分配失败\n"),m;}  编译时出现 警告： 格式 ‘%d’ expects a matching ‘int’ argument [-Wformat]  这里的m不是int类型吗……gcc编译器在这里究竟发生了什么

稍微改进了一下 p=malloc(sizeof(struct student)); 改成 p=malloc(sizeof(struct student)*n);  不过运行时出现的结果还是一样……

gdb 'your program' core .... gdb> bt  然后找到你的函数代码行，分析

噢第59行漏了个. 	free(p[m].info); 不过这样还是出现同样错误

进程意外退出会在当前目录下产生‘core’文件或形如‘core.数字’的文件比如‘core.1234’ 使用命令 gdb 运行程序名 core或core.数字 进入gdb然后使用bt命令 可以查看进程意外退出前函数调用的堆栈，内容为从上到下列出对应从里层到外层的函数调用历史。 如果进程意外退出不产生core文件，参考“ulimit -c core文件最大块大小”命令


Question: 为什么用了getch（）函数，还是一闪而过

赞同楼上！！！

引用 2 楼 max_min_ 的回复: scanf("%d",&pause); getchar(); //这里用getchar的话，会吃掉你上次scanf输入的回车符的，所以会认为你已经            //输入的一个字符，  getchar();// 在加一个的话，就是在等待输入了 //while(1); //很多方法的@ 赞同

如果，你想看到图形，在 closegraph();前面暂停。

while (1) {  if (kbhit()) getch(); else break; } getch();

system("pause"); 确定程序运行到了上句？

多用几个getch，可能有多余的换行符。


Question: 关于initgraph（）函数路径的问题

就是说TC是DOS下的东西，已经过时很久了，现在要用的话，只有通过虚拟机来安装DOS系统。  引用 2 楼 snailagg 的回复:一下子懵了，新手，能再仔细点指导下吗。

一下子懵了，新手，能再仔细点指导下吗。

1、在Windows下安装DOS6.22虚拟机； 2、在DOS下安装Turbo C 2.0； 3、用TC编译运行你的程序。  引用 楼主 snailagg 的回复:我用的是绿色版tc ，把它放在E盘当前目录下，运行 #include<graphics.h> int main() {    int gdriver,gmode;    gdriver=DETECT ;    initgraph(&gdriver,&gmode,"E:\\TC");    line(100,100,200,200);    getch();    closegraph();    return 0;      } 提示initgraph，line（）等函数都没有定义， 这个路径怎么设置好。


Question: c语言问题

引用 2 楼 buyong 的回复:十进制负数转成2进制也是负数。 所以直接把这两个数相加，结果转为二进制输出。把问题简单化，++

可以用位操作符<< 和 >>来达到二进制输出 #include <stdio.h>  typedef struct  { 	int Int1; 	int Int2; 	int IntAdd; } mInt;  void outPrintf(int a) { 	int rMove = 0x01; //移位后与整数位与得到对应二进制位的数 	int k = 8;//这是二进制的位数 	for (k = k-1;k>=0 ;k-- ) 	{ 		printf("%01x",(a&(rMove<<k)) && 1); 	} 	printf("\n"); }  int main(int argc, char *argv[]) {	 	mInt inInt; 	printf("请输入第一个整数"); 	scanf("%d",&inInt.Int1); 	printf("请输入第二个整数"); 	scanf("%d",&inInt.Int2); 	inInt.IntAdd = inInt.Int1 + inInt.Int2; 	printf("第一个整数的二进制是\t"); 	outPrintf(inInt.Int1); 	printf("第二个整数的二进制是\t"); 	outPrintf(inInt.Int2); 	printf("两个整数和的二进制是\t"); 	outPrintf(inInt.IntAdd);  	 	return 0; }

十进制负数转成2进制也是负数。 所以直接把这两个数相加，结果转为二进制输出。

/2   %2   ，二进制放到数组中，做+法和进位处理。

仅供参考#include <stdio.h> #include <stdlib.h> #include <string.h> #include <locale.h> int main() {     int i,v;     char bs[33];     char b[33];     char hs[9];     char h[9];     char s[4];     char *e;  // 十进制整数转二进制串；     i=1024;     ltoa(i,b,2);     sprintf(bs,"%032s",b);     printf("i=%d,bs=%s\n",i,bs); // 十进制整数转十六进制串；     i=1024;     ltoa(i,h,16);     sprintf(hs,"%08s",h);     printf("i=%d,hs=%s\n",i,hs); // 十六进制字符串转成十进制数     strcpy(hs,"00000400");     sscanf(hs,"%x",&i);     printf("hs=%s,i=%d\n",hs,i); // 二进制字符串转化为十六进制字符串；     strcpy(bs,"00000000000000000000010000000000");     i=strtol(bs,&e,2);     ltoa(i,h,16);     sprintf(hs,"%08s",h);     printf("bs=%s,hs=%s\n",bs,hs); // 二进制字符串转化为十进制数；     strcpy(bs,"00000000000000000000010000000000");     i=strtol(bs,&e,2);     printf("bs=%s,i=%d\n",bs,i); // 十六进制字符串转成二进制串     strcpy(hs,"00000400");     sscanf(hs,"%x",&i);     ltoa(i,b,2);     sprintf(bs,"%032s",b);     printf("hs=%s,bs=%s\n",hs,bs); // ASC\GBK字符串转十六进制串     strcpy(s,"a汉");     i=0;     while (1) {         if (0==s[i]) break;         sprintf(hs+i*2,"%02X",(unsigned char)s[i]);         i++;     }     setlocale(LC_ALL,"chs");     printf("s=%s,hs=%s\n",s,hs); // 十六进制字符串转成汉字（GBK）及字符(ASC)     strcpy(hs,"61BABA");     i=0;     while (1) {         if (1!=sscanf(hs+i*2,"%2x",&v)) break;         s[i]=(char)v;         i++;     }     s[i]=0;     printf("hs=%s,s=%s\n",hs,s);      return 0;  } //i=1024,bs=00000000000000000000010000000000 //i=1024,hs=00000400 //hs=00000400,i=1024 //bs=00000000000000000000010000000000,hs=00000400 //bs=00000000000000000000010000000000,i=1024 //hs=00000400,bs=00000000000000000000010000000000 //s=a汉,hs=61BABA //hs=61BABA,s=a汉


Question: 求看下我打的程序，提交时wrong answer，求AC。。。

The average score of course 1 is:72.25

这个也是错误的。。。

有一个空行打漏了，，我填上去以后也是错误的。。。 这个错误请忽略。。。


Question: 16进制用int 保存 怎么保存？

电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……

引用 2 楼 turingo 的回复:进制的问题，以0x开头的是16进制数，参考：  #include "iostream" using namespace std;   typedef unsigned long ULONG;    int main() {     char* l_cpTemp = "0x12345678";      ULONG u = strtoul(l_cpTemp, 0, 16);       cout<<u<<endl;       return 0; }   [quote=引用 楼主 aaadddzxc 的回复:] 0x0f  怎么保存下来？ 0x0f 字符串读取出来后，atoi转换后 保存到int 里面  我打印后 int %X 是0 为什么？[/quote] +1

atoi默认只转10进制遇到非数字的则退出，所以Ox0F才会返回0， 使用strtol 可以按进制转换

atoi转的是int吧！需要额外处理的！

进制只是一种表现形式，实际都是以二进制存储的。

楼主要保存"0x0f"？ 它整体不是一个16进制表示 因此没法直接转换成int的

。int。 好像没有x 4位表示不了它啊。。。。。。 楼主 直接字符串吧

整数就是整数，没什么几进制的，几进制只是表达形式，存储层面都是二进制

进制的问题，以0x开头的是16进制数，参考：  #include "iostream" using namespace std;   typedef unsigned long ULONG;    int main() {     char* l_cpTemp = "0x12345678";      ULONG u = strtoul(l_cpTemp, 0, 16);       cout<<u<<endl;       return 0; }  引用 楼主 aaadddzxc 的回复:0x0f  怎么保存下来？ 0x0f 字符串读取出来后，atoi转换后 保存到int 里面  我打印后 int %X 是0 为什么？

atoi只能转10进制的字串吧


Question: 关于龙格库塔法

您 做过lorenz系统的分岔图吗？？

这个太深奥了


Question: 看了C语言的书，接下来看什么？

下面内容是我之前看到的一位程序员的建议（不记得在哪里看到的了），分享给你，希望对你有帮助。  另，欢迎大家对这个路径图进一步完善和补充。  学习路径图  1、C语言-数据结构-编译  2、C语言-数据结构-汇编-计算机组成与体系结构  3、C语言-数据结构-面向对象程序设计-数据库-网络

看完C != 掌握C  还需要项目实践。

写小程序了连连了

看看数据结构


Question: vc++6.0不可以跟踪静态变量的值吗？

跟踪静态变量所在内存地址处的值（必要时指定类型）即可。 Viewing the Value of a Variable or Contents of a Register Home Page (Debugger) |  Overview |  How Do I... Topics   What do you want to do? View the value of a variable or expression or the contents of a register  View the value of a variable using QuickWatch   View a the value of a variable or expression or the contents of a register in the Watch window   View type information for a variable in the Watch window  View a variable in the Variables window   View type information for a variable in the Variables window   Display meaningful values for your custom data type?  To view the value of a variable or expression or contents of a register   Wait for the debugger to stop at a breakpoint. – or –  Click Break on the Debug menu to halt the debugger.  On the Debug menu, click QuickWatch.   Type or paste the variable or register name or an expression into the Expression text box, and click Recalculate.   Click Close.  Tip   The Expression drop-down list box contains the most recently used QuickWatch expressions.  To view the value of a variable using QuickWatch   When the debugger is stopped at a breakpoint, switch to a source window, and click the right mouse button on a variable (Var, for example).   On the shortcut menu, click QuickWatch Var.   Click Close.  To view the value of a variable or expression or the contents of a register in the Watch window   Start debugging, and pause the debugger in break mode (program is waiting for user input after completing a debugging command).    On the View menu, click Debug Windows, then click Watch.   Select a tab for the variable or expression.   Type, paste, or drag the variable or register name or an expression into the Name column on the tab. Press ENTER (if typing).   The Watch window evaluates the variable or expression immediately and displays the value or an error message.  If you add an array or object variable to the Watch window, plus sign (+) or minus sign (–) boxes appear in the Name column. Use these boxes to expand or collapse your view of the variable described in Spreadsheet Fields.  Change the Watch window display format (to display Unicode characters, for example) using formatting symbols, described in Symbols for Watch Variables.  To view type information for a variable in the Watch window   In the Watch window, select the line containing the variable whose type you want to see.   On the View menu, click Properties.  To view a variable in the Variables window   Start debugging, and pause the debugger in break mode (program is waiting for user input after completing a debugging command).    On the View menu, click Debug Windows, then click Variables.   Click the Auto tab, Locals tab, or This tab, according to the type of variables you want to see.  To view type information for a variable in the Variables window   In the Variables window, click the Auto tab, Locals tab, or This tab.   Select the line containing the variable whose type you want to see. On the View menu, click Properties.  To display meaningful values for a custom datatype  The file autoexp.dat controls how the debugger displays data types in windows, Quickwatch, and DataTips. You can modify this file to add meaningful displays for your own datatypes. For details, see the autoexp.dat file itself (located in the /bin directory).

好像只有设置临时变量来查看值是比较可行的。

http://bbs.csdn.net/topics/330181032  额。 这个帖子也是这个。 但是没有好的结果

我的居然也不可以， 那就设置一个临时变量存储b的值，观察临时变量吧 static int i=1;i++ ;int temp=i;//跟踪temp

To break when the value at a specified memory address changes   From the Edit menu, click Breakpoints.   Click the Data tab of the Breakpoints dialog box.   In the Expression text box, type the memory address for the byte.  For a word or doubleword memory address, enclose the address in parentheses, and precede it with a cast operator. For example, WO(21406036) for the word at memory location 21406036. Use the cast operator BY for a byte (optional), WO for a word, or DW for a doubleword. (The debugger interprets all integer constants as decimal unless they begin with zero (0) for octal or zero and x (0x) for hexadecimal.)  In the Number Of Elements text box, type the number of bytes, words, or doublewords to monitor. If you used the BY operator in the Expression field, specify the number of bytes. If you used WO, specify the number of words. If you used DW, specify the number of doublewords.    Click OK to set the breakpoint.


Question: 求大神帮忙是缩短下程序     谢谢  在线等

不能编译，给你个参考吧，忘采纳。 UCHAR a[16] = {0,0,0,0,0,0,4,0,0,0,0,3,0,2,1,0 }  UCHAR OnCase(UCHAR ch1,UCHAR ch2,UCHAR key) { 	if(p1 == ch1*16+ch2) 		return key = a[ch1]+a[ch2]*10;	 	else  		return 0; }  void deal(uchar P1,uchar char2) { 	uchar temp = P1,key; 	if( (temp&0xf0) != 0xf0 ) 	{ 		delayms(10); 		if( (temp&0xf0) != 0xf0 ) 		{ 			OnCase(e,ch2,key);//e开头 			OnCase(d,ch2,key);//d开头 			OnCase(b,ch2,key);//b开头 			OnCase(7,ch2,key);//7开头 			 			temp &= 0xf0; 			while(temp!=0xf0) 			{ 				temp=P1; 				temp &= 0xf0; 			} 			display(key); 		} 	} }  void keyscan() { 	deal(0x0e,0x0e);//e结尾 	deal(0x0d,0x0d);//d结尾 	deal(0x0b,0x0b);//b结尾 	deal(0x07,0x07);//7结尾 }

可以分几个函数出来的！多加几个接口！注意代码复用下就好！

引用 11 楼 tanling_zero 的回复:[quote=引用 10 楼 u012887645 的回复:] [quote=引用 9 楼 tanling_zero 的回复:] // Test.cpp : 定义控制台应用程序的入口点。 //  #include "stdafx.h" #include <iostream> using namespace std;    void display( char key ) { 	cout<<"key = "<<key<<endl;  }  void delayms( int a ){}   struct _strKey {  	int P; 	int case_value[4];  }g_key[] = { 0xfe , 0xee , 0xde , 0xbe , 0x7e ,              0xfd , 0xed , 0xdd , 0xbe , 0x7e , 			 0xfb , 0xeb , 0xdb , 0xbb , 0x7b , 			 0xf7 , 0xe7 , 0xd7 , 0xb7 , 0x77  };  int getKey() { 	 	int key = 0 ; 	for ( int n = 0 ; n < 4; n++ ) 	{ 		int P1 = g_key[n].P; 		char temp = P1 & 0xf0;  		delayms(10); 		if(temp != 0xf0) 		{ 			for (int i = 0 ; i < 4 ; i++ ) 			{ 				if (temp == g_key[n].case_value[i]) 				{ 					key = ( n + 1 )*10 + i + 1;  					while(temp!=0xf0) 					{ 						temp=P1; 						temp=temp&0xf0; 					}  					return key; 				} 			} 		} 	}  	return 0; }  void  keyscan() { 	int key = getKey(); 	display(key);  }  int _tmain(int argc, _TCHAR* argv[]) {  	keyscan();  	return 0; }    不知道是不是你要的，细节自己修改，给点下载分？   这个太深入了   表示不怎么懂[/quote]  那自己先把重复的代码只写一遍，然后上面写个for，再考虑把数据变成数组，然后循环就可以了 [/quote]  能不能加个qq

引用 13 楼 u012887645 的回复:[quote=引用 12 楼 zhao4zhong1 的回复:] [quote=引用 8 楼 u012887645 的回复:] [quote=引用 7 楼 zhao4zhong1 的回复:] uchar trans(uchar t) {     static uchar s[16]={0xee,0xde,0xbe,0x7e,0xed,0xdd,0xbe,0x7e,0xeb,0xdb,0xbb,0x7b,0xe7,0xd7,0xb7,0x77};     static uchar d[16]={  11,  12,  13,  14,  21,  22,  23,  24,  31,  32,  33,  34,  41,  42,  43,  44};     int i;      for (i=0;i<16;i++) if (s[i]==t) return d[i];     printf("oops!\n");     return 0; } void  keyscan() {     uchar temp,key;     uchar p4[4]={0xfe,0xfd,0xfb,0xf7};     int j;      for (j=0;j<4;j++) {         P1=p4[j];         temp=P1;         temp=temp&0xf0;         if(temp!=0xf0) {             delayms(10);             temp=P1;             temp=temp&0xf0;             if(temp!=0xf0) {                 temp=P1;                 key=trans(temp);                 while(temp!=0xf0) {                     temp=P1;                     temp=temp&0xf0;                 }                 display(key);             }         }     } }    printf("oops!\n");这是什么[/quote] 意外遇到temp的值不在意料之中的16个值时，输出oops!提醒程序员，并返回0.  oops int. 表示惊讶, 狼狈时所发的喊声  [/quote]   括号内的不要行不行[/quote]   能不能加个qq：568519177

引用 12 楼 zhao4zhong1 的回复:[quote=引用 8 楼 u012887645 的回复:] [quote=引用 7 楼 zhao4zhong1 的回复:] uchar trans(uchar t) {     static uchar s[16]={0xee,0xde,0xbe,0x7e,0xed,0xdd,0xbe,0x7e,0xeb,0xdb,0xbb,0x7b,0xe7,0xd7,0xb7,0x77};     static uchar d[16]={  11,  12,  13,  14,  21,  22,  23,  24,  31,  32,  33,  34,  41,  42,  43,  44};     int i;      for (i=0;i<16;i++) if (s[i]==t) return d[i];     printf("oops!\n");     return 0; } void  keyscan() {     uchar temp,key;     uchar p4[4]={0xfe,0xfd,0xfb,0xf7};     int j;      for (j=0;j<4;j++) {         P1=p4[j];         temp=P1;         temp=temp&0xf0;         if(temp!=0xf0) {             delayms(10);             temp=P1;             temp=temp&0xf0;             if(temp!=0xf0) {                 temp=P1;                 key=trans(temp);                 while(temp!=0xf0) {                     temp=P1;                     temp=temp&0xf0;                 }                 display(key);             }         }     } }    printf("oops!\n");这是什么[/quote] 意外遇到temp的值不在意料之中的16个值时，输出oops!提醒程序员，并返回0.  oops int. 表示惊讶, 狼狈时所发的喊声  [/quote]   括号内的不要行不行

引用 8 楼 u012887645 的回复:[quote=引用 7 楼 zhao4zhong1 的回复:] uchar trans(uchar t) {     static uchar s[16]={0xee,0xde,0xbe,0x7e,0xed,0xdd,0xbe,0x7e,0xeb,0xdb,0xbb,0x7b,0xe7,0xd7,0xb7,0x77};     static uchar d[16]={  11,  12,  13,  14,  21,  22,  23,  24,  31,  32,  33,  34,  41,  42,  43,  44};     int i;      for (i=0;i<16;i++) if (s[i]==t) return d[i];     printf("oops!\n");     return 0; } void  keyscan() {     uchar temp,key;     uchar p4[4]={0xfe,0xfd,0xfb,0xf7};     int j;      for (j=0;j<4;j++) {         P1=p4[j];         temp=P1;         temp=temp&0xf0;         if(temp!=0xf0) {             delayms(10);             temp=P1;             temp=temp&0xf0;             if(temp!=0xf0) {                 temp=P1;                 key=trans(temp);                 while(temp!=0xf0) {                     temp=P1;                     temp=temp&0xf0;                 }                 display(key);             }         }     } }    printf("oops!\n");这是什么[/quote] 意外遇到temp的值不在意料之中的16个值时，输出oops!提醒程序员，并返回0.  oops int. 表示惊讶, 狼狈时所发的喊声

引用 10 楼 u012887645 的回复:[quote=引用 9 楼 tanling_zero 的回复:] // Test.cpp : 定义控制台应用程序的入口点。 //  #include "stdafx.h" #include <iostream> using namespace std;   void display( char key ) { 	cout<<"key = "<<key<<endl;  }  void delayms( int a ){}   struct _strKey {  	int P; 	int case_value[4];  }g_key[] = { 0xfe , 0xee , 0xde , 0xbe , 0x7e ,              0xfd , 0xed , 0xdd , 0xbe , 0x7e , 			 0xfb , 0xeb , 0xdb , 0xbb , 0x7b , 			 0xf7 , 0xe7 , 0xd7 , 0xb7 , 0x77  };  int getKey() { 	 	int key = 0 ; 	for ( int n = 0 ; n < 4; n++ ) 	{ 		int P1 = g_key[n].P; 		char temp = P1 & 0xf0;  		delayms(10); 		if(temp != 0xf0) 		{ 			for (int i = 0 ; i < 4 ; i++ ) 			{ 				if (temp == g_key[n].case_value[i]) 				{ 					key = ( n + 1 )*10 + i + 1;  					while(temp!=0xf0) 					{ 						temp=P1; 						temp=temp&0xf0; 					}  					return key; 				} 			} 		} 	}  	return 0; }  void  keyscan() { 	int key = getKey(); 	display(key);  }  int _tmain(int argc, _TCHAR* argv[]) {  	keyscan();  	return 0; }    不知道是不是你要的，细节自己修改，给点下载分？   这个太深入了   表示不怎么懂[/quote]  那自己先把重复的代码只写一遍，然后上面写个for，再考虑把数据变成数组，然后循环就可以了

引用 9 楼 tanling_zero 的回复:// Test.cpp : 定义控制台应用程序的入口点。 //  #include "stdafx.h" #include <iostream> using namespace std;   void display( char key ) { 	cout<<"key = "<<key<<endl;  }  void delayms( int a ){}   struct _strKey {  	int P; 	int case_value[4];  }g_key[] = { 0xfe , 0xee , 0xde , 0xbe , 0x7e ,              0xfd , 0xed , 0xdd , 0xbe , 0x7e , 			 0xfb , 0xeb , 0xdb , 0xbb , 0x7b , 			 0xf7 , 0xe7 , 0xd7 , 0xb7 , 0x77  };  int getKey() { 	 	int key = 0 ; 	for ( int n = 0 ; n < 4; n++ ) 	{ 		int P1 = g_key[n].P; 		char temp = P1 & 0xf0;  		delayms(10); 		if(temp != 0xf0) 		{ 			for (int i = 0 ; i < 4 ; i++ ) 			{ 				if (temp == g_key[n].case_value[i]) 				{ 					key = ( n + 1 )*10 + i + 1;  					while(temp!=0xf0) 					{ 						temp=P1; 						temp=temp&0xf0; 					}  					return key; 				} 			} 		} 	}  	return 0; }  void  keyscan() { 	int key = getKey(); 	display(key);  }  int _tmain(int argc, _TCHAR* argv[]) {  	keyscan();  	return 0; }    不知道是不是你要的，细节自己修改，给点下载分？   这个太深入了   表示不怎么懂

引用 7 楼 zhao4zhong1 的回复:uchar trans(uchar t) {     static uchar s[16]={0xee,0xde,0xbe,0x7e,0xed,0xdd,0xbe,0x7e,0xeb,0xdb,0xbb,0x7b,0xe7,0xd7,0xb7,0x77};     static uchar d[16]={  11,  12,  13,  14,  21,  22,  23,  24,  31,  32,  33,  34,  41,  42,  43,  44};     int i;      for (i=0;i<16;i++) if (s[i]==t) return d[i];     printf("oops!\n");     return 0; } void  keyscan() {     uchar temp,key;     uchar p4[4]={0xfe,0xfd,0xfb,0xf7};     int j;      for (j=0;j<4;j++) {         P1=p4[j];         temp=P1;         temp=temp&0xf0;         if(temp!=0xf0) {             delayms(10);             temp=P1;             temp=temp&0xf0;             if(temp!=0xf0) {                 temp=P1;                 key=trans(temp);                 while(temp!=0xf0) {                     temp=P1;                     temp=temp&0xf0;                 }                 display(key);             }         }     } }    printf("oops!\n");这是什么

[quote=引用 5 楼 turingo 的回复:] 改用查表的方法。  怎么改  求教

改用查表的方法。  引用 楼主 u012887645 的回复:void  keyscan() { uchar temp,key; P1=0xfe; temp=P1; temp=temp&0xf0; if(temp!=0xf0) {   delayms(10);   temp=P1;   temp=temp&0xf0;   if(temp!=0xf0)   {    temp=P1;    switch(temp)    {    case 0xee:        key=11; 	   break;    case 0xde:       key=12; 	  break;    case 0xbe:       key=13; 	  break;    case 0x7e:       key=14; 	  break;    }    while(temp!=0xf0)    {     temp=P1; 	temp=temp&0xf0; 	} 	display(key); 	} 	}   P1=0xfd; temp=P1; temp=temp&0xf0; if(temp!=0xf0) {   delayms(10);   temp=P1;   temp=temp&0xf0;   if(temp!=0xf0)   {    temp=P1;    switch(temp)    {    case 0xed:        key=21; 	   break;    case 0xdd:       key=22; 	  break;    case 0xbe:       key=23; 	  break;    case 0x7e:       key=24; 	  break;    }    while(temp!=0xf0)    {     temp=P1; 	temp=temp&0xf0; 	} 	display(key); 	} 	}   P1=0xfb; temp=P1; temp=temp&0xf0; if(temp!=0xf0) {   delayms(10);   temp=P1;   temp=temp&0xf0;   if(temp!=0xf0)   {    temp=P1;    switch(temp)    {    case 0xeb:        key=31; 	   break;    case 0xdb:       key=32; 	  break;    case 0xbb:       key=33; 	  break;    case 0x7b:       key=34; 	  break;    }    while(temp!=0xf0)    {     temp=P1; 	temp=temp&0xf0; 	} 	display(key); 	} 	} 	P1=0xf7; temp=P1; temp=temp&0xf0; if(temp!=0xf0) {   delayms(10);   temp=P1;   temp=temp&0xf0;   if(temp!=0xf0)   {    temp=P1;    switch(temp)    {    case 0xe7:        key=41; 	   break;    case 0xd7:       key=42; 	  break;    case 0xb7:       key=43; 	  break;    case 0x77:       key=44; 	  break;    }    while(temp!=0xf0)    {     temp=P1; 	temp=temp&0xf0; 	} 	display(key); 	} 	} }

引用 3 楼 wusuopuBUPT 的回复:引用 1 楼 zhao4zhong1 的回复:在本人眼里，不超过1000行的代码都够短。赵老师好厉害。  能不能帮我改下

引用 1 楼 zhao4zhong1 的回复:在本人眼里，不超过1000行的代码都够短。  能不能帮我改短  用数组之类的

在本人眼里，不超过1000行的代码都够短。


Question: 数组作为函数参数的疑问

函数声明时： 有3种方法可以把数组当做函数参数： 1.直接传指针： void myFunction(int *param){ } 2.传带size的数组： void myFunction(int param[10]){ } 3.传不带size的数组： void myFunction(int param[]){ }  原理都是一样的，都是告诉编译器接受一个int 型的指针。  If you want to pass a single-dimension array as an argument in a function, you would have to declare function formal parameter in one of following three ways and all three declaration methods produce similar results because each tells the compiler that an integer pointer is going to be received  参考：http://www.tutorialspoint.com/cplusplus/cpp_passing_arrays_to_functions.htm  函数调用时： int param[10]; myFunction(param) 直接传递函数名（即数组地址）当做实参即可。

一维数组，传a,a[],&a[0]，或传指针。

引用 3 楼 u010334406 的回复:引用 1 楼 turingo 的回复:传如a即可，也就是数组的首地址。  [quote=引用 楼主 u010334406 的回复:] 在函数nzp的定义中，整型数组a作为函数nzp的参数时，分别定义int nzp(a[8])、int nzp(a[])、是不是都是正确的？意思是不是一样的？参数a[8]和a[]都表示数组的第一个元素的地址？ 还有个疑问，如果没声明数组a，是不是参数要写成我说的那两种形式呢？直接参数写a，程序如何知道是数组名还是变量呢？[/quote]函数形参定义成数组和指针，效果是一样的，通常直接定义成指针，调用时传入数组名和指针都是可以的

引用 1 楼 turingo 的回复:传如a即可，也就是数组的首地址。  引用 楼主 u010334406 的回复:在函数nzp的定义中，整型数组a作为函数nzp的参数时，分别定义int nzp(a[8])、int nzp(a[])、是不是都是正确的？意思是不是一样的？参数a[8]和a[]都表示数组的第一个元素的地址？ 还有个疑问，如果没声明数组a，是不是参数要写成我说的那两种形式呢？直接参数写a，程序如何知道是数组名还是变量呢？

竟然没分了竟然没分了竟然没分了，我要问问题啊，   int dc_3DesEncryption(unsigned int Lenght, unsigned char Index, unsigned char *Soure, unsigned char *ENC_Data)； 这个函数，在里面运行的时候，结果是对的。            int  redx; 	  unsigned int Lenght = 0x09; 	  unsigned char Index = 0x02; 	  unsigned char Soure[] = {0x71, 0x61, 0x51, 0x41, 0x31, 0x21, 0x11, 0x01}; 	  unsigned char ENC_Data[500];    	  redx = dc_3DesEncryption(Lenght, Index, Soure, ENC_Data);  但是当他运行完毕后，为什么ENC_Data里面没有值？