存档在 2010年7月

名次确定问题(Update:8/10)

2010年7月29日

五位运动员参加比赛,进行结果预测:

A说:B第一,我第三
B说:我第二,E第四
C说:我第一,D第三
D说:C最后,我第三
E说:我第四,A第一

比赛结束,每位选手只说对了一半,编程确定比赛名次。

拿到这道题,我首先想到的是,ABCDE五人有5!个排列次序,对于每个次序都验证题目要求,满足即可break各个循环。于是代码如下:

#include 

int main()
{
	int i,sum=0;
	int a,b,c,d,e;
	int flag=0;

	for(a=1;a<\6;a++)
	{
		for(b=1;b<\6;b++)
		{
			for(c=1;c<\6;c++)
			{
				for(d=1;d<\6;d++)
				{
					for(e=1;e<\6;e++)
					{

						sum=0;
						sum=(b==1||a==3)+(b==2||e==4)+(c==1||d==2)+(c==5||d==3)+(e==4||a==1);
						if(sum==5)
						{
							flag=1;
							printf("e=%d ",e);
							break;
						}
					}

					if(flag)
					{
						printf("d=%d ",d);
						break;
					}
				}
				if(flag)
				{
					printf("c=%d ",c);
					break;
				}
			}
			if(flag)
			{
				printf("b=%d ",b);
				break;
			}
		}
		if(flag)
		{
			printf("a=%d ",a);
			break;
		}
	}
	printf("\n");
	return 0;
}

编译运行。结果错误:11134。原因是这样的:满足上述条件的序列很多,但是遇到第一个满足条件的序列(此时a,b,c都是1,可见没跑几下就break了)时,因为多个break的原因就跳出了所有循环。看来还得加一个筛选条件。既然名字是1~5的任意排序,那么五位选手名次之和肯定是固定的,因此加入此条件即可筛选处最终名次。如下:

						sum=0;
						sum=(b==1||a==3)+(b==2||e==4)+(c==1||d==2)+(c==5||d==3)+(e==4||a==1);
						if(sum==5)
						{
							if((a+b+c+d+e)==15)
							{
							flag=1;
							printf("e=%d ",e);
							break;
							}
						}

这样就OK了。看来除了得到题目表面的信息后,还得学会抓住隐含条件。其实第一个条件也可以有下面的几种表达方式:

                                                //方法1
						sum=0;
						sum+=(b==1&&a!=3)||(b!=1&&a==3);
						sum+=(b==2&&e!=4)||(b!=2&&e==4);
						sum+=(c==1&&d!=2)||(c!=1&&d==2);
						sum+=(c==5&&d!=3)||(c!=5&&d==3);
						sum+=(e==4&&a!=1)||(e!=4&&a==1);
						//方法2
						sum=0;
						sum=(a==3||a==1)+(b==1||b==2)+(c==1||c==5)+(d==2||d==3)+(e==4);

这里还有一个更简单的方法。在我作完后,我觉得这个题目用5重循环是否太多余,就想看看牛人是如何完成的,所以就咨询牛涛,它发过来一个链接,果然很简便。虽然意思是一样的但是时间复杂度只有N平方而已。我这个N的5次方 e42

Update:8/10

今天一位同学留言说,判断条件应该再加一条判断a,b,c,d,e互不相等。这个条件在我做这个题的时候就想过,可当时总觉的两个判断条件即可。但是,为什么上面的代码也可以显示处正确的答案?那是因为我加入了break。恰好第一组名词就互不相等。如果把每个break都删除了,就会发现有两组结果,其中一个结果就有重复的名次。

其实这个题目属于一个穷举类的题目,应该在程序中让它列出所有的可能(尽管本题中的答案只有一个),而不是找到一个就立刻停止。

实现cp命令(4)

2010年7月28日

现在我们已经实现了my_cp。那么我们来运行一下下面的命令吧:

