`
boz.lee
  • 浏览: 18644 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论
收藏列表
标题 标签 来源
小例子-uweb-11
</script>

<style type="text/css">
.important
{
font-weight:bold;
font-size:xx-large;
}
.blue
{
color:blue;
}
</style>
</head>
<body>
<frame>
<h1 class="blue">标题 1</h1>
<h2 class="blue">标题 2</h2>
<p class="blue">这是一个段落。</p>
<p>CLICK</p>
<br>
<button>CLICK</button>
<div id="sidebarmenu"></div>

</frame>
</body>
</html>
小例子-uweb-10
function setMenuJsonUrl()
			{
				getMenuByCode(menuJson, "operationLog").target += "?timeOffset=" + timeOffset;
				/*getMenuByCode(menuJson, "callLog").target += "?timeOffset=" + timeOffset + "&pageTag=callLogList";
				getMenuByCode(menuJson, "smsMgr").target += "?timeOffset=" + timeOffset+"&boxType=0";
				getMenuByCode(menuJson, "memberRightsTemplate").target += "?ajaxPage=success";
				getMenuByCode(menuJson, "excessWarning").target += "?timeOffset=" + timeOffset;*/
			}
			
			function getMenuByCode(menu, code)
			{
				if (menu.length) {
					for (var i=0; i < menu.length; i++) {
						var found = getMenuByCode(menu[i], code);
						if (found.menuCode == code) {
							return found;
						}
						found = getMenuByCode(menu[i].children, code);
						if (found.menuCode == code) {
							return found;
						}
					}
				} else if (menu.menuCode == code) {
					return menu;
				}
				
				return dummyMenu;
			}


			/////////////////////////
				})
			  }	//有的浏览器中, 这个}后面的,要去掉,不然报错下一行失败, 有的ie不报错, 需要在IE选项\高级\最后的"显示每个脚本错误的通知",显示
			 };

})(jQuery);



</script>
小例子-uweb-9
function buildMenu(menu, data) {
				var parent = menu.parent = $(
						'<ul class="menu" style="z-index:100012"></ul>').appendTo(
						menu.parent);
				var depth = menu.depth, len = data.length;
				parent.addClass('menu-depth' + depth);

				$.each(data, function(i, item) {
					menu.parent = parent;
					menu.depth = depth;
					menu.isFirst = (i === 0);
					menu.isLast = (i === (len - 1));
					buildMenuItem(menu, item);
				});
				return parent;
			}

			function buildMenuItem(menu, item) {
				//alert("befor:  "+menu.parent[0].outerHTML+"|||||"+menu.parent[0].innerHTML);
				var $item = $('<li class="menu-item"></li>').appendTo(menu.parent);
					//alert($item[0].innerHTML);
					//alert($item[0].outerHTML);
					//alert("after:  "+menu.parent[0].outerHTML+"|||||"+menu.parent[0].innerHTML + "%%%%%"+ $item[0].outerHTML+"|||||"+$item[0].innerHTML);
					
				var	target = item.target || ('#' + item.title.replace(/\s+/g, '-')); 
				var	$wrap = $('<div class="menu-item-wrap"></div>').appendTo($item); 
				var	$link = $('<a></a>').attr({'value' : target,'id' : menu.options.menuIDPrefix + item.menuCode}).text(item.title).appendTo($wrap);

				menu.depth !== 1 && !menu.isLast ? $item.addClass('menu-border')
						: undefined;
				menu.isFirst ? $item.addClass('menu-first') : undefined;
				menu.isLast ? $item.addClass('menu-last') : undefined;

				if (item.icon && item.icon.length) {
					$link.addClass('menu-icon menu-icon-' + item.icon);
				}

				var hasChildren = item.children && item.children.length;

				// handle children
				$link.data('depth', menu.depth);

				if (hasChildren) {
					$item.addClass('menu-more');
					menu.depth > 0 ? $item.append('<i class="menu-arrow"></i>')
							: undefined;

					menu.parent = $item;
					menu.depth += 1;
					buildMenu(menu, item.children);
				} else {
					$link.data('leaf', true);
				}
			}
小例子-uweb-8
function getCurrentInitMenu() {
				var menuInfo = null;
				for (var i = 0; i < initMenus.length; ++i) {
					menuInfo = initMenus[i];
					//alert(menuInfo.action);
					//alert(i+"  " + window.location.href + "--------------  " + menuInfo.action);
					if (window.location.href.indexOf(menuInfo.action) != -1) {			//ie浏览器本html的路径和homePage比较.  i为0就满足
						//alert(i);
						return menuInfo;
					}
				}
			}
			
			var currentMenu = getCurrentInitMenu();	//
				//alert(currentMenu);		//homepage所在的initMenus节点
			

			menuJson = menuJson.children;	//menuJson下的child节点中的内容,几层
			var timeOffset = new Date().getTimezoneOffset();
			var dummyMenu = new Object();
			
			setMenuJsonUrl();
	
			var mainMenu = new SidebarMenu("#sidebarmenu", {
				data : menuJson,
				baseURL : "/portal",
				currentMenuId: currentMenu.menuId,
				onMenuClicked : function(menu, link, e, isInTargetList) {
					var targetUrl = $(link).attr("value");

					//加载iframe
					$('#mainiframe',window.parent.document).attr('src', targetUrl);
					return true;
				}
			});
小例子-uweb-7
var initMenus = [ {
				action : "homePage",
				rightAction : "homePageRight.action",
				menuId : "#menu_homePage"
			}, {
				action : "queryImpuList",
				rightAction : "queryImpuListRight.action",
				menuId : "#menu_impu"
			}, {
				action : "toWakeUpMgrPage",
				rightAction : "toWakeUpMgrPageRight.action",
				menuId : "#menu_wakeUp"
			}, {
				action : "showCorpStrutAll",
				rightAction : "showCorpStrut.action",
				menuId : "#menu_corpStrut"
			}, {
				action : "queryAlarmListAll",
				rightAction : "queryAlarmList.action",
				menuId : "#menu_excessWarning"
			}, {
				action : "toSetImpuRithtsAll",
				rightAction : "toSetImpuRithts.action",
				menuId : "#menu_impuRightsService"
			}, {
				action : "toDNDBusinessAll",
				rightAction : "toDNDBusiness.action",
				menuId : "#menu_dnd"
			}];
小例子-uweb-6
{
					  							"children" : [],
					  							"icon" : "",
					  							"menuCode" : "corpGroup",
					  							"parent" : "basicInfo",
					  							"target" : "centrexGroupMgr.action",
					  							"targetList" : [ "centrexSubGroupMgr.action",
					  									"toCxGrp.action", "updateCxGrp.action",
					  									"queryOcxPfxList.action",
					  									"toOcxPfx.action", "updateOcxPfx.action",
					  									"deleteOcxPfx.action",
					  									"queryIcxPfxList.action",
					  									"toIcxPfx.action", "updateIcxPfx.action",
					  									"deleteIcxPfx.action",
					  									"queryCxOcrList.action", "toCxOcr.action",
					  									"updateCxOcr.action", "deleteCxOcr.action",
					  									"toCxSubGrp.action",
					  									"toSearchPhonePage.action",
					  									"updateCxSubGrp.action",
					  									"deleteCxSubGrp.action",
					  									"queryCxSubGrpMemberList.action",
					  									"queryImpuList.action",
					  									"queryCxSubGrpList.action",
					  									"updateSubGroupMember.action" ],
					  							"title" : "企业群组"
					  						}, {
					  							"children" : [],
					  							"icon" : "",
					  							"menuCode" : "corpInfo",
					  							"parent" : "basicInfo",
					  							"target" : "toCorpInfo.action",
					  							"targetList" : [ "updateCorpInfo.action" ],
					  							"title" : "企业信息"
					  						}, {
					  							"children" : [],
					  							"icon" : "",
					  							"menuCode" : "signService",
					  							"parent" : "basicInfo",
					  							"target" : "toCorpService.action",
					  							"targetList" : [],
					  							"title" : "签约业务"
					  						} ],
					  				"icon" : "basicInfo",
					  				"menuCode" : "basicInfo",
					  				"parent" : "rootMenu",
					  				"target" : "#1",
					  				"targetList" : [],
					  				"title" : "基本信息"
									}],
					  	"icon" : "",
					  	"menuCode" : "rootMenu",
					  	"parent" : "",
					  	"target" : "#58",
					  	"targetList" : [],
					  	"title" : ""
					  }
小例子-uweb-5
var menuJson = {
					"children" : [
					  			{
					  				"children" : [],
					  				"icon" : "homepage",
					  				"menuCode" : "homePage",
					  				"parent" : "rootMenu",
					  				"target" : "homePageRight.action",
					  				"targetList" : [ "search.action" ],
					  				"title" : "首页"
					  			},
					  			{
					  				"children" : [
					  						{
					  							"children" : [],
					  							"icon" : "",
					  							"menuCode" : "corpEab",
					  							"parent" : "basicInfo",
					  							"target" : "queryUcEmployeeList.action",
					  							"targetList" : [ "toUCEmployeeInfo.action",
					  									"toImportPopWinPage.action",
					  									"toImportFormPage.action",
					  									"toSearchPhonePage.action",
					  									"checkUcAccount.action",
					  									"searchUcAccountList.action",
					  									"deleteUcEmployee.action",
					  									"downloadTemplate.action",
					  									"importUcEmployee.action",
					  									"updateEabFieldInfo.action",
					  									"downLoadErrorUcEmployee.action",
					  									"exportEabCheck.action",
					  									"exportEabList.action",
					  									"getProgressBar.action",
					  									"updateUcEmployee.action",
					  									"queryImpuByPhoneNum.action" ],
					  							"title" : "企业成员"
					  						},
					  						{
					  							"children" : [],
					  							"icon" : "",
					  							"menuCode" : "corpStrut",
					  							"parent" : "basicInfo",
					  							"target" : "showCorpStrut.action",
					  							"targetList" : [ "toDeptInfo.action",
					  									"updateDeptInfo.action",
					  									"deleteDeptInfo.action",
					  									"showCorpStrutAll.action" ],
					  							"title" : "组织架构"
					  						},
小例子-uweb-4
SidebarMenu.prototype.open = function(link, openSubmenu) {
				openSubmenu = openSubmenu === undefined ? true : openSubmenu;

				var self = this, $link = $(link), $submenu = openSubmenu ? findFirstSubmenu($link
						.parent().parent())
						: null, $$link = $submenu && $submenu.length ? $submenu.eq(0)
						: $(link), $parent = $$link.parent().parent(), isLeaf = $$link
						.data('leaf') || false, depth = $$link.data('depth');

				self.handles[depth].call(this, $parent, isLeaf);

				return $$link;
			};
			
			/////////////////////////
小例子-uweb-3
///////////////////////////////
			SidebarMenu.prototype._handleMenu0 = function($parent, isLeaf) {
				var opts = this.options;

				closeMenu($parent.siblings(this.options.openSelector), opts);
				openMenu($parent, opts.openClassName);
			};

			SidebarMenu.prototype._handleMenu1 = function($parent, isLeaf) {
				var opts = this.options;

				this._handleMenu0($parent.parent().parent(), false);

				$parent.siblings(opts.openSelector).removeClass(opts.openClassName)
						.find(opts.openSelector).removeClass(opts.openClassName);
				$parent.siblings(opts.highlightSelector).removeClass(
						opts.highlightClassName).find(opts.openSelector).removeClass(
						opts.openClassName);

				$parent.addClass(isLeaf ? opts.openClassName : opts.highlightClassName);
			};

			SidebarMenu.prototype._handleMenu2 = function($parent, isLeaf) {
				var opts = this.options;

				this._handleMenu1($parent.parent().parent(), false);

				$parent.addClass(opts.openClassName).siblings(opts.openSelector)
						.removeClass(opts.openClassName);
			};

			/**
			 * 根据菜单中的a标签展开子菜单
			 * 
			 * 注意:不会触发onMenuClicked事件;必须通过$link.trigger('click')等方式才能触发
			 * 
			 * @param {String|Object}
			 *            link 菜单中的a标签
			 * @param {Boolean}
			 *            [openSubmenu = true] 是否自动查找最终子节点并使用
			 * @return {Object} 最终展开的子节点
			 */
小例子-uweb-2
//SidebarMenu 类定义
			function SidebarMenu(container, options) {
				var self = this, openClassName = self.openClassName = 'menu-open';
				var opts = this.options = $.extend({
				data : [],
				currentMenuId : null, // 默认选中菜单
				menuIDPrefix : 'menu_', // 菜单ID前缀
				openSelector : '.menu-open',
				openClassName : 'menu-open',
				highlightSelector : '.menu-highlight',
				highlightClassName : 'menu-highlight',
				onMenuClicked : function(menu, $link, e) {
					e.preventDefault();
					return false;
				}
			}, options);
		
				this.$container = $(container);
				this.parent = this.$container;
				this.depth = 0;

				this.root = buildMenu(this, opts.data);

				this.handles = [ this._handleMenu0, this._handleMenu1,
						this._handleMenu2 ];

				// 手风琴切换,二级菜单切换,三级菜单切换
				this.root.bind('click', 'a', function(e) {	
					var $this = $(this), isLeaf = $this.data('leaf') || false, $link;

					// 如果用户点击的不是最终的子节点,那么就在代码里面自动展开某个子菜单
					// 但是,是否触发事件呢?
					$link = self.open(this, !isLeaf);
					//$link = this.open(this, !isLeaf);
					if (self.options.onMenuClicked) {
						return self.options.onMenuClicked.call(self, self, $link, e);	//第一个self是要去替换的对象,后面是参数, 传入onMenuClicked
					}

					return false;
				});

				opts.currentMenuId && this.open(opts.currentMenuId);  // open 不支持对象和方法
				
			}
小例子-uweb-1
<!DOCTYPE html>
<html>
<head>
<script src="jquery-1.8.3.min.js"></script><!--此处不能省略后面的</script>,而用<..../>. 下面一行也不能省略-->
<script src="auth.js"></script>
<script type="text/javascript">

var component={};

//$(document).ready(function(){ //相当于$(function(){			//这个是首先先加载的
	$(function(){
		
		component.authPanel.ready();	//要和命名空间的方法分开,不能在$(function(){中,直接用component.authPanel, ready。等声明,可以调用
		$.foo = function() {    //放这里也行
			alert("foo.");   
		};

		//这里定义的非$格式函数,只能在这个{}内使用,如果想在ready或者外面使用, 需要全局或者ready内定义.
		function foo4() {
			alert("foo4.");  
		}
		foo4();
	});	

	function foo2() {
			alert("foo2.");  
	}

         (function($){	
	component.authPanel = {
	  ready:function(){
		$("button").click(function()
		{
			$("h1,h2,p").removeClass("blue");
			$.foo();
			foo2();
			foo3();
			foo4();//失败
			
			function foo3() {
			alert("foo3.");  
			}
		
			function openMenu($parent, className) {
				var $submenu = $parent.children('.menu-depth1');
				if (!$parent.hasClass(className)) {
					$submenu.length ? $submenu.slideDown({
						queue : false
					}) : undefined;
					$parent.addClass(className);
				}

				$parent.find(className).removeClass(className); // cleanup children

				return $parent;
			}

			function closeMenu($parent, opts) {
				if (!$parent.length) {
					return;
				}
				var $submenu = $parent.children('.menu-depth1');
				$submenu.length ? $submenu.slideUp({
					queue : false
				}) : undefined;
				$parent.removeClass(opts.openClassName).find(opts.openSelector)
						.removeClass(opts.openClassName);
				$parent.find(opts.highlightSelector).removeClass(
						opts.highlightClassName);
			}
		
			function findFirstSubmenu($parent) {
				var $firstSubMenu = $parent.children('.menu').children('.menu-first');

				if ($firstSubMenu.length && $firstSubMenu.is('.menu-more')) {
					$firstSubMenu = $firstSubMenu.children('.menu').children(
							'.menu-first');
				}

				return $firstSubMenu.find('a');
			}
边界问题学习
#include<stdio.h>
#include<stdlib.h>
#include<MEMORY.H>
#include<ASSERT.H>

#define  ML 20
//#define  ML 2147483647
char xs[ML];
/* 功能:input中有长度为length的数据,将它复制到稀疏存储中,起始位置
 *    为position。
 * 输入:position:写入数据的起始位置,范围0到(4G-1)
 *    length:数据长度,范围1到10M
 *    input:输入数据,内存由调用者负责申请和释放
 * 输出:无
 * 返回:成功返回0
 *    input为空指针、访问越界、length为0或者内部异常,返回-1
 */
int set_data(unsigned int position, unsigned int length, const void *input)
{
    /* 请实现 */
	 if(!input||length==0)
		return -1;
	 memset(xs,0,sizeof(xs));
	 memcpy(xs+position,input,length);
		return 0;
}

/* 功能:从稀疏存储中读取一段数据,起始位置为position,长度为length,
 *    将它复制到output中。
 * 输入:position:读取数据的起始位置,范围0到(4G-1)
 *    length:数据长度,范围1到10M 
 * 输出:output:输出数据,内存由调用者负责申请和释放
 * 返回:成功返回0
 *    output为空指针、访问越界、length为0或内部异常,返回-1
 */
int get_data(unsigned int position, unsigned int length, void *output)
{
    /* 请实现 */
	 if(!output||length==0)
		return -1;
	 memset(output,0,sizeof(output));
	 memcpy(output,xs+position,length);
		return 0;
}

int main()
{
	const char input[] = {1,2,3,4,5,6,7,8,9,10};
    char output[10];
    const char expect[] = {6,7,8,9,10,0,0,0,0,0};
	assert(0 == set_data(0, sizeof(input), input));
    assert(0 == get_data(5, sizeof(output), output));
    assert(0 == memcmp(output, expect, sizeof output));
	printf("assert all are okey\n");
	return 0;
}
count算法问题
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;



string str("");;
void myfunction (string i) {
	cout << " | " << i;
	str += i;
}

void myfunctionInt (int i) {
	cout << " | " << i;
	//str += i;
}


int main()
{
	char sentence[]="This is a sentence with 7 tokens,bood with a";	//数据源
	char senCpy[200];	//副本
	strcpy(senCpy,sentence); 
	vector<string> vs;	//分割段落
	int comVal[] = {0}; //数组
	int i = 0;		//数组下标

	//进行第一次分割,把句子分开成各个段,并放入vector中
	char *p = strtok(sentence," ,");
	while(p!=NULL)
	{
		//cout<<p<<endl; 
		
		p=strtok(NULL," ,"); 
		if(p!=NULL)
		{
			vs.push_back(p);
			cout<<"vector p: "<<p<<endl;
		}
	}


	cout<<"//////////////////////////////////////////////////////////////////////////"<<endl;
	//进行第二次分割,然后对上次的分割结果进行count技术,依次匹配各个单词出现次数,并计入一个数组comVal
	char *t = strtok(senCpy," ,");
 	while(t!=NULL)
 	{
 		t=strtok(NULL," ,"); 
 		if(t!=NULL)
 		{
 			cout<<"while t: "<<t<<endl;
			int jj = (int)count(vs.begin(),vs.end(),t);
 			comVal[i] = jj;
			i++;
 		}
		else
			break;
		cout<<"!!!!"<<endl;
 
 	}

	cout<<endl;

	

//	for_each (vs.begin(), vs.end(), myfunction);

//	sort(comVal,comVal+i);

//	for_each (comVal, comVal+i,myfunctionInt);

//	int j = (int)count(vs.begin(),vs.end(),"with");

	return 0;
} 
C++编码规范 小计
1.数组下标访问越界	2.使用野指针(指针未初始化就直接使用、delele完后继续使用、NEW申请不作NULL判断/托管后自己又手动DELETE)
3.字符串结尾标志’\0’	4.变量没有初始化	  5.变量名、枚举名、常量名字面意思、注释含义与使用时相反
6.所有的可能抛异常的地方都要有try catch		  7.没有处理返回值         8.函数局部变量或参数过大,堆栈溢出
9.数据类型不一致,变量或参数赋值出错       10.分支流程未释放动态申请的内存

一,排版
  1,程序块要采用缩进风格编写,缩进的空格数为4个		2,相对独立的程序块之间、变量说明之后必须加空行		
  3,较长的语句(>80字符)要分成多行书写,长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要进行适当的缩进,使排版整齐,语句可读。
  4,循环、判断等语句中若有较长的表达式或语句,则要进行适应的划分,长表达式要在低优先级操作符处划分新行,操作符放在新行之首。
  5,在两个以上的关键字、变量、常量进行对等操作时,它们之间的操作符之前、之后或者前后要加空格;进行非对等操作时,如果是关系密切的立即操作符(如->),后不应加空格.
  6,不允许把多个短语句写在一行中,即一行只写一条语句.  ||   对齐只使用空格键,不使用TAB键
  7,if、for、do、while、case、switch、default等语句自占一行,且if、for、do、while等语句的执行语句部分无论多少都要加括号{}
  8,函数或过程的开始、结构的定义及循环、判断等语句中的代码都要采用缩进风格,case语句下的情况处理语句也要遵从语句缩进要求。
  9,一行程序以小于80字符为宜,不要写得过长

  二,注释
  1,一般情况下,源程序有效注释量必须在20%以上
  2,说明性文件(如头文件.h文件、.inc文件、.def文件、编译说明文件.cfg等)头部应进行注释,注释必须列出:版权说明、版本号、生成日期、作者、内容、功能、与其它文件的关系、修改日志等,头文件的注释中还应有函数功能简要说明。
  3,源文件头部应进行注释,列出:版权说明、版本号、生成日期、作者、模块目的/功能、主要函数及其功能、修改日志等。
  4,函数头部应进行注释,列出:函数的目的/功能、输入参数、输出参数、返回值、调用关系(函数、表)等
  5,边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。不再有用的注释要删除
  6,注释的内容要清楚、明了,含义准确,防止注释二义性
  7,避免在注释中使用缩写,特别是非常用缩写。
  8,注释应与其描述的代码相近,对代码的注释应放在其上方或右方(对单条语句的注释)相邻位置,不可放在下面,如放于上方则需与其上面的代码用空行隔开。
  9,对于所有有物理含义的变量、常量,如果其命名不是充分自注释的,在声明时都必须加以注释,说明其物理含义。变量、常量、宏的注释应放在其上方相邻位置或右方.
  10,数据结构声明(包括数组、结构、类、枚举等),如果其命名不是充分自注释的,必须加以注释。对数据结构的注释应放在其上方相邻位置,不可放在下面;对结构中的每个域的注释放在此域的右方
  11,全局变量要有较详细的注释,包括对其功能、取值范围、哪些函数或过程存取它以及存取时注意事项等的说明。
  12,注释与所描述内容进行同样的缩排.  将注释与其上面的代码用空行隔开
  13,对变量的定义和分支语句(条件分支、循环语句等)必须编写注释。
  14,对于switch语句下的case语句,如果因为特殊情况需要处理完一个case后进入下一个case处理,必须在该case语句处理完、下一个case语句前加上明确的注释
  15,避免在一行代码或表达式的中间插入注释
  16,通过对函数或过程、变量、结构等正确的命名以及合理地组织代码的结构,使代码成为自注释的
  17,在代码的功能、意图层次上进行注释,提供有用、额外的信息
  18,在程序块的结束行右方加注释标记,以表明某程序块的结束
  19,注释格式尽量统一,建议使用“/* …… */”
  20,注释应考虑程序易读及外观排版的因素,使用的语言若是中、英兼有的,建议多使用中文,除非能用非常流利准确的英文表达
三,标识符命名
  1,标识符的命名要清晰、明了,有明确含义,同时使用完整的单词或大家基本可以理解的缩写,避免使人产生误解。
  2,命名中若使用特殊约定或缩写,则要有注释说明。
  3,自己特有的命名风格,要自始至终保持一致,不可来回变化。
  4,对于变量命名,禁止取单个字符(如i、j、k...),建议除了要有具体含义外,还能表明其变量类型、数据类型等,但i、j、k作局部循环变量是允许的。
  5,命名规范必须与所使用的系统风格保持一致,并在同一项目中统一,比如采用UNIX的全小写加下划线的风格或大小写混排的方式,不要使用大小写与下划线混排的方式,用作特殊标识如标识成员变量或全局变量的m_和g_,其后加上大小写混排的方式是允许的。
  6,除非必要,不要用数字或较奇怪的字符来定义标识符
  7,在同一软件产品内,应规划好接口部分标识符(变量、结构、函数及常量)的命名,防止编译、链接时产生冲突。
  8,用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。
  9,除了编译开关/头文件等特殊应用,应避免使用_EXAMPLE_TEST_之类以下划线开始和结尾的定义  || 编译开关一定要以下划线开头。

四,排版
  1,注意运算符的优先级,并用括号明确表达式的操作顺序,避免使用默认优先级。
  2,避免使用不易理解的数字,用有意义的标识来替代。涉及物理状态或者含有物理意义的常量,不应直接使用数字,必须用有意义的枚举或宏来代替。
  3,源程序中关系较为紧密的代码应尽可能相邻。
  4,不要使用难懂的技巧性很高的语句,除非很有必要时。
五,变量、结构
  1,去掉没必要的公共变量
  2,仔细定义并明确公共变量的含义、作用、取值范围及公共变量间的关系
  3,明确公共变量与操作此公共变量的函数或过程的关系,如访问、修改及创建等
  4,当向公共变量传递数据时,要十分小心,防止赋与不合理的值或越界等现象发生
  5,防止局部变量与公共变量同名
  6,严禁使用未经初始化的变量作为右值
  7,构造仅有一个模块或函数可以修改、创建,而其余有关模块或函数只访问的公共变量,防止多个不同模块或函数都可以修改、创建同一公共变量的现象
  8,使用严格形式定义的、可移植的数据类型,尽量不要使用与具体硬件或软件环境关系密切的变量
  9,结构的功能要单一,是针对一种事务的抽象。
  10,不要设计面面俱到、非常灵活的数据结构。
  11,不同结构间的关系不要过于复杂。
  12,结构中元素的个数应适中。若结构中元素个数过多可考虑依据某种原则把元素组成不同的子结构,以减少原结构中元素的个数
  13,仔细设计结构中元素的布局与排列顺序,使结构容易理解、节省占用空间,并减少引起误用现象
  14,结构的设计要尽量考虑向前兼容和以后的版本升级,并为某些未来可能的应用保留余地(如预留一些空间等)
  15,留心具体语言及编译器处理不同数据类型的原则及有关细节。
  16,编程时,要注意数据类型的强制转换
  17,对编译系统默认的数据类型转换,也要有充分的认识
  18,尽量减少没有必要的数据类型默认转换与强制转换。
  19,合理地设计数据并使用自定义数据类型,避免数据间进行不必要的类型转换
  20,对自定义数据类型进行恰当命名,使它成为自描述性的,以提高代码可读性。注意其命名方式在同一产品中的统一。
  21,当声明用于分布式环境或不同CPU间通信环境的数据结构时,必须考虑机器的字节顺序、使用的位域及字节对齐等问题 
六,函数、过程
  1,对所调用函数的错误返回码要仔细、全面地处理
  2,明确函数功能,精确(而不是近似)地实现函数设计
  3,编写可重入函数时,应注意局部变量的使用(如编写C/C++语言的可重入函数时,应使用auto即缺省态局部变量或寄存器变量)
  4,编写可重入函数时,若使用全局变量,则应通过关中断、信号量(即P、V操作)等手段对其加以保护
  5,在同一项目组应明确规定对接口函数参数的合法性检查应由函数的调用者负责还是由接口函数本身负责,缺省是由函数调用者负责。
  6,防止将函数的参数作为工作变量
  7,函数的规模尽量限制在200行以内。
  8,一个函数仅完成一件功能。
  9,为简单功能编写函数
  10,不要设计多用途面面俱到的函数
  11,函数的功能应该是可以预测的,也就是只要输入数据相同就应产生同样的输出。
  12,尽量不要编写依赖于其他函数内部实现的函数
  13,避免设计多参数函数,不使用的参数从接口中去掉
  14,非调度函数应减少或防止控制参数,尽量只使用数据参数
  15,检查函数所有参数输入的有效性。
  16,检查函数所有非参数输入的有效性,如数据文件、公共变量等
  17,函数名应准确描述函数的功能。
  18,使用动宾词组为执行某操作的函数命名。如果是OOP方法,可以只有动词(名词是对象本身)
  19,避免使用无意义或含义不清的动词为函数命名。
  20,函数的返回值要清楚、明了,让使用者不容易忽视错误情况。
  21,除非必要,最好不要把与函数返回值类型不同的变量,以编译系统默认的转换方式或强制的转换方式作为返回值返回
  22,让函数在调用点显得易懂、容易理解。
  23,在调用函数填写参数时,应尽量减少没有必要的默认数据类型转换或强制数据类型转换
  24,避免函数中不必要语句,防止程序中的垃圾代码
  25,防止把没有关联的语句放到一个函数中
  26,如果多段代码重复做同一件事情,那么在函数的划分上可能存在问题
  27,功能不明确较小的函数,特别是仅有一个上级函数调用它时,应考虑把它合并到上级函数中,而不必单独存在。
  28,设计高扇入、合理扇出(小于7)的函数。
  29,减少函数本身或函数间的递归调用
  30,仔细分析模块的功能及性能需求,并进一步细分,同时若有必要画出有关数据流图,据此来进行模块的函数划分与组织。
  31,改进模块中函数的结构,降低函数间的耦合度,并提高函数的独立性以及代码可读性、效率和可维护性。优化函数结构时,要遵守以下原则
  32,在多任务操作系统的环境下编程,要注意函数可重入性的构造
  33,避免使用BOOL参数。
  34,对于提供了返回值的函数,在引用时最好使用其返回值
  35,当一个过程(函数)中对较长变量(一般是结构的成员)有较多引用时,可以用一个意义相当的宏代替
七,可测性
  1,在同一项目组或产品组内,要有一套统一的为集成测试、联调、系统测试准备的调测开关及相应打印函数,并且要有详细的说明
  2,在同一项目组或产品组内,调测打印出的信息串的格式要有统一的形式。信息串中至少要有所在模块名(或源文件名)及行号。
  3,编程的同时要为单元测试选择恰当的测试点,并仔细构造测试代码、测试用例,同时给出明确的注释说明。测试代码部分应作为(模块中的)一个子模块,以方便测试代码在模块中的安装与拆卸(通过调测开关)
  4,在进行集成测试、联调、系统测试之前,要构造好测试环境、测试项目及测试用例,同时仔细分析并优化测试用例,以提高测试效率。
  5,使用断言来发现软件问题,提高代码可测性
  6,用断言来检查程序正常运行时不应发生但在调测时有可能发生的非法情况。
  7,不能用断言来检查最终产品肯定会出现且必须处理的错误情况。
  8,对较复杂的断言加上明确的注释。
  9,用断言确认函数的参数。
  10,用断言保证没有定义的特性或功能不被使用。
   11,用断言对程序开发环境(OS/Compiler/Hardware)的假设进行检查。
  12,正式软件产品中应把断言及其它调测代码去掉(即把有关的调测开关关掉)
  13,在软件系统中设置与取消有关测试手段,不能对软件实现的功能等产生影响。
  14,用调测开关来切换软件的DEBUG版和正式版,而不要同时存在正式版本和DEBUG版本的不同源文件,以减少维护的难度。
  15,软件的DEBUG版本和发行版本应该统一维护,不允许分家,并且要时刻注意保证两个版本在实现功能上的一致性
  16,在编写代码之前,应预先设计好程序调试与测试的方法和手段,并设计好各种调测开关及相应测试代码如打印函数等。
  17,调测开关应分为不同级别和类型。
  18,编写防错程序,然后在处理错误之后可用断言宣布发生错误。
八, 程序效率
  1,编程时要经常注意代码的效率
  2,在保证软件系统的正确性、稳定性、可读性及可测性的前提下,提高代码效率。
  3,局部效率应为全局效率服务,不能因为提高局部效率而对全局效率造成影响。
  4,通过对系统数据结构的划分与组织的改进,以及对程序算法的优化来提高空间效率
  5,循环体内工作量最小化。
  6,仔细分析有关算法,并进行优化。
  7,仔细考查、分析系统及模块处理输入(如事务、消息等)的方式,并加以改进。
  8,对模块中函数的划分及组织方式进行分析、优化,改进模块中函数的组织结构,提高程序效率。
  9,编程时,要随时留心代码效率;优化代码时,要考虑周全。
  10,不应花过多的时间拼命地提高调用不很频繁的函数代码效率。
  11,要仔细地构造或直接用汇编编写调用频繁或性能要求极高的函数。
  12,在保证程序质量的前提下,通过压缩代码量、去掉不必要代码以及减少不必要的局部和全局变量,来提高空间效率。
  13,在多重循环中,应将最忙的循环放在最内层。
  14,尽量减少循环嵌套层次。
  15,避免循环体内含判断语句,应将循环语句置于判断语句的代码块之中
  16,尽量用乘法或其它方法代替除法,特别是浮点运算中的除法。
  17,不要一味追求紧凑的代码。
九,质量保证
  1,在软件设计过程中构筑软件质量
  2,代码质量保证优先原则
  3,只引用属于自己的存贮空间。
  4,防止引用已经释放的内存空间。
  5,过程/函数中分配的内存,在过程/函数退出之前要释放
  6,过程/函数中申请的(为打开文件而使用的)文件句柄,在过程/函数退出之前要关闭。
  7,防止内存操作越界。
  8,认真处理程序所能遇到的各种出错情况。
  9,系统运行之初,要初始化有关变量及运行环境,防止未经初始化的变量被引用。
  10,系统运行之初,要对加载到系统中的数据进行一致性检查。
  11,严禁随意更改其它模块或系统的有关设置和配置。
  12,不能随意改变与其它模块的接口。
  13,充分了解系统的接口之后,再使用系统提供的功能.
  14,编程时,要防止差1错误。
  15,要时刻注意易混淆的操作符。当编完程序后,应从头至尾检查一遍这些操作符,以防止拼写错误。
  16,有可能的话,if语句尽量加上else分支,对没有else分支的语句要小心对待;switch语句必须有default分支。
  17,Unix下,多线程的中的子线程退出必需采用主动退出方式,即子线程应return出口。
  18,不要滥用goto语句。
  19,不使用与硬件或操作系统关系很大的语句,而使用建议的标准语句,以提高软件的可移植性和可重用性。
  20,除非为了满足特殊需求,避免使用嵌入式汇编。
  21,精心地构造、划分子模块,并按“接口”部分及“内核”部分合理地组织子模块,以提高“内核”部分的可移植性和可重用性。
  22,精心构造算法,并对其性能、效率进行测试。
  23,对较关键的算法最好使用其它算法来确认。
  24,时刻注意表达式是否会上溢、下溢。
  25,使用变量时要注意其边界值的情况。
  26,留心程序机器码大小(如指令空间大小、数据空间大小、堆栈空间大小等)是否超出系统有关限制。
  27,为用户提供良好的接口界面,使用户能较充分地了解系统内部运行状态及有关系统出错情况。
  28,系统应具有一定的容错能力,对一些错误事件(如用户误操作等)能进行自动补救。
  29,对一些具有危险性的操作代码(如写硬盘、删数据等)要仔细考虑,防止对数据、硬件等的安全构成危害,以提高系统的安全性。
  30,使用第三方提供的软件开发工具包或控件时,要注意以下几点:(1)充分了解应用接口、使用环境及使用时注意事项。
  2)不能过分相信其正确性。(3)除非必要,不要使用不熟悉的第三方工具包与控件。
  31,资源文件(多语言版本支持),如果资源是对语言敏感的,应让该资源与源代码文件脱离,具体方法有下面几种:使用单独的资源文件、DLL文件或其它单独的描述文件(如数据库格式)
十,代码编辑、编译、审查
  1,打开编译器的所有告警开关对程序进行编译。
  2,在产品软件(项目组)中,要统一编译开关选项。
  3,通过代码走读及审查方式对代码进行检查。
  4,测试部测试产品之前,应对代码进行抽查及评审。
  5,编写代码时要注意随时保存,并定期备份,防止由于断电、硬盘损坏等原因造成代码丢失。
  6,同产品软件(项目组)内,最好使用相同的编辑器,并使用相同的设置选项。
  7,yao小心地使用编辑器提供的块拷贝功能编程。
  8,合理地设计软件系统目录,方便开发人员使用
  9,某些语句经编译后产生告警,但如果你认为它是正确的,那么应通过某种手段去掉告警信息。
  10,使用代码检查工具(如C语言用PC-Lint, LogiSCOPE等)对源程序检查。
十一,代码测试、维护
  1,单元测试要求至少达到语句覆盖
  2,单元测试开始要跟踪每一条语句,并观察数据流及变量的变化. 不能进行单步跟踪的代码,要采用日志输出等形式,跟踪数据流和变量的变化。
  3,清理、整理或优化后的代码要经过审查及测试。
  4,代码版本升级要经过严格测试。
  5,使用工具软件对代码版本进行维护。
  6,正式版本上软件的任何修改都应有详细的文档记录。
  7,发现错误立即修改,并且要记录下来。
  8,关键的代码在汇编级跟踪。
  9,仔细设计并分析测试用例,使测试用例覆盖尽可能多的情况,以提高测试用例的效率。
  10,尽可能模拟出程序的各种出错情况,对出错处理代码进行充分的测试。
  11,仔细测试代码处理数据、变量的边界情况。
  12,保留测试信息,以便分析、总结经验及进行更充分的测试。
  13,不应通过“试”来解决问题,应寻找问题的根本原因。
  14,对自动消失的错误进行分析,搞清楚错误是如何消失的。
  15,修改错误不仅要治表,更要治本。
  16,测试时应设法使很少发生的事件经常发生。
  17,明确模块或函数处理哪些事件,并使它们经常发生
  18,坚持在编码阶段就对代码进行彻底的单元测试,不要等以后的测试工作来发现问题。要一边编码,一边编译,同时进行调试与功能验证,以提前发现问题和解决问题。
  19,去除代码运行的随机性(如去掉无用的数据、代码及尽可能防止并注意函数中的“内部寄存器”等),让函数运行的结果可预测,并使出现的错误可再现。

 十二,宏
  1,用宏定义表达式时,要使用完备的括号。
  2,将宏所定义的多条表达式放在大括号中
  3,使用宏时,不允许参数发生变化。
ERP成绩小程序,纯数组实现
//#include "stdafx.h"
//#include <stdio.h>
//
//int _tmain(int argc, _TCHAR* argv[])
//{
//
//	char a;
//	char b;
//	scanf("%c",&a);
//	//fflush(stdin);	
//						/* 回车/回车,a/回车
//						*  +
//						*  +*a+
//						*  可见第一个回车生效 +%c,然后回车被清空
//						*  a回车,a被收录到 +*%c+中,后面回车没了. 这样是完美的
//						*/
//	getchar();			
//						/* 回车/回车,a/回车
//						*  +
//						*  +*
//						*  +
//						*  可见第一个回车生效 +%c,然后回车被getchar收到,给到第二个%c中,然后自己输出,导致换行,下一个+是剩下的
//						*  a回车,a被收录到 +*%c+中,后面回车没了
//						*/
//	scanf("%c",&b);
//	printf("+%c+*%c*+\n",a,b);
//
//	return 0;
//}


/*
    //结构体(薪资,姓名)
	//新增人
	//显示人
	//删除人


*/

//0-9 选择操作类型 0保存,1添加用户

//PP pt[200];

//main中首先调用menu来显示所有操作
//main中,0先不管,先从数组0开始,0入参Add
//while循环,直到输入9,跳出输入,回到主提醒界面 0-9menu中 (menu)
//显示所有公司人员信息.

//Add(pt,count); 把现有所有的数组和已有人员传入
// {
	 //通过输入的结构体中的各个数据,填充结构体, 
	 //可以写个单独函数来 :用宏来匹配数组和结构体,直接操作数组(并在每次输入前,加上一句提醒输入)
	 
// }

#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "windows.h"

#define N 10
#define HEADER1 "                   -----------  INFO  -------------                \n"
#define HEADER2 "                  |Nober     |Name      |Wages     |                \n"
#define HEADER3 "                  |----------|----------|----------|                \n"
#define FORMAT  "                  |%-10s|%-10s|%10.2f|                \n"
#define DATA							p->no,p->name,p->wages
#define END     "                  |----------|----------|----------|                \n"
#define NAME 1
#define NUMBER 2
#define WAGES 3
#define ALL 1
#define LINE 2
typedef struct employee
{
	char no[10];
	char name[10];
	float wages;
}PP;

//程序提示输入界面
void menu();
//格式化字符串输入
void stringInput(char* strP,int size,const char* str);
void numberInput(float* fP,const char* str);
//删除指定位置的成员
void Del(PP p[],int count);
//新添人员
void Add(PP p[],int count);
//显示所有人员
void disp(PP p[],int count,int type);
void dispHeader(PP *p);
//定位成员记录所在位置
void Qur(PP p[],int n);
int locate(PP *p,char* str,int count,int type);
//修改制定成员成绩(都是按照名字查询)
void modify(PP *p,int count);
//在指定成员后面新添个成员A
void insert(PP *p,int count);
//按指定type进行排序,低到高,冒泡排序
void sort(PP *p,int count);
//保存到相关文件
void save(PP *p,int old,int count);

/*
cprintf("     *************************Menu********************************\n");
cprintf("     *  1 input   record             2 delete record             *\n");
cprintf("     *  3 search  record             4 modify record             *\n");
cprintf("     *  5 insert  record             6 count  record             *\n");
cprintf("     *  7 sort    record             8 save   record             *\n");
cprintf("     *  9 display record             0 quit   system             *\n");
cprintf("     *************************************************************\n");
*/
int main()
{
	int select = 0;
	int count = 0;			//count是所有元素数目,除了Add时,count多1,其余都要-1才能标注下标
	int isAdd = 0;
	int isWhileOk = 0;
	int i = 0;
	int old =0;
	PP p[N];// = {0};	//注意0
	char next;
	FILE* fp;
	
	printf("size of PP:%d\n",sizeof(PP));
	fp = fopen("d:\\lqc\\m3.log","ab+");				//a+,Opens for reading and appending   (w是可写,w+是写读,二者必须操作对象为empty)
	if(fp==NULL)
	{
		printf("file open error!");
		return;
	}
	while(!feof(fp))
	{
		if(fread(&p[count],sizeof(PP),1,fp)==1); //初始化过, 所以这里也读取了一次,把PP p[N] = {0};	//注意0注销
		count++;
	}
	count--;
	old = count;
	fclose(fp);
// 	while(p[count].no[0] != 0)	//注意判断是0
// 		count++;
	
	while(1)
	{
		system("cls");
		isAdd = 0;
		if(count>0)
			disp(p,count,ALL);
		menu();
		printf("请输入选择项:");
		scanf("%d",&select);
		while(1)
		{
			switch(select)
			{
			case 0:
				return;	//忘记了break了
				break;
			case 1:
				Add(p,count);
				isAdd = 1;
				break;
			case 2:
				Del(p,count);
				isAdd = 2;
				break;
			case 3:
				Qur(p,count);
				break;
			case 4:
				modify(p,count);
				break;
			case 5:
				insert(p,count);
				isAdd = 1;
				break;
			case 7:
				sort(p,count);
				break;
			case 8:
				save(p,old,count);
				old = count;
				break;
			case 9:
				disp(p,count,ALL);
				break;
			}
			//printf("请输入下一步操作,上一层(n),继续(y)!");
				
			/*getchar();//从缓存去读出一个字符,这样可以吸收掉上面的%d,这样后面的 %c才能获取 ,或者fflush(stdin),键盘缓存区清理了,不然下次scanf直接接收的是上一个的回车符
					  //scanf不是和我们键盘动作交互,而是和键盘缓存区交互的.(这个中间代理人)
			scanf("%c",&next);*/
			do
			{
				printf("请输入下一步操作,上一层(n),继续(y)!");
				//getchar();		//如果前面没有回车,空格等键盘输入,那么此处就不要加
				fflush(stdin);
				scanf("%c",&next);
				isWhileOk = 0;
				if(next == 'n')
				{	
					isWhileOk = 1;
					break;//跳出while3
				}
				else if(next == 'y')
					;
				else
				{
					isWhileOk = 1;
					printf("输入无效,请重试!\n");
					//getchar();
					//fflush(stdin);
				}
			}while(isWhileOk);			//这种方式很好.
					
		if(count==0)
			disp(p,count,LINE);		//第一次输入,断电这里,发现disp为空,处理下,然后加上2层while(1)继续调测

		if(isAdd ==1)
			count++;
		else if(isAdd == 2)	//要判断下是否为空(未实现)
			count--;
		
		if(isWhileOk == 1)	//放在count运算后面,不然count不准,disp出问题
			break;	//双break跳出while2	
		}
		//Sleep(2000);
	}
	
	return 0;
}

//保存
void save(PP *p,int old,int count)
{
	FILE* fp;
	int i =0;
	if(count ==0)
	{
		printf("this is nothing to save.\n");
		return;
	}
	//fp = fopen("d:\\lqc\\m3.log","a");
	fp = fopen("d:\\lqc\\m3.log","ab");		//a在不删除文件EOF标识下,新添元素,b是二进制模式
	if(fp==NULL)
	{
		printf("file open error!");
		return;
	}
	for(i=old;i<count;i++)
	{
		if(fwrite(&p[i],sizeof(PP),1,fp) == 1)
		{
			continue;
		}
		else
		{
			break;
		}
	}
	if(i>0)
	{
		printf("file save is successful, the record no of file is %d!\n",i);
	}
	else
	{
		printf("file save no record saved!\n");
	}
	fclose(fp);
}

//排序
void sort(PP *p,int count)
{
	int type = 0;
	int i = 0;
	int j =0;
	int key = count;
	printf("现在有%d 个成员",count);
	printf("请输入你要排序的类型,按号码NUMBER排序[2],按薪资WAGES排序[3]: ");
	scanf("%d",&type);
	if(type == WAGES)
	{
		for(j=0;j<count-1;j++)		//因为count为全部下标,最后一个下标不应该再判断了,因为count后面的那个值,可能没到N,那么count后(溢出)的值初始化为0,也参与判断,冒泡了.所以要减1
		{
			for(i=0;i<count-1-j;i++)			//2 3 5
			{
				PP tmp = {0};
				if(p[i].wages > p[i+1].wages)
				{
					printf("befor tmp[%d]:%f    ,     %f\n",i,p[i].wages,p[i+1].wages);
					strcpy(tmp.no , p[i+1].no);
					strcpy(tmp.name , p[i+1].name);
					tmp.wages = p[i+1].wages;

					strcpy(p[i+1].no , p[i].no);
					strcpy(p[i+1].name , p[i].name);
					p[i+1].wages = p[i].wages;

					strcpy(p[i].no , tmp.no);
					strcpy(p[i].name , tmp.name);
					p[i].wages = tmp.wages;
					printf("after tmp[%d]:%f    ,     %f\n",i,p[i].wages,p[i+1].wages);
				}
			}
		}		
	}
	else if(type == NUMBER)
	{
		//int tmp = atoi(p[i].no);
		for(j=0;j<count-1;j++)		
		{
			for(i=0;i<count-1-j;i++)			//2 3 5
			{
				PP tmp = {0};
				int t1 = atoi(p[i].no);
				int t2 = atoi(p[i+1].no);
				if(t1 > t2)
				{
					printf("befor tmp[%d]:%d    ,     %d\n",i,t1,t2);
					strcpy(tmp.no , p[i+1].no);
					strcpy(tmp.name , p[i+1].name);
					tmp.wages = p[i+1].wages;

					strcpy(p[i+1].no , p[i].no);
					strcpy(p[i+1].name , p[i].name);
					p[i+1].wages = p[i].wages;

					strcpy(p[i].no , tmp.no);
					strcpy(p[i].name , tmp.name);
					p[i].wages = tmp.wages;
					printf("after tmp[%d]:%s    ,     %s\n",i,p[i].no,p[i+1].no);
				}
			}
		}

	}
					//count有问题 <, <=
	disp(p,key,ALL);
	Sleep(2000);
}



//新添成员
void insert(PP *p,int count)
{
	int point = 0;	
	int i = 0;
	char name[10] = {0};
    stringInput(name,10,"请输入你要选择放入其后成员的姓名:");
	point = locate(p,name,count,NAME);
	if(point==-1)
	{
		printf("there is no people in here!\n");
		return ;
	}
	//把原来point+1后面的值都平移往后一下,从最后开始
	for(i=count-1;i>point;i--)		//
	{
		strcpy(p[i+1].no,p[i].no);
		strcpy(p[i+1].name,p[i].name);
		p[i+1].wages = p[i].wages;
	}
	//在point+1上,进行新添用户的数据输入
	Add(p,point+1);

}

//修改成绩
void modify(PP *p,int count)
{
	int point = 0;	
	char name[10] = {0};
	float wages = 0;
    stringInput(name,10,"请输入姓名:");
	point = locate(p,name,count,NAME);
	if(point==-1)
	{
		printf("there is no people in here!\n");
		return ;
	}
    numberInput(&wages,"请输入要修改成员的新成绩:");
	p[point].wages = wages;

	//显示修改后的信息
	disp(p,point,LINE);
}


//查询
void Qur(PP p[],int count)
{
	int i,point;	//i指向下一个节点,所以point不用 -- 了
	char name[10] = {0};
    stringInput(name,10,"请输入姓名:");
	point = locate(p,name,count,NAME);
	
	if(point==-1)
	{
		printf("there is no people in here!\n");
		return ;
	}

	//dispHeader(&p[point]);		//对应 pp *p入参形式
	disp(p,point,LINE);
	
	//Sleep(3000);
}

int locate(PP *p,char* str,int count,int type)
{
	int i,point = -1;

	for(i=0;i<count;i++)
	{
		if(type == NAME)
		{
			if(strcmp(p[i].name,str) == 0)
			{	
				point = i;
				break;
			}
		}
		else if(type == NUMBER)
		{
			if(strcmp(p[i].no,str) == 0)
			{	
				point = i;
				break;
			}
		}
	}
	return point;
}
//删除指定位置上的人员  //0是第一个,所以要删除的point值在函数中要--point
void Del(PP p[],int count)
{

	int i,point;	//i指向下一个节点,所以point不用 -- 了
	char name[10] = {0};
	int searchOk = 0;
    stringInput(name,10,"请输入姓名:");
	
	point = locate(p,name,count,NAME);
	if(point==-1)
	{
		printf("there is no people in here!\n");
		return ;
	}
	

	//让指针指向要删除位置的下一个,并把这个下一节点值赋值到要删的本来位置
	for(i=point+1;i<count;i++)
	{
		strcpy(p[i-1].no,p[i].no);
		strcpy(p[i-1].name,p[i].name);
		p[i-1].wages = p[i].wages;
	}
}

//display展示
void dispHeader(PP *p)
{
	printf(FORMAT,DATA);
}

void disp(PP pp[],int count,int type)
{
	int j;
	printf(HEADER1);
	printf(HEADER2);
	printf(HEADER3);

	if(type == ALL)
	{
		for(j=0;j<count;j++)
		{
			PP *p = &pp[j];
			dispHeader(p);
		}
	}
	else if(type == LINE)
	{
		PP *p = &pp[count];	//如果是LINE,那么count是几,就是显示的下标
		dispHeader(p);
	}

	printf(END);
	printf("\n");
	printf("\n");
	printf("\n");
	printf("\n");
}
//添加记录
void Add(PP p[],int count)				//后面的几个函数,都转成PP *p了, 更好看一些.
{
	PP sp;
// 	if(count == 0)
// 	{	
// 		printf("this is first record!\n");
// 		stringInput(p[0].no,10,"请输入工号:");
// 		stringInput(p[0].name,10,"请输入姓名:");
// 		numberInput(&(p[0].wages),"请输入你的薪水:");
// 
// 	}
// 	else
// 	{
		stringInput(p[count].no,10,"请输入工号:");
		stringInput(p[count].name,10,"请输入姓名:");
		numberInput(&(p[count].wages),"请输入你的薪水:");
//	}
	
}
//格式化输入
 void stringInput(char* strP,int size,const char* str)
 {
	 do{
 		printf("%s",str);
 		scanf("%s",strP);
		if(strlen(strP)>size)
			printf("输入过长,请重新输入!\n");
	 }while(strlen(strP)>size);
 
 }

 void numberInput(float* fP,const char* str)
 {
	 do{
		 printf("%s",str);
		 scanf("%f",fP);
	 }while(0);

 }
//菜单框架
void menu()
{
	//system("cls");   /*调用DOS命令,清屏.与clrscr()功能相同*/
	cprintf("     *************************Menu********************************\n");
	cprintf("     *  1 input   record             2 delete record             *\n");
	cprintf("     *  3 search  record             4 modify record             *\n");
	cprintf("     *  5 insert  record             6 count  record             *\n");
	cprintf("     *  7 sort    record             8 save   record             *\n");
	cprintf("     *  9 display record             0 quit   system             *\n");
	cprintf("     *************************************************************\n");
}
jiaxiao 1, 为了梦想和龙妞
道路法规:
14,20,23,79,81,84,88,90,130,139,143,174,197,214,218,260,261,269,275

(*),279,283,85,93,95,97,98,06,12,13,15,16,19,21,22,23,28-33,38,41,42,44,47
48,50,51,58,61,62,66,68,69,74,77,78,83,84,91,09,18

交通信号:
1,56,75,77(黑子,黄牌,是建议,黄字是警告),79,86,87,111,117,122,140,141.149,160,162,
170,172,173,177,181,190,192,229,251
~~~ 258,259,264,278,279(地上的标记白色是最低,黄色是最高,牌子是蓝白底,红色),
289,290,291,294,300,301,303,308,311,


文明驾驶:
4,93,128,149,159,179,189,201,225,

驾驶操作:60,70,
一个百度文库网站 为了梦想和龙妞
http://wenku.baidu.com/view/d066c6f4f90f76c661371abf.html

自己写的成绩管理系统小程序


#include "stdio.h"   /*标准输入输出函数库*/
#include "stdlib.h"  /*标准函数库*/
#include "string.h"  /*字符串函数库*/
#include <conio.h>    /*屏幕操作函数库*/
#define HEADER1 "      ----------------------------STUDENT----------------------------------  \n"
#define HEADER2 "     |    number     |      name     |Comp|Math|Eng |   sum  |  ave  |mici | \n"
#define HEADER3 "     |---------------|---------------|----|----|----|--------|-------|-----| "
#define FORMAT  "        |    %-10s |%-15s|%4d|%4d|%4d| %4d   | %.2f |%4d |\n"
#define DATA  p->data.num,p->data.name,p->data.egrade,p->data.mgrade,p->data.cgrade,p->data.total,p->data.ave,p->data.mingci
#define END     "       --------------------------------------------------------------------- \n"

int saveflag=0;  /*是否需要存盘的标志变量*/
/*定义与学生有关的数据结构*/
typedef struct student      /*标记为student*/
{
char num[10];   /*学号*/
char name[15];  /*姓名*/
int cgrade;     /*C语言成绩*/
int mgrade;     /*数学成绩*/
int egrade;     /*英语成绩*/
int total;      /*总分*/
float ave;      /*平均分*/
int mingci;     /*名次*/
};

/*定义每条记录或结点的数据结构,标记为:node*/
typedef struct node
{
struct student data;  /*数据域*/
struct node *next;    /*指针域*/
}Node,*Link;   /*Node为node类型的结构变量,*Link为node类型的指针变量*/


void menu()  /*主菜单*/
{
//system("cls");   /*调用DOS命令,清屏.与clrscr()功能相同*/

//textcolor(10);   /*在文本模式中选择新的字符颜色  vs2010没有这种dos时代的函数,真的没有,你只能在turbo_ c下使用这种函*/   
//gotoxy(10,5);     /*在文本窗口中设置光标*/
cprintf("                 The Students' Grade Management System \n");
//gotoxy(10,8);
cprintf("     *************************Menu********************************\n");
//gotoxy(10,9);
cprintf("     *  1 input   record             2 delete record             *\n");
//gotoxy(10,10);
cprintf("     *  3 search  record             4 modify record             *\n");
//gotoxy(10,11);
cprintf("     *  5 insert  record             6 count  record             *\n");
//gotoxy(10,12);
cprintf("     *  7 sort    reord              8 save   record             *\n");
//gotoxy(10,13);
cprintf("     *  9 display record             0 quit   system             *\n");
//gotoxy(10,14);
cprintf("     *************************************************************\n");
/*cprintf()送格式化输出至文本窗口屏幕中*/
}
void printheader() /*格式化输出表头*/
{
  printf(HEADER1);
  printf(HEADER2);
  printf(HEADER3);
}
void printdata(Node *pp) /*格式化输出表中数据*/
{
 Node* p;
 p=pp;
 printf(FORMAT,DATA);

}

void Wrong()  /*输出按键错误信息*/
{
printf("\n\n\n\n\n***********Error:input has wrong! press any key to continue**********\n");
getchar();
}

void Nofind()  /*输出未查找此学生的信息*/
{
printf("\n=====>Not find this student!\n");
}

void Disp(Link l)  /*显示单链表l中存储的学生记录,内容为student结构中定义的内容*/
{
Node *p;
p=l->next; /*l存储的是单链表中头结点的指针,该头结点没有存储学生信息,指针域指向的后继结点才有学生信息*/

if(!p)  /*p==NULL,NUll在stdlib中定义为0*/
{
  printf("\n=====>Not student record!\n");
  getchar();
  return;
}

printf("\n\n");
printheader(); /*输出表格头部*/

while(p)    /*逐条输出链表中存储的学生信息*/
{
  printdata(p);
  p=p->next;  /*移动至下一个结点*/
  printf(HEADER3);
}
getchar();
}

/*************************************************************
作用:用于定位链表中符合要求的节点,并返回指向该节点的指针
参数:findmess[]保存要查找的具体内容; nameornum[]保存按什么查找;
      在单链表l中查找;
**************************************************************/
Node* Locate(Link l,char findmess[],char nameornum[])
{
Node *r;
if(strcmp(nameornum,"num")==0) /*按学号查询*/
{
  r=l->next;
  while(r)
  {
   if(strcmp(r->data.num,findmess)==0) /*若找到findmess值的学号*/
    return r;
   r=r->next;
  }
}
else if(strcmp(nameornum,"name")==0)  /*按姓名查询*/
{
  r=l->next;
  while(r)
  {
   if(strcmp(r->data.name,findmess)==0)    /*若找到findmess值的学生姓名*/
    return r;
   r=r->next;
  }
}
return 0; /*若未找到,返回一个空指针*/
}


/*输入字符串,并进行长度验证(长度<lens)*/
void stringinput(char *t,int lens,char *notice)
{
   char n[255];
   do{
      printf(notice);  /*显示提示信息*/
      scanf("%s",n);  /*输入字符串*/
      if(strlen(n)>lens)printf("\n exceed the required length! \n"); /*进行长度校验,超过lens值重新输入*/
     }while(strlen(n)>lens);
   strcpy(t,n); /*将输入的字符串拷贝到字符串t中*/
}

/*输入分数,0<=分数<=100)*/
int numberinput(char *notice)
{
  int t=0;
   do{
      printf(notice);  /*显示提示信息*/
      scanf("%d",&t);  /*输入分数*/
      if(t>100 || t<0) printf("\n score must in [0,100]! \n"); /*进行分数校验*/
   }while(t>100 || t<0);
   return t;
}


 /*增加学生记录*/
void Add(Link l)
{
Node *p,*r,*s;  /*实现添加操作的临时的结构体指针变量*/
char ch,flag=0,num[10];
r=l;
s=l->next;
system("cls");
Disp(l); /*先打印出已有的学生信息*/
while(r->next!=NULL)
  r=r->next; /*将指针移至于链表最末尾,准备添加记录*/
while(1) /*一次可输入多条记录,直至输入学号为0的记录结点添加操作*/
{
 while(1) /*输入学号,保证该学号没有被使用,若输入学号为0,则退出添加记录操作*/
{

  stringinput(num,10,"input number(press '0'return menu):"); /*格式化输入学号并检验*/
  flag=0;

  if(strcmp(num,"0")==0) /*输入为0,则退出添加操作,返回主界面*/
      {return;}
  s=l->next;
    while(s) /*查询该学号是否已经存在,若存在则要求重新输入一个未被占用的学号*/
    {
      if(strcmp(s->data.num,num)==0)
      {
       flag=1;
       break;
       }
     s=s->next;
    }

  if(flag==1) /*提示用户是否重新输入*/

     {  getchar();
        printf("=====>The number %s is not existing,try again?(y/n):",num);
        scanf("%c",&ch);
        if(ch=='y'||ch=='Y')
         continue;
        else
          return;
      }
     else
      {break;}
  }
  
  p=(Node *)malloc(sizeof(Node)); /*申请内存空间*/
  if(!p)
   {
      printf("\n allocate memory failure "); /*如没有申请到,打印提示信息*/
      return ;             /*返回主界面*/
   }
  strcpy(p->data.num,num); /*将字符串num拷贝到p->data.num中*/
  stringinput(p->data.name,15,"Name:");
  p->data.cgrade=numberinput("C language Score[0-100]:"); /*输入并检验分数,分数必须在0-100之间*/
  p->data.mgrade=numberinput("Math Score[0-100]:");   /*输入并检验分数,分数必须在0-100之间*/
  p->data.egrade=numberinput("English Score[0-100]:"); /*输入并检验分数,分数必须在0-100之间*/
  p->data.total=p->data.egrade+p->data.cgrade+p->data.mgrade; /*计算总分*/
  p->data.ave=(float)(p->data.total/3);  /*计算平均分*/
  p->data.mingci=0;
  p->next=NULL; /*表明这是链表的尾部结点*/
  r->next=p;  /*将新建的结点加入链表尾部中*/
  r=p;
  saveflag=1;

  }
     return ;
}

void Qur(Link l) /*按学号或姓名,查询学生记录*/
{
int select; /*1:按学号查,2:按姓名查,其他:返回主界面(菜单)*/
char searchinput[20]; /*保存用户输入的查询内容*/
Node *p;
if(!l->next) /*若链表为空*/
{
  system("cls");
  printf("\n=====>No student record!\n");
  getchar();
  return;

}
system("cls");
printf("\n     =====>1 Search by number  =====>2 Search by name\n");
printf("      please choice[1,2]:");
scanf("%d",&select);
if(select==1)   /*按学号查询*/
 {

  stringinput(searchinput,10,"input the existing student number:");
  p=Locate(l,searchinput,"num");/*在l中查找学号为searchinput值的节点,并返回节点的指针*/
  if(p) /*若p!=NULL*/
  {
   printheader();
   printdata(p);
   printf(END);
   printf("press any key to return");
   getchar();
  }
  else
   Nofind();
   getchar();
}
else if(select==2) /*按姓名查询*/
{
  stringinput(searchinput,15,"input the existing student name:");
  p=Locate(l,searchinput,"name");
  if(p)
  {
   printheader();
   printdata(p);
   printf(END);
   printf("press any key to return");
   getchar();
  }
  else
   Nofind();
   getchar();
}
else
  Wrong();
  getchar();
  
}

/*删除学生记录:先找到保存该学生记录的节点,然后删除该节点*/
void Del(Link l)
{
int sel;
Node *p,*r;
char findmess[20];
if(!l->next)
{ system("cls");
  printf("\n=====>No student record!\n");
  getchar();
  return;
}
system("cls");
Disp(l);
printf("\n        =====>1 Delete by number       =====>2 Delete by name\n");
printf("       please choice[1,2]:");
scanf("%d",&sel);
if(sel==1)
{

  stringinput(findmess,10,"input the existing student number:");
  p=Locate(l,findmess,"num");
  if(p)  /*p!=NULL*/
  {
   r=l;
   while(r->next!=p)
    r=r->next;
   r->next=p->next;/*将p所指节点从链表中去除*/
   free(p); /*释放内存空间*/
   printf("\n=====>delete success!\n");
   getchar();
   saveflag=1;
  }
  else
   Nofind();
   getchar();
}
else if(sel==2) /*先按姓名查询到该记录所在的节点*/
{
  stringinput(findmess,15,"input the existing student name");
  p=Locate(l,findmess,"name");
  if(p)
  {
   r=l;
   while(r->next!=p)
    r=r->next;
   r->next=p->next;
   free(p);
   printf("\n=====>delete success!\n");
   getchar();
   saveflag=1;
  }
  else
   Nofind();
   getchar();
}
else
  Wrong();
  getchar();
}

/*修改学生记录。先按输入的学号查询到该记录,然后提示用户修改学号之外的值,学号不能修改*/
void Modify(Link l)
{
Node *p;
char findmess[20];
if(!l->next)
{ system("cls");
  printf("\n=====>No student record!\n");
  getchar();
  return;
}
system("cls");
printf("modify student recorder");
Disp(l);


stringinput(findmess,10,"input the existing student number:"); /*输入并检验该学号*/
p=Locate(l,findmess,"num"); /*查询到该节点*/
if(p) /*若p!=NULL,表明已经找到该节点*/
{
  printf("Number:%s,\n",p->data.num);
  printf("Name:%s,",p->data.name);
  stringinput(p->data.name,15,"input new name:");

  printf("C language score:%d,",p->data.cgrade);
  p->data.cgrade=numberinput("C language Score[0-100]:");

  printf("Math score:%d,",p->data.mgrade);
  p->data.mgrade=numberinput("Math Score[0-100]:");


  printf("English score:%d,",p->data.egrade);
   p->data.egrade=numberinput("English Score[0-100]:");

  p->data.total=p->data.egrade+p->data.cgrade+p->data.mgrade;
  p->data.ave=(float)(p->data.total/3);
  p->data.mingci=0;
  printf("\n=====>modify success!\n");
  Disp(l);
  saveflag=1;
}
else
  Nofind();
  getchar();

}



/*插入记录:按学号查询到要插入的节点的位置,然后在该学号之后插入一个新节点。*/
void Insert(Link l)
{
   Link p,v,newinfo; /*p指向插入位置,newinfo指新插入记录*/
   char ch,num[10],s[10];  /*s[]保存插入点位置之前的学号,num[]保存输入的新记录的学号*/
   int flag=0;
   v=l->next;
   system("cls");
   Disp(l);
   while(1)
   { stringinput(s,10,"please input insert location  after the Number:");
     flag=0;v=l->next;
     while(v) /*查询该学号是否存在,flag=1表示该学号存在*/
     {
      if(strcmp(v->data.num,s)==0)  {flag=1;break;}
          v=v->next;
     }
      if(flag==1)
        break; /*若学号存在,则进行插入之前的新记录的输入操作*/
     else
     {  getchar();
        printf("\n=====>The number %s is not existing,try again?(y/n):",s);
        scanf("%c",&ch);
        if(ch=='y'||ch=='Y')
         {continue;}
        else
          {return;}
      }
   }
  /*以下新记录的输入操作与Add()相同*/
  stringinput(num,10,"input new student Number:");
  v=l->next;
  while(v)
  {
   if(strcmp(v->data.num,num)==0)
   {
    printf("=====>Sorry,the new number:'%s' is existing !\n",num);
    printheader();
    printdata(v);
    printf("\n");
    getchar();
    return;
   }
   v=v->next;
  }
  

  newinfo=(Node *)malloc(sizeof(Node));
  if(!newinfo)
   {
      printf("\n allocate memory failure "); /*如没有申请到,打印提示信息*/
      return ;             /*返回主界面*/
   }
  strcpy(newinfo->data.num,num);
  stringinput(newinfo->data.name,15,"Name:");
  newinfo->data.cgrade=numberinput("C language Score[0-100]:");
  newinfo->data.mgrade=numberinput("Math Score[0-100]:");
  newinfo->data.egrade=numberinput("English Score[0-100]:");
  newinfo->data.total=newinfo->data.egrade+newinfo->data.cgrade+newinfo->data.mgrade;
  newinfo->data.ave=(float)(newinfo->data.total/3);
  newinfo->data.mingci=0;
  newinfo->next=NULL;
  saveflag=1; /*在main()有对该全局变量的判断,若为1,则进行存盘操作*/
  /*将指针赋值给p,因为l中的头节点的下一个节点才实际保存着学生的记录*/
  p=l->next;
  while(1)
   {
     if(strcmp(p->data.num,s)==0) /*在链表中插入一个节点*/
      {
        newinfo->next=p->next;
        p->next=newinfo;
        break;
       }
      p=p->next;
    }

   Disp(l);
   printf("\n\n");
   getchar();

}

/*统计该班的总分第一名和单科第一,和各科不及格人数*/
void Tongji(Link l)
{
Node *pm,*pe,*pc,*pt; /*用于指向分数最高的节点*/
Node *r=l->next;
int countc=0,countm=0,counte=0; /*保存三门成绩中不及格的人数*/
if(!r)
{ system("cls");
  printf("\n=====>Not student record!\n");
  getchar();
  return ;
}
system("cls");
Disp(l);
pm=pe=pc=pt=r;
while(r)
{
  if(r->data.cgrade<60) countc++;
  if(r->data.mgrade<60) countm++;
  if(r->data.egrade<60) counte++;

  if(r->data.cgrade>=pc->data.cgrade)    pc=r;
  if(r->data.mgrade>=pm->data.mgrade)    pm=r;
  if(r->data.egrade>=pe->data.egrade)    pe=r;
  if(r->data.total>=pt->data.total)      pt=r;
  r=r->next;
}
printf("\n------------------------------the TongJi result--------------------------------\n");
printf("C Language<60:%d (ren)\n",countc);
printf("Math      <60:%d (ren)\n",countm);
printf("English   <60:%d (ren)\n",counte);
printf("-------------------------------------------------------------------------------\n");
printf("The highest student by total   scroe   name:%s totoal score:%d\n",pt->data.name,pt->data.total);
printf("The highest student by English score   name:%s totoal score:%d\n",pe->data.name,pe->data.egrade);
printf("The highest student by Math    score   name:%s totoal score:%d\n",pm->data.name,pm->data.mgrade);
printf("The highest student by C       score   name:%s totoal score:%d\n",pc->data.name,pc->data.cgrade);
printf("\n\npress any key to return");
getchar();
}
/*利用插入排序法实现单链表的按总分字段的降序排序,从高到低*/
void Sort(Link l)
{
Link ll;
Node *p,*rr,*s;
int i=0;
if(l->next==NULL)
{ system("cls");
  printf("\n=====>Not student record!\n");
  getchar();
  return ;
}

ll=(Node*)malloc(sizeof(Node)); /*用于创建新的节点*/
if(!ll)
   {
      printf("\n allocate memory failure "); /*如没有申请到,打印提示信息*/
      return ;             /*返回主界面*/
   }
ll->next=NULL;
system("cls");
Disp(l);  /*显示排序前的所有学生记录*/
p=l->next;
while(p) /*p!=NULL*/
{
  s=(Node*)malloc(sizeof(Node)); /*新建节点用于保存从原链表中取出的节点信息*/
  if(!s) /*s==NULL*/
   {
      printf("\n allocate memory failure "); /*如没有申请到,打印提示信息*/
      return ;             /*返回主界面*/
   }
  s->data=p->data; /*填数据域*/
  s->next=NULL;    /*指针域为空*/
  rr=ll;
  /*rr链表于存储插入单个节点后保持排序的链表,ll是这个链表的头指针,每次从头开始查找插入位置*/

  while(rr->next!=NULL && rr->next->data.total>=p->data.total)
   {rr=rr->next;} /*指针移至总分比p所指的节点的总分小的节点位置*/
  if(rr->next==NULL)/*若新链表ll中的所有节点的总分值都比p->data.total大时,就将p所指节点加入链表尾部*/
     rr->next=s;
  else /*否则将该节点插入至第一个总分字段比它小的节点的前面*/
  {
   s->next=rr->next;
   rr->next=s;
  }
   p=p->next; /*原链表中的指针下移一个节点*/
 }

   l->next=ll->next; /*ll中存储是的已排序的链表的头指针*/
   p=l->next;           /*已排好序的头指针赋给p,准备填写名次*/
   while(p!=NULL)  /*当p不为空时,进行下列操作*/
   {
      i++;       /*结点序号*/
      p->data.mingci=i;   /*将名次赋值*/
      p=p->next;   /*指针后移*/

   }
Disp(l);
saveflag=1;
printf("\n    =====>sort complete!\n");

}

/*数据存盘,若用户没有专门进行此操作且对数据有修改,在退出系统时, 会提示用户存盘*/
void Save(Link l)
{
FILE* fp;
Node *p;
int count=0;
fp=fopen("c:\\student","wb");/*以只写方式打开二进制文件*/
if(fp==NULL) /*打开文件失败*/
{
  printf("\n=====>open file error!\n");
  getchar();
  return ;
}
p=l->next;

while(p)
{
  if(fwrite(p,sizeof(Node),1,fp)==1)/*每次写一条记录或一个节点信息至文件*/
  { 
   p=p->next;
   count++;
  }
  else
  {
   break;
  }
}
if(count>0)
{
  getchar();
  printf("\n\n\n\n\n=====>save file complete,total saved's record number is:%d\n",count);
  getchar();
  saveflag=0;
}
else
{system("cls");
 printf("the current link is empty,no student record is saved!\n");
 getchar();
 }
fclose(fp); /*关闭此文件*/
}

void main_()
{

  Link l;      /*定义链表*/
  FILE *fp;    /*文件指针*/
  int select;     /*保存选择结果变量*/
  char ch;     /*保存(y,Y,n,N)*/
  int count=0; /*保存文件中的记录条数(或结点个数)*/
  Node *p,*r;   /*定义记录指针变量*/


  l=(Node*)malloc(sizeof(Node));
  if(!l)
   {
      printf("\n allocate memory failure "); /*如没有申请到,打印提示信息*/
      return ;             /*返回主界面*/
   }
  l->next=NULL;
  r=l;
  fp=fopen("C:\\student","ab+"); /*以追加方式打开一个二进制文件,可读可写,若此文件不存在,会创建此文件*/
  if(fp==NULL)
  {
    printf("\n=====>can not open file!\n");
    exit(0);
  }

while(!feof(fp))
{
  p=(Node*)malloc(sizeof(Node));
  if(!p)
   {
      printf(" memory malloc failure!\n");    /*没有申请成功*/
      exit(0);       /*退出*/
   }

  if(fread(p,sizeof(Node),1,fp)==1) /*一次从文件中读取一条学生成绩记录*/
  {
   p->next=NULL;
   r->next=p;
   r=p;                            /*r指针向后移一个位置*/
   count++;
   }
}

fclose(fp); /*关闭文件*/
printf("\n=====>open file sucess,the total records number is : %d.\n",count);
menu();
while(1)
{
   system("cls");
   menu();
   p=r;
   printf("\n              Please Enter your choice(0~9):");    /*显示提示信息*/
   scanf("%d",&select);

  if(select==0)
  {
   if(saveflag==1) /*若对链表的数据有修改且未进行存盘操作,则此标志为1*/
   { getchar();
     printf("\n=====>Whether save the modified record to file?(y/n):");
     scanf("%c",&ch);
     if(ch=='y'||ch=='Y')
       Save(l);
   }
   printf("=====>thank you for useness!");
   getchar();
   break;
  }

  switch(select)
  {
  case 1:Add(l);break;            /*增加学生记录*/
  case 2:Del(l);break;           /*删除学生记录*/
  case 3:Qur(l);break;           /*查询学生记录*/
  case 4:Modify(l);break;        /*修改学生记录*/
  case 5:Insert(l);break;        /*插入学生记录*/
  case 6:Tongji(l);break;       /*统计学生记录*/
  case 7:Sort(l);break;        /*排序学生记录*/
  case 8:Save(l);break;        /*保存学生记录*/
  case 9:system("cls");Disp(l);break;         /*显示学生记录*/
  default: Wrong();getchar();break;        /*按键有误,必须为数值0-9*/
  }
}
}
MK 小计
http://xinsheng.huawei.com/cn/index.php?app=forum&mod=Detail&act=index&id=1992033

http://xinsheng.huawei.com/cn/index.php?app=forum&mod=List&act=index&class=462&p=2



http://m.baidu.com/searchbox?action=novel&type=detail&src=http%3A%2F%2Fwww.caihongwenxue.com%2Fhtml%2Fbook%2F12%2F12098%2F&src=http%3A%2F%2Fwww.caihongwenxue.com%2Fhtml%2Fbook%2F12%2F12098%2F&uid=31B07A937DC122E82AF5A3CC2728F81D09D754955ONJRSENOAO&ua=640_960_iphone_5.4.5.0_0&ut=iPhone3%2C3_6.1.3&from=1099a&osname=baiduboxapp&osbranch=i0&cfrom=1099a&service=bdbox&data=%7B%22gid%22%3A%222050478912%22%2C%22cpsrc%22%3A%22http%3A%2F%2Fwww.caihongwenxue.com%2Fhtml%2Fbook%2F12%2F12098%2F%22%7D
飞机小程序 mfc
// MyFly.cpp : 定义应用程序的类行为。
//

#include "stdafx.h"
#include "MyFly.h"
#include "MainFrm.h"

#include "MyFlyDoc.h"
#include "MyFlyView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CMyFlyApp

BEGIN_MESSAGE_MAP(CMyFlyApp, CWinApp)
	ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
	// 基于文件的标准文档命令
	ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
	ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
END_MESSAGE_MAP()


// CMyFlyApp 构造

CMyFlyApp::CMyFlyApp()
{
	// TODO: 在此处添加构造代码,
	// 将所有重要的初始化放置在 InitInstance 中
}


// 唯一的一个 CMyFlyApp 对象

CMyFlyApp theApp;

// CMyFlyApp 初始化

BOOL CMyFlyApp::InitInstance()
{
	// 如果一个运行在 Windows XP 上的应用程序清单指定要
	// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
	//则需要 InitCommonControls()。否则,将无法创建窗口。
	InitCommonControls();

	CWinApp::InitInstance();

	// 标准初始化
	// 如果未使用这些功能并希望减小
	// 最终可执行文件的大小,则应移除下列
	// 不需要的特定初始化例程
	// 更改用于存储设置的注册表项
	// TODO: 应适当修改该字符串,
	// 例如修改为公司或组织名
	SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
	LoadStdProfileSettings(4);  // 加载标准 INI 文件选项(包括 MRU)
	// 注册应用程序的文档模板。文档模板
	// 将用作文档、框架窗口和视图之间的连接
	CSingleDocTemplate* pDocTemplate;
	pDocTemplate = new CSingleDocTemplate(
		IDR_MAINFRAME,
		RUNTIME_CLASS(CMyFlyDoc),
		RUNTIME_CLASS(CMainFrame),       // 主 SDI 框架窗口
		RUNTIME_CLASS(CMyFlyView));
	if (!pDocTemplate)
		return FALSE;
	AddDocTemplate(pDocTemplate);
	// 分析标准外壳命令、DDE、打开文件操作的命令行
	CCommandLineInfo cmdInfo;
	ParseCommandLine(cmdInfo);
	// 调度在命令行中指定的命令。如果
	// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。
	if (!ProcessShellCommand(cmdInfo))
		return FALSE;
	// 唯一的一个窗口已初始化,因此显示它并对其进行更新
	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();
	// 仅当存在后缀时才调用 DragAcceptFiles,
	//  在 SDI 应用程序中,这应在 ProcessShellCommand  之后发生
	return TRUE;
}



// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()

// 用于运行对话框的应用程序命令
void CMyFlyApp::OnAppAbout()
{
	CAboutDlg aboutDlg;
	aboutDlg.DoModal();
}


// CMyFlyApp 消息处理程序

VC -liying mfc
VC实战
7. 绘图
	GDI是一个模块.windows用来管理图形操作的一个,与设备无关的模块. 它是一个可执行程序,接受应用程序的绘图请求(请求就是gdi函数调用),并将这些函数传        递个相应的设备驱动程序,来完成在物理设备中的输出显示.
	DC是设备环境. 画图不用经过设备,如打印机,显示器,而是直接通过wds提供的设备环境dc来完成.
	一些绘图函数.
	应用程序通过dc设备环境来操作物理设备的步骤
		应用程-->mfc设备dc类-->图形设备接口GDI-->设备驱动程序-->物理设备
	为支持GDI绘图,MFC提供了2个重要的类,一个是CDC用于设置绘图属性和绘制图形. 一个是绘图对象类CGdiObject,用于封装各种GDI绘图对象和方法
	1)设备环境类CDC	
		CClientDC 客户区绘图
		CPaintDC  是为OnPaint重画时所提供的显示描述表. 
		CWindowDC 客户区和非客户区的绘制, 如窗口边框,标题栏,控制按钮栏
		CMetaFileDC 图源文件的绘制. 
		
		映射模式:绘图用的坐标都是按照逻辑单位(像素)给出的. 一个逻辑单位多少长度,由映射模式决定, 一共3类八种映射模式.
			逻辑点--->像素点	MM_TEXT,   
			逻辑点--->固定长度(约束映射)  MM_TWIPS,MM_HIENGLISH,MM_HIMETRIC,MM_LOENGLISH,MM_LOMETRIC
			逻辑点--->非固定长度(非约束映射) MM_ANISOTROIPC,MM_ISOTROPIC
			::SETMAPMODE, ::GETMAPMODE,


	2)GDI对象和绘图对象类CGdiObject
		CPen: 用来绘制线条,图形的 1)画笔的分类,其中堆画笔是系统定义好的画笔.	2)几何画笔的3种属性	3)画笔的构造函数  3种,分别适用于几何画笔,后面一种适合复杂的修饰画笔
								一步构造和2步构造法(后者不调用有参构造,但是要用createPen
		CBrush: 用来以颜色填充控件,窗口和其他区域的 GDI对象.
			1)分类 堆画刷,实体画刷,阴影画刷,图案画刷 , 其中堆**表示系统自己定义好的画刷,黑,百,暗灰,灰色,淡灰,空
			2)属性 颜色/图案/阴影类型  阴影类型分为阴影线为水平线,垂直线,+45°左到右,-45°右到左,交叉的水平线和垂直线,斜向交叉的直线
			3)构造函数   4种
			4)一步构造,2步构造创建画刷
		CFont: 字体方式,就是要先创建字体,然后用这个字体来输出文本
			1)分类
			2)属性,字符高度/宽度/斜度/旋转度/.....
			3)LOGFONT数据结构,包含了14个逻辑字体的特征. 如以逻辑单位指出字符的高度,输出精度....
			4)TEXTMETRIC 设置或者获取文本字符的有关信息,如文本高度,字符基线以上的高度....
			5)创建字符 
		CBitMap: 位图.

	3)点类,矩形大小类,矩形类   CPoint ,CSize, CRect
	4)常见的流程
		绘图任务流程: 
			定义CDC类或者其派生类 的对象.
			定义GDI, 创建GDI对象.
			用selectObject选择新的GDI对象,保存老GDI对象
			绘图
			还原老GDI对象
		绘制文本任务流程: 
			字体大小计算 GetTextMetric
			设置文本属性 SetTextColor,SetBkColor,SetBkMode
			输出文本 DrawText,ExtTextOut,GrayString,TabbedTextOut,TextOut
		绘点任务流程: 
		
		绘直线:
		
		绘椭圆,矩形.			//用的都是CClientDc的函数,那CRect是class CPoint : public tagPOINT,也可以画出,但不是画笔的吧?

		

			
	5)实例操作










11. 数据库操作
	1)ODBC
		首先要新建Access mdb文件以及表,记录,值
		在window注册数据库, 然后在程序导航中,指向这个test2.mdb
		set类文件自动生成,建立了类与数据库表的交互, 包括一些connect,defaultSql操作等 如果要新添记录,删除等操作需要自己实现
		在view的rc中,新建edit输入框, 在view的DoDataExchange中, 按照模板 // DDX_FieldText(pDX, IDC_MYEDITBOX, m_pSet->m_szColumn1, m_pSet)来修改  DDX_FieldText(pDX, IDC_EDIT1, m_pSet->m_ID, m_pSet);  不需要自己新添变量(vc6可以新添变量导航,支持m_pSet->m_ID变量新添,vs不行)
		编译即可完成最简单的 view---关联db的呈现动作.  可能要修改一下set中,变量的类型 cString, long,为期望的字段类型

	2)Ado	
		需要自己在dlg/view视图中进行使用, 在app中进行初始化

	3)OLE DB 在vs2003中可以直接用odbc和oledb.
	
	4)关于variant的用法 http://baike.baidu.com/view/977550.htm ,词条下面的类型对应表 ,用它来接收来自数据库各字段类型

12. DLL


13. ActiveX+COM

15. 进程和线程
ADO连接 mfc
void CAdoDlg::OnBtnQuery() 
{
	// TODO: Add your control notification handler code here
	CoInitialize(NULL);
	_ConnectionPtr pConn(__uuidof(Connection));
	_RecordsetPtr pRst(__uuidof(Recordset));
	_CommandPtr pCmd(__uuidof(Command));

	//D:\oracle\product\10.2.0\db_1\NETWORK\ADMIN\tnsnames.ora中有配置ora11g_123,且有ORACLE的tns运行.
	//pConn->Open("Provider=OraOLEDB.Oracle;User ID=omepg;Password=omepg;Data Source=ora11g_123","","",adModeUnknown);//adConnectUnspecified
	pConn->Open("Provider=OraOLEDB.Oracle;User ID=omepg;Password=omepg;Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=host)(PORT=1521)))(CONNECT_DATA=(SID=ora11g)))","","",adModeUnknown);
    pRst=pConn->Execute("select user_uri,state from espace_user_xml where rownum<=5",NULL,adCmdText);


	while(!pRst->rsEOF)
	{
		((CListBox*)GetDlgItem(IDC_LIST1))->AddString(
			(_bstr_t)pRst->GetCollect("user_uri"));
		pRst->MoveNext();
	}
	
	pRst->Close();
	pConn->Close();
	pCmd.Release();
	pRst.Release();
	pConn.Release();
	CoUninitialize();
}
test
include<iostream>
using namespace std;
class pwr
{
private:
    int e;
    double base,val;
public:
    pwr(double base,int e);

    pwr operator+(pwr p)
    {
        cout<<"p base: "<<p.base<<" and e: "<<p.e<<endl;
        pwr tmp(base+p.base,e+p.e);
        return tmp;
    }
};

pwr::pwr(double base,int e)
{
    this->val = 1;
    while(e-->0)
    {
        val *= base;
    }
}

int main()
{
    pwr p1(2,1),p2(2,2),p3(0,0);
    p3=p1+p2;
    return 0;
}
2014-06学习总结 为了梦想和龙妞
6月第一周:  
	研究通用类,通用函数,模板
           stl,算法
	重温primer和指南笔记
	研究内核代码,学习一些技巧
	研究各种面试/笔试题
	麻将和九宫格代码
	深入理解计算机系统中的有关转码知识
	类型转换技术



//6.3
大全20 通用函数和模板  *608
	1,testMain工程函数,L1270
		通用函数,不用再写出定义实体,否则必须在下面实现.(可以实现特殊类型的重写)
	2,C1125(P620) 通用数组类  ,里面有操作符的重载, []. 要学习下.
		atype<int> int_array;
		Atype &operator[](int);

		...
		template <class AType> AType &atype<AType>::operator[](int i)


大全21 异常处理和类型转换,以及函数默认参数,naming 空间
	1,程序中编写的异常处理, 都包含一个try,1/多个throw,1/多个catch.   如果有第二个try块, 那又是另外一个异常块了.
	2,C1131, 如果try中调用多个throw程序, 但是如果第一个就符合,后面的讲不再调用, 直接到了catch了就.
	3,testMain工程函数,L1373   
	程序何时执行catch, 1133中,try/catch是为了保护程序,以免非正常结束. 只有try中的throw后(而且throw的类型和cathc中相符)才会执行catch. 如果没有相符的, 会报错.
	4,如果要throw进行类型限制,可以用一个函数专门管理throw,并在throw后的()里进行throw类型限制, C1138
		void XHandler(int test) throw(int,double,float)
		{	if(test==0)throw 1;
			...
		}
		如果你throw的东西,超出了3个限制,如"hello", 则异常 //不对,如果后面有catch(char*)还是能继续,这不对啊.去看primer4
		如果throw(),里面是空,那么里面的throw会被无视,就是定义了不抛出异常,函数里的throw写了也没用, 那么catch会直接报错.//可是现在例子证明,列表有没有都一样,去看primer4吧 //
		(from primer)空说明列表指出函数不抛出任何异常:(throw(),可以让编译器更快,但是如果后面有catch匹配,它还是会走)
		(from primer)如果一个函数声明没有指定异常说明,则该函数可以抛出任意类型的异常。(就是函数后没有throw关键字)
	5,重新抛出异常
		如在XHander中 try/throw 1/catch(cathc中又有throw 2),  那么main调用Xhander,先抛出throw 1, 函数中的cathc捕获, 然后throw 2, 这时是main中的catch捕获.  C1139
		异常处理提供强大的功能,保护程序以防止非期望的事情/输入等事件 C1140
	6,在函数中,如果定义了缺省参数,如 Xhander(int i,int j=5),那么调用函数时,第二个参数可以不用,同样可以适用于构造函数,可以避免重载构造函数(不用再多写一个场景的构造函数). 这样可以简化函数参数的处理,但是如果第二个参数缺省使用的概率少于75%,那么久就没必要使用缺省,会影响其他人阅读.

	7,类型转换
		C1145是类型转换+类运算符重载的极好例子啊. 
		class pt{int a,b,c};   pt operator +(pt obj){ int i,j; i=obj.a; j=obj.b; pt t(i,j);return t;} //运算符重载
		operator int(void) {return c;}//类型转换,必须(void),可以省掉再弄个重载运算符 pt和int的,甚至友元省掉.
		pt(int base ,int exp){a=base; b= exp; c = a*b;}; //构造
		main(){pt w1(1,2); int i = w1; pt w2(3,4),w3(5,6); w3=w2+w3; i=w3; cout<<i;}
		选择使用重载运算符还是类型转换,要根据程序和类的不同而不同,基于类的特色而定.

	  强制转换运算符
		c强制转换运算符:
			
		c++新添强制转换运算符:
			a)常量强制转换 const_cast<type>(object)
				重置const,volatile修饰符(就是去掉这个属性),显式转换指向任何类型的对象的指针以及指向数据成员的指针.
				如,void X(const Y* obj){ Y *y = obj; //error,常量指针给普通指针了 Y *y = const_cast<Y*> (obj); //可以}
				缺点:转换后的指针,引用,指向数据成员的指针进行写操作,可能产生不可知的或不可预期的结果.
				const_cast只能用于指针或引用, 不能跨基础类型, 主要是为了去const和volatile

			b)动态强制转换 dymanic_cast<type>(object)
				执行程序运行时的强制转换并校验转换的有效性,如果转换失败,则转换表达式返回NULL.一般用在多态对象类型的强制转换.
				dynamic作用,换了指针后,会能调用对应派生类D的一些独有的成员g的目的,如 dynamic_cast<D*>(pb)->g();且该语句不影响原来的指针的类型,就是pb还是不变. 且只用于父子带虚函数类型的指针或引用. 
				微软C/C++编译器命令行模式用法 微软C/C++编译器编译选项数目众多命令提示符窗口键入cl /?即查看完整列表(见附录1)比说/GX启用C++异常处理机制/GR启用C++ RTTI等等此打算详细讨论些编译选项用法
				在vs2003中,项目右键属性/c-c++/命令行/附加选项/填上/GR  (YANGYANG支招百度关键字:  打开 RTTI)
				
				//关于dynamic_cast强制运行时转换,也就是父子类指针转换
				/*
				class Base1
				{
				public:
				    //virtual void f(void){cout<<"BASE1 _f()"<<endl;}
				    virtual void f(void)=0;
				};
				class Base2
				{

				};

				class Device:public Base1
				{
				public:
				    void f(void){cout<<"DEVICE _f()"<<endl;}
				};

				int main_dynamic_cast()
				{
				    try
				    {
					Device d,*pt;
					//1创建Device对象; 2隐式this转化成Base1类指针类型, 虽this本质Device对象表面上依Base1类型指针
					Base1 *b1 = new Device; //or Base *b1 = &d;
					
					//显示转化的时候,编译器认为用户企图将继承类的指针指向基类Device的对象,如果命令行不填上/GR,就是不打开RTTI,那么可能会导致
					//构造函数无法正常初始化继承类的成员, 所以要打开RTTI选项,RTTI可以把基类的指针或者引用安全的转化成继承类的指针或引用
					//(/GX启用C++异常处理机制/GR启用C++ RTTI)
					//dynamic作用,换了指针后,会能调用对应派生类D的一些独有的成员g的目的,如 dynamic_cast<D*>(pb)->g();且该语句不影响原来的指针的类型,就是pb还是不变
					if((pt = dynamic_cast<Device*>(b1))!=NULL)
					{
					    //指向Device,转换后
					    cout<<"dynamic_cast Device* successful!,the type is:"<<typeid(pt).name()<<endl;   //typeid().name可以知道现在指针指向哪个,招数
					    pt->f();
					}
					
					else
					    throw 1;

				    }
				    catch (int i) //Bad_cast不好用
				    {
					cout<<"dynamic_cast FAILED_"<<i<<endl;
					exit(1);
				    }
				    catch (...)
				    {
					cout<<"the other Excepiton handler error"<<endl;
				    }

				    return 0;
				}*/

			c)重释强制转换 reinterpret_cast<type>(object) #interpret为解释,说明,翻译的意思  L1521
				可以把一种类型转化成根本不同或不相容的类型.如X类的指针转换成int指针. 所以对程序可读性有影响.不是绝对需要,就别用它.
				reinterpret_cast主要是将数据从一种类型的转换为另一种类型。所谓“通常为操作数的位模式提供较低层的重新解释”也就是说将数据以二进制存在形式的重新解释.

				//reinterpret重新解释的强制转换   char*指针字符串转成int,  16位机器转换得到T, 32为机器得到Th (i逐位计算)
				int main()
				{
				    int *i;
				    char* pt = "TT";
				    i = reinterpret_cast<int*>(pt);
				    cout<<"reinterpret_cast char* to int: "<<*i<<endl;   //pt为"T",  *i为84 // TT的话为21588

				    int j = 'T';
				    cout<<j<<endl;  //84
				    return 0;
				}

				int *pi = &i; //pi--> 4位的int
				double *pd = reinterpret_cast<double*>(pi);  //也会失败,和static,或者c风格转换一样,内存长度4--->8就是乱,*pd写入,更是直接报错.

				这个运算符少用为好.
				
			d)静态强制转换 static_cast<type>(object)
				能够执行非多态强制转换,就是说能够把基类指针强制转换成派生类指针. 还能整形-->枚举.
				static_cast<T>(arg) T为指针,引用,枚举,数学类型.  arg必须和T类型相符.
				C++中的static_cast执行非多态的转换,用于代替C中通常的转换操作。因此,被做为显式类型转换使用.
				float f = 166.71f;
				int i = static_cast<int>(f); //166

				//继承类中的static_cast,也就是父子类指针转换
				class Base
				{
				    virtual void f(){cout<<"V_base()"<<endl;}
				};

				//虚基类的基本原则是在内存中只有基类成员的一份拷贝.
				//在继承中产生歧义的原因有可能是继承类继承了基类多次,从而产生了多个拷贝,即不止一次的通过多个路径继承类在内存中创建了基类成员的多份拷贝。
				//class Device:virtual Base   //Base不准为虚基类 error,
				class Device:public Base
				{
				    virtual void f(){cout<<"V_device()"<<endl;}
				};

				int main()
				{
				    Device d,*dd;
				    Base *b = &d;
				    dd = static_cast<Device*>(b);       //不想要/GR,但要保证无二义性(因为没有动态类型检查),这是下行.						//如果上行(把派生类指针或引用转换成基类表示)是安全的
				    cout<<typeid(dd).name()<<endl;

				    return 0;
				}

				static_cast转换没有安全保障的,那么用它是为了什么呢, 转换中,避免类型检查的开销? 
				dymanic_cast转化通常被称为类层次的动态导航,static_cast为常可用于类层次的静态导航,无映射变换,窄化变换(会丢失信息)等,前者安全,后者比较快,所以后者有限制:
					存在继承类到base的无二义的转换  &&   base类不是虚基类(就是继承时关键字不能是virtual)
					其他int->枚举, float-->int等, 会造成精度问题缺点吧.
					所以父子类指针转换用dynmic比较安全,受限少. static_cast在指针方面转换较差,不安全.(普通指针转化, T和arg必须一致,所以没啥意义),父子转换又不如dynmic,只有用在普通基础类型转换了. 
				总结就是:
					1)上下行 (下行不安全,要保证无二义性条件)
					2)基础数据类型转换,int--char,int---enum(程序员自己保证安全)
					3)任何类型的表达式转化成void(常用)
					4)NULL===>NULL,没啥用
					5)不能不相关的两个类对象转换,本质上c语言强制转换的替代品.
				

				 //进一步深刻剖析转换
				    int i = 10;
				    double j = 55,*pj=&j;
				    cout<<sizeof(i)<<"    "<<sizeof(j)<<endl;   //4  8   (32位机)

				    int *pi = &i; //pi--> 4位的int
				    //double *pd = reinterpret_cast<double*>(pi); 不行
				    double *pd = static_cast<double*>(pi);  //编译时会告诉你int*无法转化为double*,因为arg类型必须也T类型一致   static_cast<T>(arg)
				    //double *pd = (double*)pi; //告诉编译器把指针指向地址后sizeof(double)字节内存当作pd对象来解析,但是以前i只有4位,这个时候的pd访问时已经不安全,为乱码,容易非法访问内存,乱码,但能正常运行
				    
				    *pd = 1;  //这里不重新赋值,i,pi都还正常,pd为乱的,如果这里再对pd进行了重新赋值,为1.0000...(16个0),超出了int i的范围, *pi也修改了i, 那么i会发生内存写失败.debug错误,运行失败
						//这就是c风格类型转换.不安全.
				    cout<<"i:"<<i<<endl;    //10
				    cout<<"pi:"<<*pi<<endl; //10
				    cout<<"pd:"<<*pd<<endl; //-0.925e+61
				    return 0;



		8, 名字空间
		    
		    1)来自2个空间的j不能同时都using,会重复定义,除非第二个你用using namespace 全局, 那么里面的j就是这个全局的了. 直至碰到第二个的using namespace;
		    2)第二个using namespace全局后, j就变成了hello 的j 
			hello.h###################
			#include "hello.h"
			using namespace hello;
			//
			int j = 10; //定义
			testClass::testClass()
			{
			   i=10; 
			}

			int kgk = 20;

			hello.cpp##########
			#include "hello.h"
			namespace hello 
			{
			    extern int j;   //这样定义, 在test.cpp的main中,无法用hello::j定位使用. 
					     //在namespace,定义一个变量,用extern常规方法不能规避j在其他地方定义好后,仍旧无法使用hello::j的问题,只能放它进struct&class
			    const int p = 19;      //const可以可以
			    
			    class testClass
			    {
			    public:
				int i;
				testClass();
			    };

			    enum ABC            //可以
			    {
				A,
				B,
				C
			    };

			    typedef struct s_AB
			    {
				static const int a = 20;    //必须同时为const和static的才能直接初始化,(类/struct中)
				// const int b = 30;
				// static long c = 40.0;
				//int r=10;
				int q;
				void init()
				{
				    q = 90;
				}
			    }SS; //这个要引入新函数,或者直接用 , 美吧
				// typedef struct s_AB
				// {
				//    int q;
				// }SS(90);

			}

			extern int kgk; //表示变量或者函数的定义在别的文件,这里只是个声明,那么被多个文件include这个.h, 这个变量避免出现重复定义的编译错误
			class c2
			{
			    int kk;
			};

			
			test.h##########
			
			namespace test
			{
			    int kj=1;
			}

			主体test.cpp###########  当然要include2个.h文件
			void testM()
			{
			    using hello::j;
			    cout<<j<<endl; //9
			    using namespace hello;
			    j = 5;
			    cout<<j<<endl; //5
			}

			int main()
			{
			    using test::kj;  
			    //using hello::j; //重复定义
			    cout<<kj<<endl;
			    testM();
			    using namespace test;
			    cout<<kj<<endl;

			    using namespace hello;
			    //cout<<j<<endl; //无法解析hello::j,所以普通变量不能独立声明在namespace中,
					    //要包在struct或者类中(除非没有超过2个include包含,比如这个包含main的test.cpp直接包含test.h就可以,
					    //如果有其他文件包含test.h,就会造成变量重复定义,加上extern的话,用test::kg又是无法解析)
			    testClass tt;
			    cout<<"hello.i: "<<tt.i<<endl;
			    cout<<"hello.p: "<<p<<endl; //由于p是const类型的,所以可以从hello.h 中用过来
			    cout<<"hello.enum_A: "<<A<<endl;
			    cout<<"hello.enum_B: "<<B<<endl;
			    SS s;
			    s.init();
			    //cout<<"hello.struct_intQ: "<<s.r<<endl;//只有常数,静态整形数据成员才能在类和结构中初始化. 其他需要在函数中,构造中初始化
			    cout<<"hello.struct_intQ: "<<s.q<<endl;
			    cout<<"hello.struct_intQ: "<<s.a<<endl;
			    return 0;
			}

			
			进一步深刻剖析 ###################
			1)
			namespace T1
			{
			    int i = 15;
			    int j = 16;
			    int k = 17;
			    int testT(int k)
			    {
				//std::cout<<k<<endl;//不能使用其他name的,这个可以,它在T1的函数里,就可以.
				return k;
			    }
			}
			namespace T2
			{
			    int i = 25;
			    int j = 26;
			    
			    //std::cout<<i<<endl;  //在name中不能使用其他的
			    //using T1::testT; ////在name主体中不能使用其他的,函数中可以
			    //using T1::k; //没意义, 因为using后,你不能在下面对值进行使用, namespace里,只有函数可以使用变量,外面使用都是重新定义
			    //T1::k = 5;  //重定义
			    //i = 5;  //在namespace中, 这样属于重定义,算再次初始化,在name中出错.; 除非在函数中.不然会报错
			    int testT(int k)
			    {   
				using std::cout;
				cout<<"testT: "<<k<<endl;//不能使用其他name的,这个可以,它在T1的函数里,就可以.
				return k;
			    }
			    void testM()
			    {
				//using namespace T1;   //在space中再用namespace是无用
				using T1::i;    //有用,下面的i为T1的了,但是必须在T2的函数内
				std::cout<<i<<endl; //默认这个指向是T2的i,除非写成T1::i,或者上面有using T1::i;. 说明这个函数中, using namespace T1没用
			    }
			}

			void testC()
			{
			    using namespace T1;//在普通函数中,有用.
			    cout<<"in testC,namespace_T1:i "<<i<<endl; //15
			    using T2::i;
			    cout<<"in testC,using T2::i "<<i<<endl;  //25
			}
			int main()
			{
			    using T1::testT;
			    testT(5);
			    using namespace T1;
			    cout<<"T1:i: "<<i<<endl;
			    using T2::i;    //声明了变量i, 不能再声明其他的i了,除非用全局using namespace T3;
			    cout<<"T2:i: "<<i<<endl;
			    cout<<"T1:j: "<<j<<endl;    //由于T1到这里之间没有其他namespace,所以这个j还是T1的
			    using T2::testM;
			    cout<<"testM(): ";
			    testM();
			    //函数中使用using namespace问题(没问题)
			    testC();

			    //重复问题
			    using std::cout;  //可以, 虽然上面有对std的namespace,但是没有单独定义过cout,不算重复,(没问题)
			    cout<<"";  
			    return 0;
			}

			
		9, mutable修饰符 , 只适合用于const member function函数,规定了类成员不能在这个函数中修改.  但是加mutable的成员,可以在这个成员函数中进行修改. 带来的坏处是不容易跟踪.
		下面实例总结:
			1)在M1中,用const限制修改类成员,但是i和ppt都能修改,因为有mutable
			2)ppt中的*在const后,所以它是const目标对象.就是对象不能通过指针来修改,但是指针不是const,所以ppt能够修改,可以重新指向其他
			3)const int pt; 是const int, 它的定义必须在构造函数的初始化列表中进行.用法是tt3():pt(20)这样子的.(或者自定义函数??)
			4)没有mutable const int pt这种类型.
			5)int*p ; 如果p不new , 也不=&其他变量, 那么*p是违法的.

		//mutable
		class tt3
		{
		public:
		     mutable int i;
		     int j;
		     //mutable const int pt;//非法存储类型
		     //const int pt = 20;   //pt” : 只有常数静态整型数据成员才可以在类或结构中初始化
		     
		     const int pt;
		     mutable const int* ppt;
		     //tt3(){pt = 20;}      //在构造函数里进行pt赋值不行,必须在设定项列表进行初始化const
		     tt3():pt(20)
		     {
			 //*ppt = 50;  都没指向定义在哪块内存空间,怎么能直接*ppt赋值呢
		     }   

		     

		     void M1(int k) const       //函数后加个const表示函数内不准对类成员做任何改动. (但是加了mutable,却能突破这个限制)
		     {
			i = k;               //没问题,500 ,i可以修改
			//j = 50;            //不能修改成员数据
			ppt = &k;            //ppt也能修改了
			//pt = k;            //不能修改
			cout<<*(ppt)<<endl;
		     }
			  
		};
		int main()
		{
		   tt3 t;
		   t.i =50;
		   //*(t.ppt) = 150; //不能修改,因为这个指针是const的, 这个和mutable无关的限制

		   cout<<t.i<<endl;                     
		   cout<<t.pt<<endl;
		   //cout<<*(t.ppt)<<endl;
		    
		   t.M1(500);
		   cout<<t.i<<endl;
		   int k = 600;
		   t.ppt = &k;  //修改成功,不能用  *t.ppt = 600来改. 看下面的关于 const*和 *const对指针的使用
		   cout<<*(t.ppt)<<endl;

		   //const修饰对象还是修饰指针,在于*在const前后的关系, *在前,表示int* const,修饰的是指针.  const int*,或者 int const* 都是修饰的对象
		   int kk = 700;
		   const int *p = &kk; //(const对象)
		   //*p = 800; 那么就不能通过指针来修改对象, 当然直接kk =800是可以的, 但是那和指针无关
		   p = &k;  //(那么可以修改指针p,让他重新指向600的空间)
		   cout<<*p<<endl;   

		   int *const pp = &kk;//(const指针,就是pp指针不能再指向其他,那么对象是可以变的,就是通过*pp可以修改对象的值)
		   *pp = 800; 
		   cout<<*pp<<endl;  
		    

		   return 0;
		}
记录2个内核网站 嵌入式开发
http://www.kerneltravel.net/
http://www.kernel.org
中断, uboot 嵌入式开发
9 中断体系结构   书本59页有ATPCS中各个寄存器的使用规则和名称, 如PC,SP,LR等  , LR是连接寄存器,
9.1 2410/2440中断体系结构
   9.11 cpu的7种工作模式	
	用户模式,快速中断模式,中断模式, 管理模式 .... 
	
	每个工作模式都有16个通用寄存器和 1/2个程序状态寄存器. r0 - r15 +CPSR/CPSR+SPSR  (用户模式下只有cpsr)
	
	每个工作模式有不同的权限和不同的触发条件,不同的寄存器(备份寄存器)
	
	异常发生时,切换相应的工作模式, 相应的动作 1234
	
	从异常工作模式退回到之前的工作模式,也要有相应的动作  1 2

	中断是一种异常.  发生了异常,cpu会进入异常中断模式,切换寄存器,pc指针=异常入口,
   
   9.12 2410/2440中断控制器
	cpu运行时,通过查询方式/中断方式来知道各种外设发生了哪些不预期的事件,如插入usb,串口接收到了新数据,按键动作等
	然后就是中断处理工作 12345.
		1)中断控制器汇集各外设信息的信号,然后告诉CPU
		2)cpu保存当前运行环境(保存寄存器),然后调用ISR(interupt service routine)来处理中断.
		3)在ISR中,读取中断控制器和外设的相关寄存器的信息判断是何种中断,并处理之
		4)清除中断 (读写中断控制器和外设寄存器)来清理
		5)恢复运行环境到中断前
	通过中断控制器内部结构,剖析中断处理过程,对中断处理过程进行详细剖析.

   9.13 中断控制器寄存器
	SUBSRCPND INTSUBMSK
	SRCPND INTMSK
	INTMOD
	PRIORITY
	INTPND
	INTOOFFSET

   9.14 实例
	head.S : 异常向量,
	
	PS: ARM中断返回SUB pc lr-irq #4,为什么lr-irq要减去4呢
		因ARM指令三级流水线说取指译指执行时同时执行 样说吧现PC指向正取指地址cpu正译指指令地址PC-4(假设ARM状态下指令占4字节),
		cpu正执行的指令地址PC-8.也说PC所指向的地址和现在cpu所执行的指令地址相差8. 当突发生断时候,保存的是PC地址, 这样你就知道了如果返回的时候返回PC,那么中间就有1个指令没有执行.   
		所以用SUB pc lr-irq #4,   [ sub lr lr #4 也是这个意思??]
	    SP:栈寄存器,它始终是指向栈顶.  sp实际上也就是一个指针而已,它始终是指向栈顶。如果是8088/8086系列,压栈操作sp就减2,同时把要压栈的数据复制到sp所指的两个单元里。这个时候的栈顶因为sp减了2,因此上移了两个单元,sp还是指向新的栈顶。
	    pc程序指针指向当前正执行指令地址单元,pc值随着指令执行而变化,一般不会是最大地址值

	    lr连接寄存器,LInk Register,在Arm体系中他有2个用途: 1)用来保存子程序返回地址.2)当发生异常时,LR保存的值等于异常发生时PC的值减去4(2 这是16位ARM),因此在各种异常模式下可以根据LR的值返回到异常发生前的相应位置继续执行.

10 UBOOT
   BootlLoader
	1, 首先介绍bootlLoader,  启动方式(自动加载模式,用户交互下载模式)
	2, Bootloader的2个阶段
		1)完成一些依赖于cpu体系结构的初始化.并调用第二阶段的代码   (汇编阶段)
			a)硬件设备初始化 (不是必须)
			b)为第二阶段代码准备Ram空间 (不是必须)
			c)复制bootloader的第二阶段的代码到Ram空间去
			d)设置好栈
			e)跳转到第二阶段代码的c入口点
		2)内核阶段  (C阶段)
			a)初始化本阶段要使用到的硬件设备   (至少初始化一个串口,方便程序员和BootLoader之间交互)
			b)检测系统内存映射
			c)将内核映像和根文件系统映像从Flash中读到RAM空间中
			d)为内核设置启动参数
			e)调用内核
				// 调用内核前,下列条件要满足
				a)cpu寄存器的设置. 
				b)cpu工作模式
				c)cache和mmu设置
			
	3, BootLoader和内核的交互
		a)BT和内核不能同时运行, BT与内核的交互是单向,
		b)BT把参数放到约定的某个地方,然后再启动内核,内核启动后从这个地方取得这些参数
		c)除了参数的存放的地址外. linxu2.4.x后,都是用标记列表来规定参数的结构,标记就是一种数据结构,标记列表是挨个放的多个标记.  以ATAG_CORE开始, ATAG_NONE结束
		d)标记的数据结构是tag. 由一个tag_header和一个union组成,  tag_header结构包含标记的size和tag类型, 对应tag是内存,还是命令行等
			struct tag_header {
				u32 size;
				u32 tag;
			};

			struct tag_mem32 {
				u32	size;
				u32	start;	/* physical start address */
			};

			struct tag_cmdline {
				char	cmdline[1];	/* this is the minimum size */
			};

			struct tag {
				struct tag_header hdr;
				union {
					struct tag_core core;
					struct tag_mem_range mem_range;
					struct tag_cmdline cmdline;
					struct tag_clock clock;
					struct tag_ethernet ethernet;
				} u;
			};
		e)以设置内存标记和命令行标记为例   P260 1,2,3,4 
			1)首先定义ATAG_CORE 
			2)然后 mem/cmd
			3)ATAG_NONE

			
		f)通用BT介绍
			X86上的LiLO,GRUB,   ARM的U-BOOT,VIVI(三星的,初始版本只支持串口下载交互,较慢),  UBOOT支持大多cpu,可以少些EXT2,JFFS2文件系统映像,支持串口/网络下载,提供很多的命令交互,使用复杂,但是更好的调试.

  U-Boot
	1,Universal Boot Loader, 通用的意思,是它的代码结构容易增加其他类型的开发板,多种架构的CPU,可以引导多种操作系统,
	2,有以下特性
		开放源码
		支持多种嵌入式操作系统内核
		.. 多个处理器系列
		较高可靠性,稳定性
		高度灵活的功能设置,适合u-boot调试,操作系统的不同引导要求\产品发布等
		丰富的设备驱动源码,如串口,以太网,SDRAM,FLASH ,LCD,NVRAM,EEPROM,RTC,键盘
		强大开发调试文档,网络技术支持
		支持NFS挂载,RAMDISK(压缩或非压缩)形式的根文件系统
		支持NFS挂载,从Flash中引导压缩或非压缩系统内核
		可灵活设置,传递多个参数给操作系统,适合系统在不同开发阶段的调试要求与产品发布, 尤其是对linux系统
		支持目标板环境变量的多种存储方式,如Flash,NVRAM,EEPROM
		CRC32校验,可以校验Flash中内核和RAMDISK镜像文件是否完好
		上电自检功能,SDRAM/FLASH大小自动检测,SDRAM故障检测,cpu型号检测
		XIP内核引导
	3,U-Boot-1.1.6包含26个子目录, 主要分为4类
		1)1,2,3,4
		2)目录说明 
			board
			cpu
			lib_i386
			include
			lib_generic
			common
			disk
			drivers
			dtt
			fs
			nand_spl
			net
			post
			rtc
			doc
			examples
			tools
嵌入式基础学习 嵌入式开发
linux内核完全注释

4. 80X86保护模式及其编程
  4.1 80X86系统寄存器和系统指令
    1)标志寄存器
    2)内存管理寄存器
    3)控制寄存器
    4)系统指令
  4.2 保护模式和系统管理
    1)内存寻址
    2)地址变换 (分段机制和分页机制)
    3)保护
	1)
  4.3 分段机制
	
  4.4 分页机制

  4.5 保护

  4.6 中断和异常处理

  4.7 任务管理

  4.8 保护模式编程的初始化

  4.7 一个简单的多任务内核例子



linux的内核就是对硬件资源的抽象和访问调度.


加油.  重新复习80X86

看了韦东山的路线介绍之后,开始看他的嵌入式应用开发完全手册, 但是有些章节无法掌握, 介绍太少, ARM体系结构与编程,这个不错.

2章 ARM体系结构与编程
	2.1,arm指令
	  1),arm指令的分类:
	  跳转指令,数据处理指令,程序状态寄存器(PSR)传输指令,LOAD/STORE指令,协处理器指令,异常中断产生指令.
	  2),arm指令的一般编码格式:
	  cond(32:28),001(27:25),opcode(24:21),S,Rn(19:16),Rd(15:12),shift_operand(11:0)
	  指令执行的条件编码
			       指令操作符编码
					    决定指令的操作是否影响CPSR	
						包含一个操作符的寄存器编码
							目标寄存器编码
								  两个操作数
	  3),arm指令的条件码域, 条件吗是4为开头的条件码,根据CPSR中的条件标志位决定是否执行该指令.
		如果不满足, 该指令就被当做一条NOP指令,这时处理器进行判断终端请求等操作,然后转向下一条指令.
		一共有16个条件码,可以在其助记符的扩展域加上条件码助记符. 
		如条件吗0000, 助记符是EQ, CPSR条件标志位置是  Z=1
	2.2,arm寻址方式
		数据处理指令的操作数的寻址方式,字及无符号字节的Load/Store指令的寻址方式
		杂类Load/Store指令的寻址方式,批量Load/Store指令的寻址方式,协处理Load/Store指令的寻址方式

	  1),数据处理指令的操作数的寻址方式
	  2),
	  3),

 3章 arm指令集
	跳转指令:  跳转,向pc寄存器写入目标地址值	;  B,BL,BLX,BX
	数据处理指令: 

 4章 arm汇编语言程序设计
	1, 伪操作
		汇编源程序有汇编指令+伪操作+宏指令组成.  伪操作不像机器指令那样在计算机运行期由机器运行,而是在汇编程序对源程序汇编期间由汇编程序处理的.
		1)符号定义伪操作
			用于定义ARM汇编程序中的变量,对变量进行赋值以及定义寄存器名称
			GBLA,GBLL,GBLS声明全局变量
			LCLA,LCLL,LCLS声明局部变量
			SETA,SETL,SETS给变量赋值
			RLIST 为通用寄存器列表定义名称
			CN  为协处理器的寄存器定义名称
			CP  为协处理器定义名称
			DN及SN  为VFP的寄存器定义名称
			FN  为FPA的浮点寄存器定义名称
		2)数据定义伪操作
			LTORG 声明一个数据缓冲池的开始
			MAP 定义一个结构化的内存表的首地址
			FIELD 定义结构化的内存表中的一个数据域
			SPACE 分配一块内存单元,并用0初始化
			DCB 分配一段字节的内存单元,并用指定的数据初始化
			DCD及DCDU 分配一段字的内存单元,并用指定的数据初始化
			DCDO 分配一段字的内存单元,并将一个单元的内容初始化成该单元相对于静态基址寄存器的偏移量
			DCFD及DCFDU 分配一段双字的内存单元,并用双精度的浮点数据初始化
			DCFS及DCFSU 分配一段字的内存单元,并用双精度的浮点数据初始化
			DCI 分配一段字节的内存单元,用指定的数据初始化,指定内存单元中存放的是代码,而不是数据
			DCQ及DCQU 分配一段双字的内存单元,并用64位的整数数据初始化
			DCW及DCWU 分配一段半字的内存单元,并用指定的数据初始化
			DATA 在代码段中使用数据,现在不再使用,仅用于保持向前兼容
		3)汇编控制伪操作
			IF ELSE ENDIF
			WHILE WEND
			MACRO MEND
			MEXIT
		4)框架描述伪操作			
		5)信息报告伪操作
			ASSERT,INFO,OPT,TTL,SUBT
		6)其他伪操作, (杂类伪操作)
			ALIGN
			AREA
			CODE16 CODE32
			END 
			ENTYR
			EQU
			EXPORT,GLOBAL
			EXTERN
			GET, INCLUDE
			IMPORT
			INCBIN
			KEEP
			NOFP
			REQUIRE
			REQUIRE8,REQUIREVE8
			RN
			ROUT
	2, ARM汇编语言伪指令
		包括ADR,ADRL,LDR,NOP	
		ADR,小范围的地址读取伪指令
		ADRL,中等范围*****
		LDR,大范围*****
		NOP,空操作, 替换成arm中的空操作,不影响CPSR标志位
	3, ARM汇编语言语句格式	{符号} {伪操作} {伪指令} {;注释}
		符号:
			变量,
			数字常量,
			标号,
			局部标号
		
		ARM语言中的表达式:
			由符号,数值,单目或多目操作符以及括号组成. (括号>单目(右左)>双目(左右))
			1)字符串表达式,长度在[0,512字节],由字符串,字符串变量,操作符和括号组成. 
				字符串, abc SETS "hello "" you "" &&a"
				字符串变量,GBLS和LCLS声明,SETS赋值
				操作符,LEN,CHR,STR,LEFT,RIGHT,CC,  由 : :隔开,  如
				例子:
				GBLS STR1
				GBLS STR2
				STR1 SETS"hello"
				STR2 SETS"world":CC:(STR2:LEFT:3) 
			2)数字表达式
				整数数字量
				浮点数字量
				数字变量
				操作符
			3)基于寄存器和基于PC的表达式
				基于寄存器表达式表示了某个寄存器的值加上/减去一个数字表达式  
					BASE返回基于寄存器表达式中的寄存器编号  :BASE: A
					INDEX返回基于寄存器表达式相当于其基址寄存器的偏移量 :INDEX: A
				基于PC的表达式表示了PC寄存器加减一个数字表达式, 如
					+/-A, 
			4)逻辑表达式
				逻辑量 ,关系操作符,逻辑操作符以及括号组成.
				关系操作符的逻辑量是 数字表达式,字符串表达式,基于寄存器或者PC的表达式之间的操作, 如=,/=,<>, >,>=,<,<=
				逻辑操作符的逻辑两是两个逻辑表达式, :LNOT:, :LAND:, :LOR:,:LEOR:.
			5)其他表达式
				?A 返回定义符号A的代码所产生的可执行代码的字节数
				DEF 判断某个符号是否已经定义
				SB_OFFSET_19_12
				SB_OFFSET_11_0

韦东山开发完全手册

3.3 常用ARM汇编指令
	1,相对跳转 B, BL
	2,数据传输mov, 地址读取伪指令LDR
	3,内存访问指令LDR,STR,LDM,STM
	4,加减指令 ADD, SUB
	5,程序状态寄存器的访问指令 MSR, MRS
	6,其他伪指令 .extern, .text, .global, 
	7,汇编指令的条件执行 
3.4 ARM-THUMB子程序调用规则 ATPCS
	让c程序和汇编程序之间互相调用而制定的调用规则,包括寄存器使用规则,数据栈使用规则,参数传递规则

		
linux内核完全注释 嵌入式开发
linux内核完全注释

4. 80X86保护模式及其编程
  4.1 80X86系统寄存器和系统指令
    1)标志寄存器
    2)内存管理寄存器
    3)控制寄存器
    4)系统指令
  4.2 保护模式和系统管理
    1)内存寻址
    2)地址变换 (分段机制和分页机制)
    3)保护
	1)
  4.3 分段机制
	
  4.4 分页机制

  4.5 保护

  4.6 中断和异常处理

  4.7 任务管理

  4.8 保护模式编程的初始化

  4.7 一个简单的多任务内核例子



linux的内核就是对硬件资源的抽象和访问调度.
ststr
//大全 新方法
char* Strstr(const char* str,const char* sub)
{
	int i,j;
	for(i,*str,i++)
		for(j=i,k=0;str[j]==sub[k];j++,k++)
		{	判断sub下一个元素为0么
			是 return str+i
		}否,就继续for遍历下一个要相等,不等的话回到for1,一定要for2遍历完到sub[k]结束才能return str+i,
		如果for1结束了, for2中还没有出现sub[k]到结束, 说明for2的sub中么有和str完全嵌入的子字符
	结束for1, return NULL
	
 }


int main()
{
    char str[64] = "helloworld";
    char subStr[] = "ow";     //输出oworld,   he输出helloworld, 相当于字串在str的位置,并把后面的全都列出 //如果没有就输出NULL,没法cout了
    //cout<<"strstr: "<<strstr(str,subStr)<<endl;
    cout<<"strstr: "<<Strstr(str,subStr)<<endl;
    return 0;
}
*/

//获取一个子串出现的次数 strstr_cnt(const char* ,const char*)

/*int _strstr_cnt(const char* str,const char* sub)伪代码
{
    //wohawoha      ha
    for(i;str[i];i+)
    {
        for(j=i,k=0;str[j]==sub[k];j,k+)
        {
            //不等就for2;
            //相等了,就在str中遍历完sub,然后看后面还有没有sub
        
            if(!sub[k+1])如果for2到sub结束,那么count加一次
            count++;
            break
        }
     } 
}*/

/*
int testFor(char* str)
{
    for(int i=0;i<3;i++)// i++后, 在和i<3比较,不是先比较, 再++
    {
        str[i];
    }
    return 0;
}

int strstr_cnt(const char* str,const char* sub)
{
    int i,j,k,count=0;
    //for(i=0;*str;i++)// 这样*str无法结束, 因为没有str++,如果加上str++,那么i就无法准确定位了
    for(i=0;str[i];i++)
    {
        for(j=i,k=0;str[j] == sub[k];j++,k++)
        {
            if(!sub[k+1])   //这个必续sub K+1,不然sub最后一个元素了,上面就不等了
            {
                count++;
                break;
            }
        }
        
    }
    return count;
}

int main()
{
    char str[64] = "wohahahahe";
    char sub[8] = "ha";
    cout<<"strstr_cnt: "<<strstr_cnt(str,sub)<<endl;
    //testFor(str);
    return 0;
}*/

//194 获取字串在字符串中的最右端出现的指针  char* r_strstr(const char* ,const char*) //hellowoo    wo
char* r_strstr(const char* str ,const char* sub)
{
    //sub和str都倒序
    //查询str和sub相同的地方
    //strstr的倒写
    assert((strlen(str)>0)&&(strlen(sub)>0));
    char* ti = (char*)str;
    char* tj = (char*)sub;
    int k;
    int i = strlen(str)-1;
    int j = strlen(sub)-1;
    for(;i>=0;i--)
    {
       /* for(k=i;sub[j] == str[k];j--,k--)
        ;
        if(j<0)
            return ti+i;*/
        //下面的也行
        for(k=i;sub[j] == str[k];j--,k--)
        {
            if(j==0)
                return ti+i-1;
        }
    }   
    return NULL;
}
const char* r_strstr2(const char* s1,const char* s2)
{
    int i,j,k,left =0;
    for(i=0;s1[i];i++)
        for(j=i,k=0;s1[j]==s2[k];j++,k++)
            if(!s2[k+1])
                left = i;
    return ((left)?s1+left:NULL);
}

int main()
{
    char str[64] = "helloowowowbaba";
    char sub[8] = "wo";
    cout<<r_strstr(str,sub)<<endl;
    cout<<r_strstr2(str,sub)<<endl;
    return 0;
}
c++大全笔记(字符串)
大全目录
1 c语言入门
2 宏与常量  ※69
3 字符串 ※81
4 函数	※107
5 键盘操作
6 数学
7 文件,目录和磁盘	※178
8 数组,指针和结构	※245
9 DOS和BIOS服务
10 内存管理	※336
11 日期和时间
12 重定向I/O和进程命令行
13 编程工具
14 高级C语言编程	※392

15 C++入门
16 对象	※
17 常见的类函数	※484
18 用C++输入和输出
19 继承和多态性	※565
20 通用函数和模板
21 异常处理和类型转换
22 创建可重用的类
23 标准模板库	※671
24 Windows
※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※
2 宏与常量(大全)
	133 编译程序前,预处理器先运行,目的是包含指定的头文件并扩展宏和常量.
	135 输出属性
		_FILE_判断当前文件的名称, 如printf("file name is %s",_FILE_);
		_LINE_当前源文件的当前行号,如printf("now reach line is %d",_LINE_);
	    如果想让编译器到某处停止,不继续执行下去,比如修改了代码,让其他程序员注意到这行,故意让这块出错 #error i have a error here(后面话自编).
	141 判读是否是ANSI C编译
		编译器比较多,有时用户需要现在的编译器是否是ANSI C编译器, 用#ifdef _STDC_判断,是了就yes
		同理判断c++的是  #ifdef _cplusplus, 
	143 取消宏或常量
		宏定义一个常量后,如果后面要重新定义,那么一般编译器都会显示一条告警信息 ,可以用#undef来取消宏, 然后再重定义就不告警了
		#undef _TOPKING
		#undef _TOPKING(c) ((((c)>='a')&&((c<'z'))?(c)-'a'+'A':0) (不带分号);
		#undef _TOPKING(c) ((((c)>='a')&&((c<'z'))\
		?(c)-'a'+'A':0)	//一行写不满,换行符 \
	144 宏和函数的区别, 前者注重速度快捷,(但如果一个文件调用宏常量N次, 那么就要替换N次,增加执行程序的规模)
		后者是调用函数的代码,程序很小(调用),但是调用程序需要占用额外的处理,比执行宏时所用操作和时间长.
	145 预处理命令 #define,#include,#undef ,#pragma( #pragma startup getA() ,  #pragma exit closeA(), 一般加上startup表示在main之前自动运行的函数,exit为结束时自动运行的函数, exit要注意,必须不能带参数的函数才行.)  #include表示包含的预处理,一般在头文件中.
		
	147 创建用户自己的头文件
		c编译器提供不同的头文件,之中包含不同的宏常量,函数原型, 随着用户常见程序数量的增加,有可能出现同名的常量和宏, 与其重复使用这些重复的宏,常量,不如自己创建自己的头文件,把宏常量放到文件中. 如
		系统头文件, 用<>,自己目录用""(只搜索当前子目录),而<>的文件,用户首先去头文件子目录搜索,再搜索当前子目录或者用户指定子目录.
	149 判断是否使用以及if-else处理
		#ifdef ....
			nnnnn
		#endif	//如果ifdef已定义,执行后面的语句,直到执行endif

		#ifndef
			nnnn
		#endif //同理是??未定义,执行后面的, 后面的可以是其他预处理命令,定义.#include包含操作等.

		进行if-else预处理
			#ifdef
				nnn
			#else
				nnn
			#endif
		#if更强大,可以进行组合判断 #if define(symbo)
			#if define(MY_DEFINE) && !define(MY_OTHER)
				NNNNN
			#else if define(....)
				nnnn
			#else
				nnnn
			#endif
	154 自定义宏
		#define SUM(x,y) ((x)+(y))	//当值传给宏时,预处理器将宏参数进行替换,//作为规则,一定要把宏参数使用时,放到括号中 (x),(y)
		注意SUM和(x,y)之间不能有空格,不然预处理器会把(x,y)当成后面要用的.
		注意宏参数类型, 上面x,y不限类型,如果 #define SUM(int x,int y) ((x)+(y))会报错, 因为宏没有参数类型.

3  字符串(大全)
	161 计算机用一个字节的内存来存储单个的ANSII字符,那么字符串就是一系列的ANSII字符,自动分配NULL(\0)字符来结尾.
	int main()
	{
	    char ch[64] = "hello";
	    cout<<"ch[0]: "<<ch[0]<<" and ch[63]: "<<ch[63]<<" and chAll: "<<ch<<endl;  //h (无) hello
	    cout<<"size of ch: "<<sizeof(ch)<<endl;					//64 站位64,但是在内存存储时是只有33个字节有效,后面											//的是未使用的.
	    return 0;
	}
	正常使用字符串时,分配"nnn",给一个字符串,它自动用NULL结束. 如果用for遍历给ch中添加char, 那么要在for结束后,手工添加NULL,如
	char ch[64]; for(i-20) ch[i]=i; 结束for后, 让ch[i]=NULL;
	还有从键盘获取输入到ch的 gets和fgets会自动添加NULL,如:
	char ch[64]; gets(ch); //输入20个, 那么0-19是输入值, ch[20]会自动是NULL,不用我们自己再手工写.
	167 //长度
		int main()
		{
		    string str("HOOHOO");
		    cout<<"sizeof: "<<sizeof(str.c_str())<<endl;  //4 sizeof(str)为28,需要改为char* ,没有\0, 
		    cout<<"length: "<<str.length()<<endl;         //6 string(stl)
		    cout<<"capacity: "<<str.capacity()<<endl;     //15 The member function returns the storage currently allocated to hold the controlled sequence  (stl)
		    cout<<"size: "<<str.size()<<endl;             //6 Returns the current number of elements in a string(stl).
		    cout<<"strlen: "<<strlen(str.c_str())<<endl;  //6 the number of characters in string, excluding(不包括) the terminal NULL  (Run-Time Library Reference) , 不属于stl string字符串,而属于c函数库,类似strcpy等

		    char* st = "HOOHoo";
		    cout<<"sizeof: "<<sizeof(st)<<endl;            //4  指针 C++ Language Reference (sizeof Operator), 关键字部分
		    //cout<<"length: "<<st.length()<<endl;         //
		    //cout<<"capacity: "<<st.capacity()<<endl;     //
		    //cout<<"size: "<<st.size()<<endl;             //
		    cout<<"strlen: "<<strlen(st)<<endl;            //6

		    cout<<sizeof("HOOHoo")<<endl;                    //7
		    char ch[] = "HOOHoo";             
		    cout<<sizeof(ch)<<endl;                        //7
		    //cout<<"length: "<<ch.length()<<endl;         //
		    //cout<<"capacity: "<<ch.capacity()<<endl;     //
		    //cout<<"size: "<<ch.size()<<endl;             //

		    int i = 15;
		    cout<<sizeof(i)<<endl;                         //4
		    return 0;
		}
	168 怎么算长度, 对于strlen.    size_t是unsigned int类型,vector使用的下标实际也是size_t,数组的也是
		size_t Strlen(const char* str)
		{   
		    int i = 0;
		    while(str[i])
			i++;
		    return i;
		}
		int main()
		{
		    char* str="HOOH";   //4
		    char str2[]="HOOH"; //4
		    cout<<Strlen(str)<<endl;
		    cout<<Strlen(str2)<<endl;
		    return 0;
		}

	//C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\crt\src 查源文件
	168  拷贝strcpy
		char* _cdecl Strcpy(char* dst, const char* src)	 //本地源文件实现
		{
		    char* tmp = dst;
		    if(!tmp) return NULL;
		    while(*tmp++ = *src++)  //二者优先级一样,从右向左”结合,相当于 *(src++), 但是NULL没有拷贝过去, 为啥下面返回dst时还正常
			;	//如果这里cout<<dst; 输出的值是逐步填入的src和pp[25]其他20+空位,比如乱码,如果pp[25]有事先定义,如="0", 那么
				//这块输出,就是逐步的h,he,hel,hell,hello
				//如果cout<<tmp-1; 就是h,e,l,l,o
		    return dst;   //dst虽然是局部指针变量,但是指向的外部传来的地址,函数结束这个地址还在
				    //相当于理解下这个

				    char *strcpy(char *strDest,const char *strSrc) 
				    { assert((strDest!=NULL)&&(strSrc!=NULL)); 
				      char *address=strDest; 
				      while((*address++=*strSrc++)!='\0'); 
				      return strDest; } 这个绝对可以理解不会出现问题吧. 
				    那么反面教材: 返回局部变量释放野指针
				    int *fun(int a)
				    {int *p;
				     int n[10];
				     p = n;
				     n[0] = 1;
				     n[2] = 2;
				     return p;}  这个p指向的数组地址,在函数结束后,数组释放结束,地址也没了,p就是野指针了
		}
		char* _cdecl Strcpy2(char* dst, const char* src)  //大全上的写法
		{    
		    while(*dst++ = *src++)  //二者优先级一样,从右向左”结合,相当于 *(src++)
			;
		    return dst-1;	(这个dst-1不好,如果在下面ctou<<"return strcpy: "<<Strcpy2(pp,cp)<<endl; 返回的不对,是字符串最后处了)
		}
		int main()
		{
		    char* cp = "hello";
		    //char* pp = NULL; 
		    char pp[25] = "0";
		    cout<<"return strcpy: "<<Strcpy(pp,cp)<<endl;
		    cout<<"return strncpy: "<<Strncpy(pp,cp,8)<<endl;	//8不能大于pp的长度,不然会报错. 8大于cp的长度, 会用\0一直填充
		    cout<<"pp Strcpy: "<<pp<<endl;
		    return 0;
		}

		看strncpy 
		char * __cdecl Strncpy (char * dest, const char * source, size_t count)
		{
			char *start = dest;

			while (count && (*dest++ = *source++))    //copy string别用count--在while里,不然0--后为负,后面的if()还是为真,死循环
				count--;			  //除非后面没有if(count,或者用个int i,用i和count比较

			if (count)                              /* pad out with zeroes 如过N大于传输的字符,就以你个\0填*/
				while (--count)
					*dest++ = '\0';

			return(start);
		}
	169 看字符串连接
		
	//连接字符串char *strcat(char *strDestination,const char *strSource);
	char *Strcat(char *dst,const char *src)
	{
	    //char *top = dst;
	    char *tmp = dst;
	    while(*tmp++) //要有*,才有判断,如果只有tmp++,那么就是地址了, 到了NULL也是地址
	    ;
	    tmp--;	//这个必须有,不然tmp到NULL了
	    
	    while(*tmp++ = *src++)
	    ;
	    //return top;	//多此一举,可以用dst
	    return dst;
	}

	int main()
	{
	    char *plu = "hello";
	    char rst[25]="world";
	    Strcat(rst,plu);
	    //Strncat(rst,plu,8);	//需要8小于rst的长度
	    cout<<"Strcat: "<<rst<<endl;
	    return 0;
	}
	//优化下
	
	char *Strcat(char *dst,const char *src)
	{
	    char *tmp = dst;
	    while(*tmp) //要有*,才有判断,如果只有tmp++,那么就是地址了, 到了NULL也是地址
		tmp++;  //到头
	    while(*tmp++ = *src++)
	    ;
	    return dst;
	}

	//延伸, 看下strncat 
	char* Strncat(char *dst,const char *src,size_t count)
	{
	    char* tmp = dst;
	    int i = 1;  //i不能初始为0, 不然下面的i++ 在运算式中是0, 直接while结束了
	    while(*tmp)
		tmp++;
	    while(count && (*tmp++ = *src++)&& i++)   //count到0后, 再执行while就跳出了,同时后面的i++等都不再执行,这就是&&,
	       count--;                                                //但是如果i++在前面,那就先执行它成功,再执行--不成功退出,但是i++还是执行了
	    if(count)
		while(--count)              //记住 --count,说明它独立的, 后面没有要同时执行的东西, 如果有 --count如果从1开始,那么&&后面的就没机会了(已经为0了)
		    *tmp++ = '\0';
	    return dst;
	}
	171  如果 区域选项 是 "POSIX" 或者 "C", 那么 strxfrm() 同用 strncpy() 来 拷贝 字符串 是等价的.(dest等价,不是说完全函数等价)
	char *strncpy(char *strDest, const char *strSource, size_t count ); //Returns strDest
	size_t strxfrm(char *strDest, const char *strSource, size_t count); //Returns the length of the transformed string
	返回类型和返回意义不同. 

	173 判断2个字符串是否相等 streql(系统函数中没有,用户自己实现)
	//判断2个字符串是否相等
	size_t streql(const char* s1,const char* s2)
	{
	    size_t flag = 0;
	    //while(*s1++ == *s2++)   //都已经遍历完了,还在比较,看来要做个判断,不然s1和s2一直++ 地址下去了
	    while((*s1++ == *s2++)&&*s1&&*s2)
		;
	    if((*s1==NULL)&&(*s2==NULL))    //不是s1和NULL比较,要取指针值
		flag =1;
	    return flag;
	}
	int main()
	{
	    char *s1 = "hello"; 
	    char *s2 = "hell";
	    //if(s1==s2)  //这种模式只适合2个都是char* , 都是char[]也不同, 所以要自写函数最佳
	    if(streql(s1,s2))
		cout<<"=";
	    else
		cout<<"!=";
	    return 0;
	}
	//延伸:如果想忽略大小写比较字符串,可以把每个值都大写或者都统一小写后,再比较,如下:
	while((toupper(*s1++) == toupper(*s2++))&&*s1&&*s2)

	175, 所有字符串转为大小写 
	//字符串大小写函数 strupr/strlwr
	char* Strupr(char* str)
	{
	    char* tmp = str;
	    while(*str)
	    {
		*str = toupper(*str);
		str++;
	    }
	    return tmp;
	}

	176 获取字符串中第一个出现的某个字符 char* strchr(const char* str,int ch);
	char* Strchr(const char* str,int ch)
	{
	    const char* tmp = str;
	    while(*tmp)
	    {
		if(*tmp == ch)
		    return  "ok";
		tmp++;
	    }
	    if(*tmp==NULL)
		return "no";
	}
	//优化
	char* Strchr2(const char* str,int ch)
	{
	   //char *tmp = str;
	   while((*str != ch) &&(*str))
	   {
	       str++;
	   }
	   return str; //return (str - tmp); 就是字符出现的地方的索引值
	}

	int main()
	{
	    char ch = 'o';
	    cout<<Strchr("hello",ch);
	    return 0;
	}

	177, 依次类推, 如何找寻字符在串中最后出现的位置呢  char* strrchr(const char* str,int ch);
	
	//倒序,从后面找和字符第一个一样的 ,我写的太差了, 看下面的.
	char* Strrchr(const char* str,int ch)
	{
	    //char* tmp = const_cast<char*>(str);//用法:const_cast<type_id> (expression)
	    //该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的
	    //一、常量指针被转化成非常量的指针,并且仍然指向原来的对象;
	    //二、常量引用被转换成非常量的引用,并且仍然指向原来的对象;  (这2点,是不是可以修改常量了, 这样不安全了. )
	    char* tmp = (char*)str;
	    int c = 0;
	    while(*tmp)
	    {
		tmp++;//到o后面了,++就是null
		c++;  //c也是到了o后的索引了  那么如果下面开始从倒数第一个o开始比较,需要 --各一次, 如果从NULL开始比较的话, 可以不先--,但是不能带*tmp判断
	    }
	//  c--;
	//  tmp--;
	//  while(*tmp && c>=0)
	    while(c-->=0)   //如果后--,就是要比较NULL结束符也算里面,如果--c,则是从字符的最后一个有效字符算起的
	    {
		if(*tmp == ch)
		    return tmp;
		tmp--;
	 //       c--;
	    }
	    return "no";
	}

	char * __cdecl _strrchr (
				 const char * string,
				 int ch
				 )
	{
	    char *start = (char *)string;

	    while (*string++)                       /* find end of string */
		;
	    /* search towards front */
	    while (--string != start && *string != (char)ch)
		;

	    if (*string == (char)ch)                /* 上面while结束,只有到头start了,或者string出现相同的了,char found , */
		return( (char *)string );

	    return(NULL);
	}

	int main()
	{
	    char ch = 'h';
	    //cout<<Strchr("hello",ch);
	    cout<<Strrchr("hello",ch);
	    return 0;
	}

	//测试 const_cast能否修改常量.
	char* testConst_cast(char* str)
	{ 
	    
	    //char* pp = const_cast<char*>(str);
	    char* tmp = (char*)str;    //tmp++,str也变了,看来用char* 接char[]不行啊, char[N]也不行. 一般是用char[]来接char*, 反过来就.....
	    //while(*tmp++)  //因为这块实现是到了下一个,然后把下一个值进行+1, 但是到了最后的o后,tmp++就是\0, \0+1的话,就是未知了,一直死循环下去了
			     //所以如果要修改判断条件,那么就要把null考虑进去.
	    while(*tmp)
	    {
		*tmp = *tmp+1; //这句屏蔽了,上面的str就不会跟着变了,也不会越域后,还继续tmp++了. //把上面的*tmp++改了,这句也不屏蔽也正常了
		tmp++;
	    }

	    return str;
	}
	int main()
	{
	    char* st = "hello"; //改成这个, *tmp=*tmp+1就不行了
	    //char st[20] = "hello";
	    testConst_cast(st);
	    cout<<st<<endl;    
	    
	    return 0;
	}


         182//计算一个字符串某个字段出现的次数(charcnt,不是c函数,要自己写)
	
	183 将字符串反序输出
	//实现字符串的反向输出 strrev(const char*)   [Run-Time Library Reference]C函数
	char* Strrev(char* str)
	{
	    int i=0,j=0;
	    char* tmp = (char*)str;
	    char dst[20] = "";
	    //while(*tmp++) 如果用这个*tmp++, 经过123(23),23(3),3(""),3次后, 最后一次"",while跳出,但是++还执行了,跑到""外的指向了, 那么就跟i不协调了
	    while(*tmp)
	    {
		i++;
		tmp++;
	    }
	    tmp--;//指向了最后一个非""字符
	    while(--i>=0)
		dst[j++] = *tmp--;
	    //return str;         //return dst就报错.加上strcpy,输出结果就好,因为出了这个函数, dst就被回收了
	    strcpy(str,dst);
	    return str;
	}
	
	char* Strrev2(char* str)
	{
	    char* tmp = str;
	    char* org = str;
	    char tt;

	    //*tmp = '4';  关于这个tmp能否修改的问题,取决于实参str的类型,是char[],还是char*,前者传入后可以改,后者不行(常量字符串const),
	   
	    while(*tmp)
		tmp++;
	    
	    while(org<tmp)
	    {
		tt = *(--tmp);
		*tmp = *org;    //这块总是替换*tmp 处出现写入失败.
		*org++ = tt;
	    }

	    return str;

	}

	int main()
	{
	    char str[20] = "HELLO";
	    cout<<"str after rev: "<<strrev(str)<<endl; //OLLEH
	    cout<<"str: "<<str<<endl;                   //OLLEH

	    char *tmp = "GOOD";
	    cout<<"str after tmp: "<<strrev(strdup(tmp))<<endl; //不用strdup,就运行时死机,貌似是内存中变量位置问题 
	    
	    char *tt = "123";
	    char* pp = strdup(tt);//将串拷贝到新建的位置处,strdup()在内部调用了malloc()为变量分配内存
				  //不需要使用返回的字符串时,需要用free()释放相应的内存空间,否则会造成内存泄漏。
	    cout<<"pp: "<<pp<<endl;
	    cout<<"strrev pp: "<<strrev(pp)<<endl;

	    cout<<"**************************************Strrev******************************"<<endl;

	    //char *ff = "123";	//常量字符串,这样的入参,要注定函数不能改动*str状态,读取可以, 如strcpy中,*dst++ = *src++;(后者是常量可以读,				//前者就改变了, 所以必须是字符数组.

	    char ff[20] = "12345";
	    cout<<"Strrev result: "<<Strrev2(ff)<<endl;
	    return 0;
	};

	184 //strset ,自己编写的函数, 用来把字符串用某个特定字符来整个覆盖赋值, 如 "aaaaaaa", 每个元素都赋上char b
	char* strset(char* str,char ch)//完全等同于 char* strset(char* str,int ch)
	{
	    char *tmp = str;
	    while(*tmp)
		*tmp++ = ch;
	    return str;
	}
	int main()
	{
	    char str[64] = "hello";
	    cout<<"strset: "<<strset(str,65)<<endl;//完全等同于 strset(str,'A')
	    return 0;
	}
	
	185 比较个字符串  string1 less than string2  < 0 ,  string1 identical to string2  0, string1 greater than string2  > 0 
	//int strcmp(const char *string1, const char *string2 );  Run-Time Library Reference 
	int Strcmp(const char *str1, const char *str2)
	{
	    //while(*str1++ != *str2++) //必须为真才能继续循环啊   ,12 cmp 12 , 一下子就while外面了
	    //{
	    //    if((*str1&&*str2))
	    //    {
	    //        if(*str1<*str2) return -1;
	    //        else if(*str1>*str2) return 1;
	    //        else if(*str1==*str2) return 0;
	    //    }
	    //    else if(*str1)
	    //        return 1;
	    //    else if(*str2)
	    //        return -1;
	    //    else if(!(*str1||*str2))
	    //        return 0;
	    //}
	    ////下面的可以通过
	    //assert( (str1 != NULL) &&(str2 != NULL) ); 
	    //while(*str1)
	    //{
	    //    if(!*str2) return 1;
	    //    if(*str1>*str2) return 1;
	    //    if(*str1<*str2) return -1;
	    //    str1++;str2++;
	    //}
	    ////if(*str1 == *str2) //if1   没有这个状况
	    ////    return 0;
	    //if(!*str1 && !*str2)  //if2
	    //    return 0;
	    //if(!*str1)            //if3    //str1 = "";   直接到 if3处, *str1为否 ,如果2个都"",则到if2. 
	    //    return -1;

	    // 精简,strcmp源码
	    int ret = 0;
	    while(!(ret = (*str1-*str2))&&(*str2))  //相等了, ret为0, 加!为1来继续. ||如果后者为空,ret为 char '3' - 0 = 51-0=51, !(非0)得0while结束
	    {
		str1++;str2++;
	    }
	    if(ret<0) return -1;
	    if(ret==0) return 0;
	    if(ret>0) return 1;
	    //if(ret<0) ret= -1;
	    //if(ret==0) ret= 0;
	    //if(ret>0) ret= 1;
	    //return ret;         //这个完全可以, 因为函数调用结束后,返回值会入栈的,这里的ret只是个int属于传值调用,ret在调用结束会被释放,
				//但是ret这个值如果为0, 那么0存入栈中,
				//但是如果局部变量是地址, 那么且不是引用形参外部传来的地址,那么内存释放后,这个地址有可能被修改,就是野指针隐患
	    
	}

	//比较N个数据
	int Strncmp(const char *str1, const char *str2, int n)
	{
	    int ret = 0;
	    //while(!(ret=(*str1-*str2))&&(*str2)&&n)// 在n等于0时, &&前的2个判断ret和*str2 都被判断执行了,会造成不符,如123和12,N=2比较了3和""了
	    while(n&&!(ret=(*str1-*str2))&&(*str2))
	    {
		str1++;str2++;n--;
	    }
	    if(ret<0) return -1;
	    if(ret==0) return 0;
	    if(ret>0) return 1;
	}
	//不考虑大小写对比
	int Stricmp(const char *str1, const char *str2)
	{   
	    int ret = 0;
	    //while(!(ret=(*str1-*str2))&&(*str2)&&n)// 在n等于0时, &&前的2个判断ret和*str2 都被判断执行了,会造成不符,如123和12,N=2比较了3和""了
	    while(!(ret=(toupper(*str1)-toupper(*str2)))&&(*str2))
	    {
		str1++;str2++;
	    }
	    if(ret<0) return -1;
	    if(ret==0) return 0;
	    if(ret>0) return 1;    
	}

	int main()
	{
	   //char* str1 = "";     //如果为空, 那么*str1 = 0, 0-'1'为否, !ret为+ 为何会跳出while呢,因为-49 
				 //取反是0, !(非0)就是0,别看成负负得正了
	    char* str1 = "123";  //
	    char* str2 = "123";

	    int flag = Strcmp(str1,str2);
	    int nflag = Strncmp(str1,str2,2);
	    //cout<<"flag: "<<flag<<endl;
	    cout<<"nflag: "<<nflag<<endl;

	    char* s1 = "abCdE";
	    char* s2 = "aBCDe";
	    cout<<"strcmp ingore case: "<<Stricmp(s1,s2)<<endl;
	    return 0;
	}
	
	189: 复制字符串 内容,  strdup, 分配内存空间
        #include<malloc.h>

char* Strdup(const char* str)
{
	char* tmp;
	if((tmp = (char*)(malloc(strlen(str)+1))))
		strcpy(tmp,str);
	return tmp;
}

int main()
{
	char *str = "hello";
	//char str[64] = "hello"; //这个数组格式,本身就有地址空间了,下面不用strdup也能使用strrev
	char *pt = Strdup(str);
	cout<<strrev(str)<<endl;//Error 因为str是个字符串,但是没有在内存中分配空间
	cout<<strrev(pt)<<endl;//测试这个strdup是否好用,通过
	cout<<"Strdup: "<<pt<<endl;
	return 0;
}
	
	
	
	XX//一个字段替换掉已知字符串中的某个串
	void replace(char *oldstr, char *newstr, char *oldsubstr, char *newsubstr)
	{    
	    int i, j;
	    int nLen = strlen(oldstr);    
	    int nLenSub = strlen(oldsubstr);    
	    for(i=0, j=0; i<nLen;)    
	    {      
		if(0 == strncmp(oldstr+i, oldsubstr, nLenSub))      
		{           
		    strcat(newstr+j, newsubstr);           
		    j += strlen(newsubstr);           
		    i += nLenSub;      
		}      
		else      
		{          
		    newstr[j++] = oldstr[i++];      
		}    
	    }
	}

	int main()
	{
	    char *oldS = "helloworld";
	    char newS[20];
	    char *oldstr = "wo";
	    char *newstr = "WO";
	    replace(oldS,newS,oldstr,newstr);
	    cout<<"new: "<<newS<<endl;

	}
Global site tag (gtag.js) - Google Analytics