导语
自编od C语言实现版名为myod
上个星期有一个初代版,链接- myod原版
这星期的课上要求实现myod-系统调用版本,要求如下
1 参考教材第十章内容
2 用Linux IO相关系统调用编写myod.c 用myod XXX实现Linux下od -tx -tc XXX的功能,注意XXX是文件名,通过命令行传入,不要让用户输入文件名
3.不要把代码都写入main函数中
4.要分模块,不要把代码都写入一个.c中
5 提交测试代码和运行结果截图, 提交调试过程截图,要全屏,包含自己的学号信息
程序思路
结构
- 判定命令行输入是否正确,错误则报错退出。
对文件进行录入并存入字符数组str[]
相关函数及头文件
函数 | 头文件 |
---|---|
open() | #include <sys/types.h>;#include <sys/stat.h>;#include <fcntl.h> |
read() | #include <unistd.h> |
- 输出八位表示的累计字符
- 输出最多十六个为一组的文本
- 输出该组文本各字符的ASCII码
- 对于每行最多处理16个字符,我使用的是for循环和一个计数函数count共同把控
变量说明
char str[BUFFERSIZE];存整个文本的字符串
int LJ;已累计表示了多少各字符
int SY;还剩下多少字符没有表示
int tSY,Dan;tSY其实是SY,但是为了分模块处理便于我自己的理解便改了个名称,Dan是单次表示字符个数,和tSY组合使用
int tx[8];char tx2[8];用于表示八位十六进制累计数字和ASCII码十六进制表示
补充知识点
- read()在Linux C下,可以直接在终端用man查看,或者下载中文的man帮助文档,如果懒得翻可以打开该链接—— read()
- open()同理—— 打开文件open()函数的使用方法详解--C语言函数
perror()同理——perror; perror 的用法
codeblocks整理代码:Plugins->Source code formatter(Astyle)
优化过程
代码对比
嫌弃版
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void One(int LJ,int tx[],char tx2[]);
void TX(int H,int tx[]);
char Change(int t);
void main(int argc,char *argv[])
{FILE *fp;if((fp = fopen(argv[4],"r")) == NULL){printf(" ***文件打开失败***");exit(0);}if(strcmp(argv[1], "od")==0){if(strcmp(argv[2], "-tc")==0){if(strcmp(argv[3], "-tx")==0){char str[1000];int num,i,j,i2;for(num=0; num<strlen(str); num++)str[num] = '0';num = 0;int fd;fd = open(argv[4], O_RDONLY);num = read(fd, str, sizeof(str));close(fd);int LJ;int SY;for(LJ = 0,SY = num;;){int tx[8];char tx2[8];for(j=0; j<8; j++)tx[j] = 0;One(LJ,tx,tx2);for(j=0; j<8; j++){printf("%c",tx2[j]);}printf(" ");//累计字符输出完毕int tSY,Dan;tSY = SY;// do// {if(tSY>=16){Dan = 16;}else{Dan = tSY;}for(j=LJ; j<Dan+LJ; j++){// printf("j = %d,Dan=%d\n",j,Dan);if(str[j]=='\n'){printf("\\n ");}else{printf("%c \t",str[j]);}}// putchar(str[i]);printf("\n");int tt;
//输出文本printf(" ");for(j=LJ; j<Dan+LJ; j++){tt = str[j];One(tt,tx,tx2);for(i2=0; i2<8; i2++){if(tx2[i2]!='0')printf("%c",tx2[i2]);}printf(" \t");}printf("\n");tSY = tSY-Dan;// }// while(tSY>0);printf("\n");// printf("SY=%d,LJ=%d\n",SY,LJ);if(SY>=16){LJ = LJ+16;}else if((SY>0)&&(SY<16)){LJ = LJ+SY;}else if(SY==0){break;}SY = num-LJ;// printf("SY=%d,LJ=%d\n",SY,LJ);}}}}else{printf("指令输入错误\n");}
// printf("\nover\n");fclose(fp);
}
void One(int LJ,int tx[],char tx2[]){TX(LJ,tx);int i;// printf("\n分界线\n");for(i=0; i<8; i++){// printf("%d ",tx[i]);tx2[i] = Change(tx[i]);// printf("%c",tx2[i]);}
}
void TX(int H,int tx[])
{if(H>536870911){printf("字符数太大,超出限制\n");exit (0);}int i=7;// printf("LS = %d\n",H);for(; i>0;){tx[i] = H%16;H = H/16;i--;
// printf(" H = %d,tx[%d] = %d\n",H,i+1,tx[i+1]);}
}
char Change(int t)
{// printf("scs\n");if((t>=0)&&(t<10)){return t+48;}else{return t+87;}
}
优化版
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define BUFFERSIZE 1000
void Change(int LJ,int tx[],char tx2[]);
void dToH(int H,int tx[]);
char intToChar(int t);
int count(int *tSY,int *Dan,int *LJ,int *SY,int *num);
void outputAscii(char tx2[],int Dan,int LJ,int tx[],char str[]);
void main(int argc,char *argv[])
{char str[BUFFERSIZE];int num,i,j,i2;int fd;if((strcmp(argv[1], "od")!=0)|(strcmp(argv[3], "-tc")!=0)|(strcmp(argv[2], "-tx")!=0)){printf("输入格式错误");exit(0);}for(num=0; num<strlen(str); num++)str[num] = '0';num = 0;if ( (fd = open(argv[4], O_RDONLY)) == -1 ){perror(argv[4]);exit(1);}num = read(fd, str, BUFFERSIZE);close(fd);int LJ;int SY;int tx[8];char tx2[8];int tSY,Dan;for(LJ = 0,SY = num;;){for(j=0; j<8; j++)tx[j] = 0;Change(LJ,tx,tx2);for(j=0; j<8; j++){printf("%c",tx2[j]);}printf(" ");//累计字符输出完毕tSY = SY;if(tSY>=16){Dan = 16;}else{Dan = tSY;}for(j=LJ; j<Dan+LJ; j++){if(str[j]=='\n'){printf("\\n ");}else{printf("%c \t",str[j]);}}printf("\n");//输出文本outputAscii(tx2,Dan,LJ,tx,str);if(2==count(&tSY,&Dan,&LJ,&SY,&num))exit(0);}
}
void Change(int LJ,int tx[],char tx2[]){dToH(LJ,tx);int i;for(i=0; i<8; i++){tx2[i] = intToChar(tx[i]);}
}
void dToH(int H,int tx[])//十进制转十六进制,但此时仍用int存储
{if(H>536870911){printf("字符数太大,超出限制\n");exit (0);}int i=7;for(; i>0;){tx[i] = H%16;H = H/16;i--;}
}
char intToChar(int t)//十六进制,把int[]转为char[]
{if((t>=0)&&(t<10)){return t+48;}else{return t+87;}
}
int count(int *tSY,int *Dan,int *LJ,int *SY,int *num)//计数并判定是否终止
{*tSY = *tSY-*Dan;printf("\n");if(*SY>=16){*LJ = *LJ+16;}else if((*SY>0)&&(*SY<16)){*LJ = *LJ+*SY;}else if(*SY==0){return 2;}*SY = *num-*LJ;return 1;
}
void outputAscii(char tx2[],int Dan,int LJ,int tx[],char str[])
{int tt,j,i2;printf(" ");for(j=LJ; j<Dan+LJ; j++){tt = str[j];Change(tt,tx,tx2);for(i2=0; i2<8; i2++){if(tx2[i2]!='0')break;}for(;i2<8;i2++)printf("%c",tx2[i2]);printf(" \t");}printf("\n");
}
改造过程
1.把没来得及删掉的用指针打开文件的那段fp = fopen(argv[4],"r"等删掉,有open就可以了
2.修改自编函数名称。当我回来再看代码时原先的名称确实无法提醒我到底它要做什么,(捂脸),所以组合型名称按照小驼峰式,单个词函数名用了首字母大写的方式,多谢老师指导与提醒~
3.判定命令行输入条件时取消那么多if,直接用“|”符号来限定选择条件
if((strcmp(argv[1], "od")!=0)|(strcmp(argv[3], "-tc")!=0)|(strcmp(argv[2], "-tx")!=0))
4.将存文本的字符大小用宏定义BUFFERSIZE,提高程序的可读性与可维护性。解释:比如我想存一个10000的文本,但是之前的str[]只有1000,所以我只需要把define那里的BUFFERSIZE改掉,后面的就不用改了,否则还得满篇找1000改10000,这个程序短,所以还不觉得有什么,但是程序如果很大很复杂,这种情况不仅维护的人不好读懂代码,而且容易改漏。
5.使用perror()函数,添加报错功能。
6.将计数和输出ASCII码的功能从主函数中分离出来成为自编函数,使主程序显得不那么臃肿,更好读懂。
7.修改了一个程序上的错误
for(i2=0; i2<8; i2++){if(tx2[i2]!='0')printf("%c",tx2[i2]);}
这个输出会把所有0给抹掉,也是优化的时候才发现这个错误(捂脸)
修改为:
for(i2=0; i2<8; i2++){if(tx2[i2]!='0')break;}for(;i2<8;i2++)printf("%c",tx2[i2]);
代码链接
myod嫌弃版(合体)
myod优化版(合体)
myod优化版(模块化)
一阵瞎逼逼
第一个版本我本来就实现了命令行调用,并且并未只写在一个main函数里,就只需要改两个函数就可以了。当时课上电脑不知道被我改了哪里,找不到网络的开关……慌慌地改了代码交了,觉得代码还是有点丑,想着怎么再改改,眼瞎也没看到还有展开项-提交代码……
看到老师对之前博客的评论,越看我的代码越觉得……好嫌弃,确实需要好好改一改。于是真的有不少地方可以改……就有了对二代版的优化版。
之所以单开一篇博客是为了方便我日后记不到了好查找资料。是的,作为一个暑假之后就忘了放在学校电脑的开机密码的人真的不能对自己的记忆力多有信心。以后可能会在自己的博客里记录一些非常简单的知识。反正最终都会忘掉的,不如让再次自学的时候能轻松高效一些。