gues@huangwei-desktop:~/code/shell_command$ ./my_cp -r dir/ newdir/ -r
my_cp: can't get file status of "-r" : no this file or directory.

问题出来了,我们并没有考虑到多个重复选项的情况,因此上面命令把末尾的-r当成了文件名。如果用cp执行上面的指令,那么是成功的,因为多个重复选项在cp命令下就相当于一个。因此我们下面来修改代码。
你可以让检查选项处的param_r=1;改为param+=1;然后再加入下面的代码,当出现这种情况的时候,让其出错。

if(param_r>1)
{
printf("my_cp:invalid options.\n");
exit(1);
}

为了完美一些,我们可以这样做。首先我们将原来index_r改成数组index,记录出现-r的位置。我们可以让这个数组全部初始化为0,如果参数中,第i个参数为-r或者-R,那么就将index[i]赋值为i。并且这时候的param_r就要累计出现合法(对于本程序,合法选项就是-r或-R了)选项的个数。

	//check the legality of the options,only -r or -R
	for(i=1;i<\argc;i++)
	{
		if(argv[i][0]=='-')
		{
			if((!strcmp(argv[i],"-r")||!strcmp(argv[i],"-R")))
			{
				param_r+=1;
				index[i]=i;
			}
			else
			{
				printf("my_cp:invalid options: %s\n",argv[i]);
				exit(1);
			}
		}
	}

那么在计算源文件数目的时候也相应的就有了小改动。

	if(param_r)
	{
		num=argc-1-param_r;
		src_num=num-1;
	}
	else
	{
		num=argc-1;
		src_num=num-1;
	}
	if(num<\2)
	{
		printf("my_cp: [option]  \n");
		exit(1);
	}

提取目标文件的时候,就有些小麻烦,但是也是可以解决的。我们从命令行参数末尾开始,找到那个不是选项的那个参数,因为目标文件总是靠近末尾的。比如:./my_cp dir/ newdir/ -r -r

	//extract the dest path
	for(i=argc-1;i>\0;i--)
	{
		if(!strcmp(argv[i],"-r")||!strcmp(argv[i],"-R"))
			continue;
		else
			break;
	}
	if(i==argc-1)
	{
		strcpy(dest_path,argv[i]);
	}
	else
	{
		strcpy(dest_path,argv[i]);
	}

好了,改完上面的代码,下面就和以前的一样了。这样就可以避免开始的时候我们所举的例子的错误。

ubuntu下安装VirtualBox

2010年7月28日

ubuntu的功能非常强大,但是有时候还是会用到XP下的某些软件。那么就在ubuntu下安装个虚拟XP吧。

下载好文件(这里只针对.run格式),解压至主文件夹运行:

sudo sh VirtualBox-3.2.4-62431-Linux_x86.run

安装完毕后,也许你会觉得原始屏幕太小,那么安装增强包。在虚拟窗口点击:设备–安装增强包。然后打开虚拟XP的光驱,点击那里的VBoxWindowsAdditions.exe文件就可安装。重启XP以后,你就可以随意拖动虚拟窗口大小了。

实现cp命令–文件夹的拷贝

2010年7月27日

刚刚完成了my_cp的另一个功能:将一个目录拷贝到指定目录。加上昨天实现的将一个文件拷贝到指定地址下,现在已经完成了我们实现前所定下的要求。也许你会有疑问,那多个文件的拷贝的实现呢?我面前面已经说过,只要完成上述两个功能,并且你在主函数中“分流”正确,那么只要在合适的位置调用这两个函数即可,具体办法我们下面会讨论。

在详解如何实现将一个目录拷贝到指定目录(cp_directory函数)之前,我们首先应该弄明白下面的内容:

1.如果目标目录中的最低级目录不存在,则会新建这个目录,并把源目录中的所有文件拷贝到此新建的目录下。比如cp -r dir ./newdir。我们可以看到./newdir(这个路径中最低级的目录是newdir)在cp前是不存在的,但是cp后新建了这个目录,并且将dir中的所有文件拷贝到这个新建的目录下。

