一学期的实验及答案

第一周:Linux环境搭建——虚拟机文件共享

① 右键新建终端

② 键入ifconfig


1

③ 键入ifconfig eth0 up

④ 键入service network restart


2

⑤ 键入ifconfig,出现图中红框所示部分即配置成功。inet addr为主机号。


⑥ 打开xshell,点击新建连接


⑦ 输入自拟名称及主机号


⑧ 注册用户名及密码(若用root用户登录,密码须与Linux虚                    拟机root用户密码相同)

⑨ 点击xftp图标,重复新建步骤



⑩ 出现如图所示界面,即共享成功,双击文件即可传输。


第二周:Linux使用测试

(1)进入用户主目录

         cd或者 cd ~ 或者cd #

(2)创建文件hello.c

         touchhello.c

(3)在文件hello.c中添加字符串“hello world”

         echohello world > hello.c

(4)创建目录test

         mkdirtest

(5)进入test

         cdtest

(6)将/root/hello.c拷贝在当前目录下,命名为hello1.c

         cp  /root/hello.c hello1.c

(7)查找hello1.c中是否存在字符串“hello”

         grep  hello hello1.c

(8)返回用户主目录

         cd

(9)为hello.c创建硬链接hello_back.c和符号链接hello.lnk

         ln  hello.c hello_back.c

         ln  -s hello.c  hello.lnk

(10)将目录test打包为test.tar.gz

         tar  zcvf test  test.tar.gz

(11)删除目录test并解压test.tar.gz。

         rm   -rf  ./test

         tar  zxvf test.tar.gz


第三周:Shell测试

请编写shell脚本,完成下列题目。

(1)编写menu.sh,请用case实现下列菜单功能。

                            [N]ewa file _新建文件

                            [E]dita file _编辑文件

                            [D]eletea file _删除文件

                            [Q]uit_退出

答案

#!/bin/bash

echo "Please choose either N,E,D orQ:"

cat<<-ENDIT               #依次打印

       #[N]ew a file

       #[E]dit a file

       #[D]elete a file

       #[Q]uit

ENDIT

read choice               #读取输入字符

case "$choice" in          #case语句

       N) echo "please input a new filename:"

         read value

                   touch${value}            #新建指定名字的文件 

         ;;

       E) echo "pleas input a filename:"

         read value

            vi ${value}               #进入指定名字的文件

         ;;

       D) echo "Please input a filename:"

         read value

                 rm ${value}               #删除指定名字的文件

                ;;

       Q) TERM=quit

                echo "QuitSuccessfully" #退出选项

                ;;

 esac                     #退出case语句

(2)编写computer.sh,请用至少三种方式计算2*3的结果。

答案

#!/bin/bash

#方法一expr

echo "use the way of expr"

r=`expr 2 \* 3`          #“\”为转义字符

echo $r

#方法二将内层括号内运算结果作为外层括号的输出值

echo "use the way of /$ (())"

r=$((2*3))

echo $r

#方法三 $[]直接输出计算值

echo "use the way of /$ []"

r=$[2*3]

echo $r

#方法四let

echo "use the way of let"

let r=2*3

echo $r

(3)编写printNum.sh,请用至少三种方式打印数字1-10。

答案

#!/bin/bash

#方法一 while语句

echo "loop of while"

let "n = 0"

while [ $n -lt 10 ]

do

let "n = n + 1"

echo $n

done

#方法二 until语句

echo "loop of until"

let "n = 0"

until [ $n -eq 10 ]

do

let "n += 1"

echo $n

done

#方法三 for语句

echo "loop of for"

for i in `seq 1 10`

do

echo $i

Done

(4)编写functionEx.sh,用函数调用实现对输入数字平方的计算。      例如:运行./functionEx.sh

5,则输出结果25。

答案

#!/bin/bash

# Scriptname: do_square

function square

{

 local sq

  let"sq=$1 * $1"

 return

}                

