第一周:Linux环境搭建——虚拟机文件共享
① 右键新建终端
② 键入ifconfig
③ 键入ifconfig eth0 up
④ 键入service network restart
⑤ 键入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"); } 第十周:进程通信实验-电子表
第十一周:进程通信实验-输入输出重定向
第十二周:进程实验
第十六周:线程实验