gues@huangwei-desktop:~/code/shell_command$ ls
cptest  ls   my_cp   my_cp.c  my_ls_plus    my_shell.c    nothisdirectory  tdir         test
dir     ls1  my_cp1  my_ls.c  my_ls_plus.c  newdirectory  nothisfile       tdirmy_ls.c  ttfile.c
gues@huangwei-desktop:~/code/shell_command$ ls dir
ed  my_cp1  test  ttfile.c
gues@huangwei-desktop:~/code/shell_command$ cp -r dir ./newdir
gues@huangwei-desktop:~/code/shell_command$ ls newdir
ed  my_cp1  test  ttfile.c

2.如果最低级的目标目录存在,则会将源目录(当然也包含源目录下的所有文件)拷贝到这个目标目录。我们仍执行上面那个命令:cp -r dir ./newdir。但是这次结果是不一样的,由于1的操作,newdir目录已经存在,这次cp后将dir目录拷贝到了已存在的newdir目录下(即./newdir/dir/)。

gues@huangwei-desktop:~/code/shell_command$ ls newdir
ed  my_cp1  test  ttfile.c
gues@huangwei-desktop:~/code/shell_command$ cp ./dir -r ./newdir
gues@huangwei-desktop:~/code/shell_command$ ls newdir
dir  ed  my_cp1  test  ttfile.c

如果我说的还不够明白,你也可以自己亲自验证一下cp命令。

下面我们来详解。还是先保留传递过来的路径。然后如果源文件夹不包含/,则添加。

void cp_directory(char* original_src_path,char* original_dest_path)
{
	struct stat buf;
	DIR *dir;
	struct dirent *ptr;
	char path[PATH_MAX+1];
	char src_path[PATH_MAX+1],dest_path[PATH_MAX+1];

	strcpy(src_path,original_src_path);
	strcpy(dest_path,original_dest_path);

	if(src_path[strlen(src_path)-1]!='/')
	{
		strncat(src_path,"/",1);
	}
        //the following code be omited
}

如果目标目录中最低级的目录不存在,则创建它。如果次低级目录也不存在,则在创建的时候就发生错误。如果目标目录存在,并且是目录文件,那么就如同上面举例2中所述,我们需要将源路径中最低级的目录拷贝到目标目录中。这里面设计到提提取源路径最低级的目录,以及将其连接在目标目录后等。这些都不难理解。注意当完成目标路径的拼接后,如果这个目录本身就存在,那么我们将其删除,创建新目录。

if(stat(dest_path,&buf)==-1)
	{
		//create a directory which name is dest_path
		stat(src_path,&buf);
		if(mkdir(dest_path,buf.st_mode)==-1)
		{
			printf("my_cp:create the directory \"%s\" error.\n",dest_path);
			return ;
		}
 	}
	else
	{
		//exist
		if(!S_ISDIR(buf.st_mode))
		{
			printf("my_cp:the directory \"%s\" can't cover the no-directory \"%s\".\n",src_path,dest_path);
			return ;
		}
		else
		{
			if(dest_path[strlen(dest_path)-1]!='/')
			{
				strncat(dest_path,"/",1);
			}
			//extract the lowest directory
			int i,k=0;
			char lowestdir[PATH_MAX+1];
			for(i=strlen(src_path)-1-1;i>\0;i--)
			{
				if(src_path[i]=='/')
				{
					i=i+1;
					break;
				}
			}

			for(;i<\strlen(src_path);i++)
			{
				lowestdir[k++]=src_path[i];
			}
			strncat(dest_path,lowestdir,strlen(lowestdir));
			struct stat temp_buf;
			char temp_path[PATH_MAX+1]="rm -rf ";
			if(stat(dest_path,&temp_buf)==0)
			{
				strcat(temp_path,dest_path);
				system(temp_path);
			}
              		if(mkdir(dest_path,buf.st_mode)==-1)
	        	{
				printf("my_cp:create the directory \"%s\" error.\n",dest_path);
	 		        return ;
	          	}
		}
	}