value_returned=$(square $1)

echo "$value_returned"

(5)请依次输出命令行中所有位置参数。

答案

#!/bin/bash

#方法一 until语句

until [ $# -eq 0 ]

do

echo $1

shift

done

#方法二 while语句

num=$#

i=0

while [$i - lt $num]

do

Echo “$1”

i=$[i+1]

shift

done

exit 0



第四周:U盘挂载


挂载U盘(设定字符集,保证能够正常显示中文)

①新建终端后依次输入一下命令行

②fdisk-l                #查看系统硬盘和分区情况



③插入U盘

④fdisk -l

#重新查看文件后,大家可以发现多了一个硬盘/dev/sdb和它的一个分区/dev/sdb1

 ⑤mkdir -p/mnt/usb  #在mnt目录下创建目录usb来作挂接点

⑥mount -o iocharset=cp936 /dev/sdb1 /mnt/usb   #进行挂载

#其中,-o iocharset是设定字符集(该字符集不唯一),保证能够正常显示中文。

⑦ls /mnt/usb                     #成功挂载后使用命令进行查看。

#挂载移动硬盘和U盘完全一样。


⑧umount /dev/sdb1#解除挂载(目的是避免损坏或丢失数据)



第五周:Shell编程实现加减乘除

touch arithmetic.sh    #创建存放实现运算函数代码的shell文件

vim arithmetic.sh      #进入shell文件进行代码编写

编写内容

#!/bin/bash

add () {

return $(($1 + $2))

}                      #实现+运算

sub () {

return $(($1 - $2))

}                      #实现-运算

mul () {

return $(($1 * $2))

}                      #实现*运算

div () {

return $(($1 / $2))

}                      #实现/运算


touch test.sh          #创建测验文件

vi test.sh

编写内容

#!/bin/bash

. arithmetic.sh          #调用函数文件

`add 2 2`              #用倒引号``调用加运算

echo $?                #用$?输出运算结果

`sub 8 4`

echo $?

`mul 7 2`

echo $?

`div 6 2`

echo $?


第六周:Makefile实现静态库、共享库

touch makefile

vi makefile

编写内容

libstatic: usehello.c libhello.c

                                     gcc-c libhello.c

                                     arcr libstatic.a libhello.o

                                     gcc-o static usehello.c libstatic.a

libshared: usehello.c libhello.c

                                     gcc-c libhello.c

                                     gcc-shared -fPIC -o libshared.so libhello.o

                                     gccusehello.c  –o  dyLib –lshared  –L ./

clean:

                                     rm-f *.so

                                     rm-f *.o

                                     rm-f *.a

静态库运行过程:

#make libstatic                                   

#./static                                             

共享库运行过程:

$make libshared                                       

$ LD_LIBRBRY_PATH= ./   ./dyLib                                    


 第七周:半期测验

阅读Makefile文件,回答问题: 

#如果注释掉all : libmys.so语句的话,需要输入指定执行规则make libmys.so运行

all : libmys.so

SRC=f1.c f2.c f3.c

TGT=$(patsubst %.c,%.o,$(SRC))   #子串替换

%.o : %.c        #模式规则所有.c通过执行gcc指令获得.o文件

         cc-c $?     #代表依赖文件f1.c f2.c f3.c

libmys.so : $(TGT) 

         cc-shared -o $@ $(TGT)

clean: 

         rm-f $(TGT) 

回答以下问题:

A卷

(1) 此Makefile文件的主要功能是什么?(20分)

创建名为libmys.so的动态库

(2) 此Makefile文件包含多少个规则?它们分别是什么?(20分)

4个;分别是 all 、 %.o 、  libmys.so、clean

(有几个冒号,就有几个规则)

(3) 使用此Makefile文件可以生成目标文件f2.o吗?为什么?(20分)

可以生成f2.o  因为有%.o : %.c 这一模式规则,该规则 使所有的.c的依赖文件编译生成.o的目标文件。

(4) 此Makefile中,请指出存在的伪目标名称。(20分)

                 all、clean

(5) 请写出$(TGT)的值。(20分)

$(TGT)的值为:f1.o f2.o f3.o

B卷

(1)此Makefile文件中,可以生成共享库,请指出共享库名字。(10分)

                         libmys.so

(2)如果测试该生成共享库的源文件test.c,请将它编译生成可执行程序并运行。(20分)

gcc test.c -o test -lmys -L ./

LD_LIBRARY_PATH=./

./test

(3)此Makefile文件中,除了显式规则,还使用了哪种规则,请指出并解释。(30分)

                   还使用了模式规则:%.o : %.c

                                                               cc -c $?

         该规则使所有的.c的依赖文件编译生成.o的目标文件。

(4)此Makefile文件中,all表示什么目标?(20分)

                   伪目标

(5)此Makefile中,请指出使用的函数并解释其功能。(20分)            TGT=$(patsubst %.c,%.o,$(SRC)):运用patsubst(替换通配符),将$(SRC)中所有的末尾为.c的字符串替换为末尾为.o的字符串。

C卷

(1) 此Makefile文件的主要功能是什么,如何通过命令执行出结果?(20分)

生成共享库libmys.so,执行指令make 或者make all

(2) 请描述该Makefile文件获得执行结果的过程(20分)

① 声明所需要的文件名

② 为f1.c f2.c f3.c生成.o文件

③ 将所生成的.o文件生成共享库

④ 清除中间生成的文件

(3) $?的值是什么?(20分)

f1.c f2.c f3.c

(4) 此Makefile中,请指出存在的伪目标名称。(20分)

all、clean

(4) 请写出$(TGT)的值。(20分)

 f1.of2.o、f3.o


                            第八周:ls模拟实验



#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

//\033(e)[显示方式;前景色;背景色m\033(e)[0m

void get_mode(struct stat buff)//得到当前的文件类型和三个权限

{

char *ptr;

unsigned int i,mask = 0700;

static char *perm[]={"---","--x","-w-","-wx","r--","r-x","rw-","rwx"};//分别对应0 1 2 3 4 5 6 7

if(S_ISREG(buff.st_mode))

ptr="-";

else if(S_ISDIR(buff.st_mode))

ptr="d";

else if(S_ISLNK(buff.st_mode))//符号连接

ptr="l";

printf("%s",ptr);

for(i=3;i;i--)

{

printf("%3s",perm[(buff.st_mode&mask)>>(i-1)*3]);//我们得到的3位8进制数 从左到右分别是 右边没有参与运算的处理掉

mask >>= 3;//mask是掩码

}

}

void get_name(struct stat buff)//得到属主名字 和 属主所在的组 名字

{

struct passwd *user=NULL;//定义一个用户的结构体

struct group *group=NULL;//定义一个组的结构体

user=getpwuid(buff.st_uid);//文件属主的用户身份标识

printf(" %s",user->pw_name);//得到这个标识结构体中的用户名字

group = getgrgid(buff.st_gid);//文件属主的分组身份标识

printf("    %s",group->gr_name);

}

void get_time(struct stat buff)//最新的内容修改时间

{

char *month[]={"1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"};

struct tm *mptr=NULL;//时间结构体

mptr = localtime(&buff.st_mtime);//文件内容方面的上次被修改时间 atime上次被访问时间 ctime文件权限\属主\分组或内容方面的上次被修改时间 这个函数取得文件的时间

printf(" %4s %2d ",month[mptr->tm_mon],mptr->tm_mday);

printf("%02d:%02d",mptr->tm_hour,mptr->tm_min);

}

void list_info(struct stat buff)//文件类型的就列出各种函数得到的结果

{

get_mode(buff);

printf("%5d",buff.st_nlink);//得到硬链接

get_name(buff);

printf("%12ld",buff.st_size);//文件大小

get_time(buff);

}

void list_dir(char *dir_path)//是目录类型的 就

{

int i;

static int count = 0;

DIR *dirp=NULL;//一个文件目录指针

struct dirent *dp=NULL;//存储目录中的文件信息的结构体

struct stat buff;//存储文件信息的结构体

dirp=opendir(dir_path);//打开一个子目录并建立一个子目录流

chdir(dir_path);//进入这个子目录流

while((dp=readdir(dirp)) != NULL)//读这个子目录流是否有内容readdir函数读取到的文件名存储在结构体dirent的d_name成员中

{

if(dp->d_name[0]=='.')//隐藏文件

continue;

if(lstat(dp->d_name,&buff)==-1)//函数lstat的作用就是获取文件名为d_name的文件的详细信息,存储在stat结构体中

{

printf("fail to get stat\n");

continue;

}

for(i = 0;i

{

printf(" \t",count);

}

list_info(buff);

if(S_ISREG(buff.st_mode))

{

printf(" %s\n",dp->d_name);

}

        else if(S_ISDIR(buff.st_mode))

{

printf(" \e[1;34m%s\e[0m\n",dp->d_name);

count++;//再次深入

list_dir(dp->d_name);//自身递归 直到该层的目录中的文件列表读完了 才出来

count--;//递归出来深入减1

}

      else if(S_ISLNK(buff.st_mode))//如果是链接

{

char sbuf[128];

memset(sbuf,'\0',128);

if(readlink(dp->d_name,sbuf,128)!=-1)//成功找到源

{

printf(" \e[0;36m%s\e[0m -> %s\n",dp->d_name,sbuf);

}else{

printf("error\n");

}

}

}//一直读取到这一层目录文件列表完成

chdir("..");//返回到上级目录

}

int main(int argc,char *argv[])

{

int i;

struct stat buff;//定义stat的结构体

if(argc<2)//缺少给定的参数文件

{

printf("loss argument\n");

return -1;

}

for(i=argc-1;i>=1;i--)

{

if(lstat(argv[i],&buff)==-1)// lstat,是一种文件描述词。意思是获取一些文件相关的信息,成功执行时,返回0。失败返回-1

{

printf("%s error\n",argv[i]);

continue;

}

if(S_ISREG(buff.st_mode))//文件是一个普通文件

        {

list_info(buff);

printf(" %s\n",argv[i]);

}

        else if(S_ISDIR(buff.st_mode))//文件是一个子目录

        {

list_dir(argv[i]);

}

else if(S_ISLNK(buff.st_mode))//文件是一个符号链接

        {

list_info(buff);

char sbuf[128];

memset(sbuf,'\0',128);//用‘\0’填充字符串sbuf

if(readlink(argv[i],sbuf,128)!=-1)//readlink取得符号链接所指的文件readlink()会将参数path 的符号连接内容存到参数sbuf 所指的内存空间, 返回的内容不是以NULL作字符串结尾, 但会将字符串的字符数返回. 若参数bufsiz 小于符号连接的内容长度, 过长的内容会被截断.执行成功则传符号连接所指的文件路径字符串

{

printf(" \e[0;36m%s\e[0m -> %s\n",argv[i],sbuf);

}else{

printf("error\n");

}

}

printf("\n");

}

}


                            第九周:内存纠错实验

示例1:

void GetMemory(char *p, int num)

{

         p= (char *)malloc(sizeof(char) * num);

}

void Test(void)

{

         char*str = NULL;

         GetMemory(str,100);

         strcpy(str,"hello");

}

错误:

(1)空指针非法操作。因为str与p之间是值传递,在函数GetMemory调用结束后,p分配空间的首地址无法存入str,导致str仍然是null,后续字符串拷贝函数则出现了空指针非法操作。

(2)在函数GetMemory中分配的空间没有回收,导致内存泄露。

改正:

参见示例2和示例3。

示例2:

void GetMemory2(char **p, int num)

{

         *p= (char *)malloc(sizeof(char) * num);

}


void Test2(void)

{

         char*str = NULL;

         GetMemory2(&str,100);

         strcpy(str,"hello");

         cout<

         free(str);

}

正确。

示例3

char *GetMemory3(int num)

{

         char*p = (char *)malloc(sizeof(char) * num);

         returnp;

}

void Test3(void)

{

         char*str = NULL;

         str= GetMemory3(100);

         strcpy(str,"hello");

         cout<

         free(str);

}

正确

示例4

char *GetString(void)

{

         charp[] = "hello world";

         returnp;

}


void Test4(void)

{

         char*str = NULL;

         str= GetString();

         cout<

}

错误。

(1)出现乱码打印。因为在函数GetString中,p数组拷贝了字符串常量“hello world”的值,但函数调用结束后,p数组回收导致这段空间内容被篡改,但p数组首地址确能成功返回指针变量str中,所有str可以输出,但内容确不是”hello world”。

改正:

参见示例5。

示例5

char *GetString2(void)

{

         char*p = "hello world";

         returnp;

}


void Test5(void)

{

         char*str = NULL;

         str= GetString2();

         cout<

}

                            第十周:进程通信实验-电子表

用alarm(单进程实现)(文件名 clock)

#include

#include

#include

#include

#include

#include

#include

#include


int second=0,minute=0,hour=0;


void time(){

 if (second > 59 ){

 second=0;

 minute++;

 }

 if (minute > 59 ){

 minute=0;

 hour++;

 }

 if (minute > 24 ){

 hour=0;

 }

 printf("\r%02d : %02d :%02d\r",hour,minute,second);

 second++;

 fflush(stdout);

 alarm(1);    #区别ualarm    

}

int main(){ 

 signal(SIGALRM,time);

 alarm(1);   #区别ualarm

 while(1);

 return 0;

}

运行

gcc -o clock clock.c

./clock

 [ctrl+c可以快速跳出运行界面]


用ualarm实现(文件名 clock2)

#include

#include

#include

#include

#include

#include

#include

#include

int second=0,minute=0,hour=0;

void time(){

 if (second > 59 ){

 second=0;

 minute++;

 }

 if (minute > 59 ){

 minute=0;

 hour++;

 }

 if (minute > 24 ){

 hour=0;

 }

 printf("\r%02d : %02d :%02d\r",hour,minute,second);

 second++;

 fflush(stdout);     

}

int main(){ 

 signal(SIGALRM,time);

 ualarm(1000000,1000000);    #区别alarm

 raise(SIGALRM);             #区别alarm

 while(1);

 return 0;

}

运行

gcc -o clock2 clock2.c

./clock2

用父子进程实现(文件名 clock3)

#include

#include

#include

#include

#include

void handle(int signo)    #必须有一个int类型的参数,接收信号

{       

         if(signo==SIGALRM)     #处理SIGALRM信号

         {

                   staticsecond;

                   staticminutes;

                   statichours;

                   staticday = 22;

                   second++;

                   if(second==60)

                   {

                            minutes++;

                            second=0;

                            if(minutes==60)

                            {

                                     hours++;

                                     minutes= 0;

                                     if(hours==24)

                                     {

                                               day++;

                                               hours= 0;

                                     }

                            }

                   }

                   //\r表示回到开头,输出的内容会覆盖之前的内容

                   printf("\r11月%02d号%02d:%02d:%02d",day,hours,minutes,second);

                   fflush(stdout);

                   #清空缓存,printf标准输出是行缓冲,没有换行需要清空缓冲区才能输出

         }

}


int main()

{

         intpid;

         signal(SIGALRM,handle);#信号安装,每次产生SIGALRM信号就调用handle

         if((pid = fork()) == 0)

         {

                   while(1)

                   {

                            kill(getppid(),SIGALRM);#给父进程发送SIGALRM信号

                            sleep(1);

                   }

         }

         while(1);#若没有死循环,父进程先退出,信号只发送了一次

         return0;

}

运行

gcc -o clock3 clock3.c

                            第十一周:进程通信实验-输入输出重定向

代码(文件名 redirection)

#include

#include

#include

#include

#include


int main()

{

         intfd;                  #定义test.txt文件的文件描述符

         pid_tpid;

         intfiledes[2];

         pipe(filedes );

         charbuf[80] = {0};

         printf("echo内容为:\n" );

         if(fork()== 0)

         {

                   charstr[] = "";

                  dup2( filedes[1], 1 );

                   close(filedes[0] );

                   scanf("%[^\n]",str);      #输出有空格的字符串

                   execlp("echo", "echo", str, (char *)0 );

                   close(filedes[1] );

         }    

         else{

                   fd= open( "test.txt", O_RDONLY | O_WRONLY | O_APPEND | O_CREAT );

                   close(filedes[1] );

                   read(filedes[0], buf, sizeof(buf) );  

#将管道读入的内容读到buf中

                   write(fd, buf, sizeof(buf) );  

#将buf中的内容写到文件test.txt中

                   close(filedes[0] );

             exit(0);

         }

         exit(0);

}

运行

gcc -o redirection redirection.c

./redirection

输入语句,回车运行

cat test.txt(查看是否定向输入成功)


                            第十二周:进程实验

实验内容:编写一段程序,要求:

(1)使用系统调用fork( )创建两个子进程。

(2)当此程序运行时,在系统中有一个父进程和两个子进程活动。

(3)让每一个进程在屏幕上显示一个字符:父进程显示字符“a”,子进程分别显示字符“b”和“c”。请多次运行后观察屏幕上的显示结果,并分析原因。

代码(文件名Process)

#include

#include

#include

#include


int main(void)

{

   pid_t pid;

   pid = fork();


   if (pid == 0)       

    {

       printf("b");

    }

   else                      

    {

                   pid= fork();

                   if(pid==0)

                            printf("c");

                   else

                            printf("a");

    }

   exit(EXIT_SUCCESS);

}                          

第十六周:线程实验

利用Linux多线程编程实现以下功能

(1)创建两个线程;

(2)父线程(生产者线程)依次向缓冲区写入整数0,1,2,...,19;

(3)子线程(消费者线程)暂停3s后,从缓冲区读数,每次读一个,并将读出的数字从缓冲区删除,然后将数字显示出来;

(4)父线程等待子线程(消费者线程)的退出信息“exit now”,当父线程接收到这条退出信息并打印后,则退出。

#include

#include

#include

#include

#include

char globe_buffer[100];

void *read_buffer_thread(void *arg);

int main(void)

         intres,i;

         pthread_tread_thread;

  for(i=0;i<20;i++)

                   globe_buffer[i]=i; 

         printf("\nxianchengthread : write buffer finish\n");

         sleep(3);

  res = pthread_create(&read_thread, NULL, read_buffer_thread, NULL);

   if(res != 0)

  {   

                   printf("ReadThread creat Error!");

            exit(0);

  }     

 sleep(1);

 printf("waiting for read thread to finish...\n");

  res= pthread_join(read_thread, NULL);

  if(res != 0)

 {   

                printf("read thread joinfailed!\n");

             exit(0);

  } 

 printf("read thread xiancheng OK, havefun!! exit ByeBye\n");

 return 0;

}  

void *read_buffer_thread(void *arg)

{

  inti,x; 

 printf("Read buffer thread read data : \n");    

 for(i=0;i<20;i++)    

 {         

         x=globe_buffer[i];

        printf("%d   ",x);

        globe_buffer[i]=0;

   }

  printf("\nread over\n");

}

你可能感兴趣的:(一学期的实验及答案)