接着我们打开源目录,读取其下的所有文件名。这个方法在my_ls的时候就已经使用过。我们将这些文件名与目的路径拼接后,检查他们是否是目录文件。如果是普通文件那么就调用cp_single函数,否则调用cp_directory函数。

	if((dir=opendir(src_path))==NULL)
	{
		printf("my_cp:open the srouce path \"%s\" error.\n",src_path);
		return ;
	}
	char temp_dest_path[PATH_MAX+1];
	strcpy(temp_dest_path,dest_path);
	while((ptr=readdir(dir))!=NULL)
	{
		if(!strcmp(ptr->\d_name,"."))
			continue;
		if(!strcmp(ptr->\d_name,".."))
			continue;
		strcpy(path,src_path);
		strcat(path,ptr->\d_name);
		if(stat(path,&buf)==-1)
		{
			printf("my_cp:open the file \"%s\" error.\n",path);
			return ;
		}
		strcpy(dest_path,temp_dest_path);
		//get the right dest_path
		if(S_ISDIR(buf.st_mode))
		{
			cp_directory(path,dest_path);
		}
		else
		{
			cp_single(path,dest_path);
		}
	}

其实这是一个递归的过程,对于递归,最重要的是能返回到调用函数。对于任何目录,最终要么这个目录是空的,要么全是普通文件,所以肯定能返回到上一级函数中,不会无限的去嵌套。

以上就是my_cp函数的实现过程,需要源码的同学留下邮箱即可。如果发现了不妥之处,欢迎指正。

实现cp命令–单个文件的拷贝

2010年7月26日

昨天我们主要从主函数入手,对命令行参数进行合法性检测,并引导主程序进入相应的子函数。今天我们要实现一个最基本的复制功能,将一个源文件复制到指定路径。之所以说路径,是因为目的文件可能是一个存在的文件,也可能是一个不存在的文件或者是一个目录(不存在的目录会出错)。在我们详细分析代码前,先看看我做的这个my_cp的运行结果吧。
1.成功将一个已存在源文件复制到另一个指定文件名的文件中。

gues@huangwei-desktop:~/code/shell_command$ ls
cptest  dd  dd1  ed  ls  ls1  my_cp  my_cp1  my_cp.c  my_ls.c  my_shell.c  newls.c  tdir  test  tfile.c
gues@huangwei-desktop:~/code/shell_command$ ./my_cp tfile.c ttfile.c
gues@huangwei-desktop:~/code/shell_command$ ls -l
总用量 124
-rw-r--r-- 1 gues gues  7378 2010-06-22 23:58 my_ls.c
-rw-r--r-- 1 gues gues  6271 2010-07-17 14:29 my_shell.c
-rw-r--r-- 1 gues gues  7378 2010-07-25 17:20 newls.c
drwxr-xr-x 2 gues gues  4096 2010-07-25 18:03 tdir
drwxr-xr-x 3 gues gues  4096 2010-07-25 18:03 test
-rw-r--r-- 1 gues gues  6271 2010-07-25 16:35 tfile.c
-rw-r--r-- 1 gues gues  6271 2010-07-26 10:14 ttfile.c

2.将已存在的源文件拷贝到一个不存在的目录下,会提示错误信息。

gues@huangwei-desktop:~/code/shell_command$ ./my_cp tfile.c ~/nothisdirectory/
my_cp:can't create the file:"/home/gues/nothisdirectory/":it is a directory.

3.将不存在的源文件拷贝到一个目录或文件中,提示相应错误。这里的目标文件或指定目录是否存在不确定。因为只有一个源文件时,cp命令总先检查源文件是否存在。

gues@huangwei-desktop:~/code/shell_command$ ./my_cp nothisfile ~/nothisdirectory
my_cp: can't get file status of "nothisfile" : no this file or directory.

4.成功将源文件拷贝到已存在的指定目录,由于指定路径没有文件名,因此目标文件名与源文件名相同。

gues@huangwei-desktop:~/code/shell_command$ ./my_cp tfile.c ~/
gues@huangwei-desktop:~/code/shell_command$ ls ~/
code     Documents  EIOffice               EIOffice_Personal_Lin.tar.gz  Pictures   tfile.c  Yozo_Office
cptest   Downloads  EIOfficelog.txt        examples.desktop              Public     tmp
Desktop  edsionte   EIOffice_Personal_Lin  Music

5.之所以首先演示这些结果是因为我们在编写cp_single函数的时候都要考虑到这些情况,加之路径相对灵活可能少一个/就会产生不结果。比如下面的结果:

gues@huangwei-desktop:~/code/shell_command$ ./my_cp tfile.c ~/nothisdirectory
gues@huangwei-desktop:~/code/shell_command$ ls ~/
code     Documents  EIOffice               EIOffice_Personal_Lin.tar.gz  nothisdirectory  Templates  Videos
cptest   Downloads  EIOfficelog.txt        examples.desktop              Pictures         tfile.c    Yozo_Office
Desktop  edsionte   EIOffice_Personal_Lin  Music

拷贝成功。这里我们输入的参数仅仅与2中输入的参数少一个/,为什么结果就大不相同?因为2中目标文件是一个不存在的目录(~/nothisdirectory/),而上面的命令是将已存在文件拷贝到已存在目录(~/)下,并且指定文件名为nothisdirectory。
好了,我们下面来分析代码。进入cp_single函数,我们将传递过来的路径拷贝到局部变量src_path和dest_path当中。因为cp_single函数可能在程序的一次运行中被调用多次,如果修改了传递过来的路径(指针)那么会导致下面的调用不正确。如果传递过来的源文件只是一个文件名,那么我们自动为其加上当前路径,这可以方便下面提取文件名。

void cp_single(char *temp_src_path,char* temp_dest_path)
{
	struct stat buf;
	int len;
	char ch[10],filename[PATH_MAX+1],dest_dir[PATH_MAX+1];
	int fdrd,fdwt,i,j,k;
	char src_path[PATH_MAX+1],dest_path[PATH_MAX+1];

	strcpy(src_path,temp_src_path);
	strcpy(dest_path,temp_dest_path);
	for(k=0;k<\strlen(src_path);k++)
	{
		if(src_path[k]=='/')
		break;
	}
	char temp_path[PATH_MAX+1]="./";
	if(k==strlen(src_path))
	{
		strcat(temp_path,src_path);
	        strcpy(src_path,temp_path);
	}

        //the following code be omited
}

接着,从源文件路径中提取文件名。即提取最后一个/符号后面的字符串。

	//extract the file name from src_path
	for(i=strlen(src_path)-1;i>\0;i--)
	{
		if(src_path[i]=='/')
			break;
	}
	j=k=0;
	for(j=i;j<\strlen(src_path);j++)
	{
		filename[k++]=src_path[j];
	}
	filename[k]='\0';

如果目标文件路径存在,并且不含文件名,那么这时候就用到了我们上面提取的源文件名,用strcat连接即可。当然在连接之前还要检查目标文件夹是否包含/,如果包含则删除,否则会连接成这样:existeddir//filename。当不存在此目标路径,我们要检测这个路径末尾这是一个不存在的目录(上述举例2)还是一个已存在目录下不存在的文件(举例5)。我们先找到目标路径中出现的最后一个/,然后检测这个/之前的路径是否存在。比如对于路径:~/existdirectory/nothisdirectory/nothisfile。我们需要检测的是~/existdirectory/nothisdirectory/是否存在,若不存在那就显示出错信息。如果存在,那么按照完整路径:~/existdirectory/nothisdirectory/nothisfile打开文件即可。实现代码如下:

	//check the if dest path has exsited
	if(stat(dest_path,&buf)==0)
	{
		//the dest_path exsited
		if(S_ISDIR(buf.st_mode))
		{
			if(dest_path[strlen(dest_path)-1]=='/')
				dest_path[strlen(dest_path)-1]='\0';
			strcat(dest_path,filename);
		}
	}
	else
	{
		//the dest_path didn't exsit
		for(i=strlen(dest_path)-1;i>=0;i--)
		{
			if(dest_path[i]=='/')
				break;
		}
		if(i>=0)
		{
			strncpy(dest_dir,dest_path,i+1);
		        if(stat(dest_dir,&buf)==-1)
	            	 {
		         	printf("my_cp:accessing:\"%s\" :it is't a directory.\n",dest_path);
			        exit(1);
               		}
		}

	}

下面是cp命令和本程序运行结果的比较。

gues@huangwei-desktop:~/code/shell_command$ ./my_cp tfile.c ~/nothisdirectory/nothisfile
my_cp:accessing:"/home/gues/nothisdirectory/nothisfile" :it is't a directory.
gues@huangwei-desktop:~/code/shell_command$ cp tfile.c ~/nothisdirectory/nothisfile
cp: 正在访问"/home/gues/nothisdirectory/nothisfile": 不是目录

完成上述功能,便进行真正的拷贝了。我们不仅要拷贝源文件的内容,还要拷贝相关文件属性,比如存取权限,用户ID,用户组ID等。下面的代码便是实现上述功能。如果你完成了my_ls,下面的代码并不困难理解,在此不在赘述。

	//fistly the content which was read from srouce file will be write to dest file
	if((fdrd=open(src_path,O_RDONLY))==-1)
	{
		perror("open");
		exit(1);
	}
	if(lseek(fdrd,0,SEEK_END)==-1)
	{
		perror("lseek");
		exit(1);
	}
	if((len=lseek(fdrd,0,SEEK_CUR))==-1)
	{
		perror("lseek");
		exit(1);
	}
	if(lseek(fdrd,0,SEEK_SET)==-1)
	{
		perror("lseek");
		exit(1);
	}
	//open the dest file
	if((fdwt=open(dest_path,O_CREAT|O_TRUNC|O_RDWR,S_IRWXU))==-1)
	{
		perror("open");
		exit(1);
	}
	close(fdwt);
	if((fdwt=open(dest_path,O_WRONLY|O_APPEND))==-1)
	{
		perror("open");
		exit(1);
	}

	while(len-->\0)
	{
		//write all characters to dest file
		if(read(fdrd,ch,1)!=1)
		{
			perror("read");
			exit(1);
		}
		if(write(fdwt,ch,1)!=1)
		{
			perror("write");
			exit(1);
		}

	}

	//get src file's attributes
	if(fstat(fdrd,&buf)==-1)
	{
		perror("fstat");
		exit(1);
	}
	//set the dset file's access right
	if(fchmod(fdwt,buf.st_mode)==-1)
	{
		perror("fchmod");
		exit(1);
	}
	//set file's user id and group id
	if(fchown(fdwt,buf.st_uid,buf.st_gid)==-1)
	{
		perror("fchown");
		exit(1);
	}
	close(fdwt);
	close(fdrd);

现在基本上完成了最基本的拷贝功能。如果上述代码有问题,欢迎留言指正。

windows 7 ultimate product key

windows 7 ultimate product key

winrar download free

winrar download free

winzip registration code

winzip registration code

winzip free download

winzip free download

winzip activation code

winzip activation code

windows 7 key generator

windows 7 key generator

winzip freeware

winzip freeware

winzip free download full version

winzip free download full version

free winrar download

free winrar download

free winrar

free winrar

windows 7 crack

windows 7 crack

windows xp product key

windows xp product key

windows 7 activation crack

windows7 activation crack

free winzip

free winzip

winrar free download

winrar free download

winrar free

winrar free

download winrar free

download winrar free

windows 7 product key

windows 7 product key