linux|南邮——实验3:C程序设计实验

 

实验三 C程序设计实验 
实验目的:
巩固Make使用和C程序设计语言基本语法,加深对所学知识理解。
(1) 编写一 C 程序,采用标准 I/O 库显示文本文件的内容(cat 命令)。该程序的编译和链接用 make 工具来实现,要求先产生.o 文件,再产生可执行文件,并且在 makefile 文件中具备删除中间文件(.o)的功能。

(2)编写一 C 程序,显示当前目录下的所有文件名(ls 命令)。该程序的编译和链接用 make 工具来实现,要求先产生.o 文件,再产生可执行文件,并且在 makefile 文件中具备删除中间文件(.o)的功能。

(3) 编写一个 C 程序,改变当前进程的工作目录(cd 命令)。该程序的编译和链接用 make 工具来实现,要求先产生.o 文件,再产生可执行文件,并且在 makefile 文件中具备删除中间文件(.o)的功能

实验一:c语言实现cat命令

实验过程:

1、编写c文件实现cat命令

文件内容如下:

#include <stdio.h>
int main(int argc, char *argv[])
{
    FILE *fp = fopen(argv[1], "r");   // 以只读方式打开文件,argv[1]是输入的要显示的文件路径名
    int read_ret;
    if(argc < 2)  //说明没有输入要显示的文件名,只有本程序名argv[0]
    {
        printf("please input source file!\n");
    }
    if(fp == NULL)  //如果打开成功的话就把该文件的信息结构体地址赋给文件指针fp,如果打开不成功的话就将文件指针fp置为无效(NULL)
    {
        printf("open source %s failed!\n", argv[1]);
        return -1;
    }
    while(1)  //成功打开
    {
        read_ret = fgetc(fp);  //单个字符读写
        if(feof(fp))  // feof判断文件结束,若fp已经指向文件末尾,则feof(fp)函数值为“真”,即返回非零值
        {
            printf("read file %s endl\n",argv[1]);   //提示读写结束       
            break;
        }
        fputc(read_ret,stdout);  //把单个字符输出到屏幕
    }
}

2、编写makefile文件,编写编译过程

2.1、makefile的规则如下:

 target ... 
 prerequisites ...
 command...
target也就是一个目标文件,可以是object file,也可以是执行文件。
prerequisites就是,要生成那个target所需要的文件或是目标。
command也就是make需要执行的命令。(任意的shell命令)
这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于 prerequisites中的文件,其生成规则定义在 command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是makefile的规则。

2.2、clean

clean不是一个文件,它只不过是一个动作名字,有点像c语言中的lable一样,其冒号后什么也没有,那么,make就不会自动去找它的依赖性,也就不会自动执行其后所定义的命令。要执行其后的命令(不仅用于clean,其他lable同样适用),就要在make命令后明显得指出这个lable的名字。

.PHONY clean意思表示clean是一个“伪目标”。而在rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事(假设手动删掉了一个文件,保证其他文件也能删除)。

2.3、makefile文件的命名

默认的情况下,make命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“makefile”、“Makefile”的文件,找到了解释这个文件。当然,也可以使用别的文件名来书写Makefile,比如:“Make.Linux”,“Make.Solaris”,“Make.AIX”等,如果要指定特定的Makefile,你可以使用make的“-f”和“--file”参数,如:make -f Make.Linux或make --file Make.AIX。

2.4、makefile文件的编写

使用vim编写makefile文件,编译cat.c文件,并编写相应的清除功能。

cat.o:cat.c
        gcc -o cato cat.c
.PHONY : clean
clean :
        -rm cato

3、编译、链接

编译:由于该makefile命名为Make.cat,故编译选择make -f Make.cat

链接:链接.out文件形成可执行代码。由于cat.c文件的函数需要实参,故链接时写入相应的实参,即文件名,由于本题要求cat输出代码的内容,故实参为cat.c

清除clean命令时候报错

后查明,因为我修改makefile文件名为Make.cat故执行其对应的clean命令需要输入文件名,故正确的输入为make -f Make.cat clean

4、实验结果

 

 

实验二:编写c语言实现ls命令

1、编写c语言实现ls命令

采用C语言编写程序,实现以下LS命令。

-a:显示所有档案及目录(ls内定将档案名或目录名称为“.”的视为影藏,不会列出);

-l:与“-C”选项功能相反,所有输出信息用单列格式输出,不输出为多列;

-d:仅显示目录名,而不显示目录下的内容列表。显示符号链接文件本身,而不显示其所指向的目录列表;

-i:显示文件索引节点号(inode)。一个索引节点代表一个文件;

-R:递归处理,将指定目录下的所有文件及子目录一并处理;

代码如下:

 #include <stdio.h>  
    #include <sys/types.h>  
    #include <dirent.h>  
    #include <sys/stat.h>  
    #include <pwd.h>  
    #include <grp.h>  
    #include <unistd.h>  
    #include <string.h>  
      
    #define LS_NONE 0  
    #define LS_L 101  
    #define LS_R 102  
    #define LS_D 103  
    #define LS_I 104  
      
    #define LS_A 200  
      
    #define LS_AL (LS_A+LS_L)  
    #define LS_AI (LS_A+LS_I)  
      
    // 展示单个文件的详细信息  
    void show_file_info(char* filename, struct stat* info_p)  
    {  
        char* uid_to_name(), *ctime(), *gid_to_name(), *filemode();  
        void mode_to_letters();  
        char modestr[11];  
        mode_to_letters(info_p->st_mode, modestr);  
      
        printf("%s", modestr);  
        printf(" %4d", (int) info_p->st_nlink);  
        printf(" %-8s", uid_to_name(info_p->st_uid));  
        printf(" %-8s", gid_to_name(info_p->st_gid));  
        printf(" %8ld", (long) info_p->st_size);  
        printf(" %.12s", 4 + ctime(&info_p->st_mtime));  
        printf(" %s\n", filename);  
    }  
      
    void mode_to_letters(int mode, char str[])  
    {  
        strcpy(str, "----------");  
      
        if (S_ISDIR(mode))  
        {  
            str[0] = 'd';  
        }  
      
        if (S_ISCHR(mode))  
        {  
            str[0] = 'c';  
        }  
      
        if (S_ISBLK(mode))  
        {  
            str[0] = 'b';  
        }  
      
        if ((mode & S_IRUSR))  
        {  
            str[1] = 'r';  
        }  
      
        if ((mode & S_IWUSR))  
        {  
            str[2] = 'w';  
        }  
      
        if ((mode & S_IXUSR))  
        {  
            str[3] = 'x';  
        }  
      
        if ((mode & S_IRGRP))  
        {  
            str[4] = 'r';  
        }  
      
        if ((mode & S_IWGRP))  
        {  
            str[5] = 'w';  
        }  
      
        if ((mode & S_IXGRP))  
        {  
            str[6] = 'x';  
        }  
      
        if ((mode & S_IROTH))  
        {  
            str[7] = 'r';  
        }  
      
        if ((mode & S_IWOTH))  
        {  
            str[8] = 'w';  
        }  
      
        if ((mode & S_IXOTH))  
        {  
            str[9] = 'x';  
        }  
    }  
      
    char* uid_to_name(uid_t uid)  
    {  
        struct passwd* getpwuid(),* pw_ptr;  
        static char numstr[10];  
      
        if((pw_ptr = getpwuid(uid)) == NULL)  
        {  
            sprintf(numstr,"%d",uid);  
      
            return numstr;  
        }  
        else  
        {  
            return pw_ptr->pw_name;  
        }  
    }  
      
    char* gid_to_name(gid_t gid)  
    {  
        struct group* getgrgid(),* grp_ptr;  
        static char numstr[10];  
      
        if(( grp_ptr = getgrgid(gid)) == NULL)  
        {  
            sprintf(numstr,"%d",gid);  
            return numstr;  
        }  
        else  
        {  
            return grp_ptr->gr_name;  
        }  
    }  
      
    void do_ls(char dirname[],int mode)  
    {  
        DIR* dir_ptr;  
        struct dirent* direntp;  
      
        if ((dir_ptr = opendir(dirname)) == NULL)  
        {  
            fprintf(stderr, "ls2: cannot open %s \n", dirname);  
        }  
        else  
        {  
            if(mode==LS_D)  
            {  
                printf("%s\n", dirname);  
            }  
            else  
            {  
                char dirs[20][100];  
                int dir_count = 0;  
                  
                while ((direntp = readdir(dir_ptr)) != NULL)  
                {  
      
                    if(mode < 200 && direntp->d_name[0]=='.')  
                    {  
                        continue;  
                    }  
      
                    char complete_d_name[200];  // 文件的完整路径  
                    strcpy (complete_d_name,dirname);  
                    strcat (complete_d_name,"/");  
                    strcat (complete_d_name,direntp->d_name);  
                      
                    struct stat info;  
                    if (stat(complete_d_name, &info) == -1)  
                    {  
                        perror(complete_d_name);  
                    }  
                    else  
                    {  
                        if(mode == LS_L||mode == LS_AL)  
                        {  
                            show_file_info(direntp->d_name, &info);  
                        }  
                        else if(mode == LS_A||mode == LS_NONE||mode == LS_I||mode == LS_AI)  
                        {  
                            if(mode == LS_I||mode == LS_AI)  
                            {  
                                printf("%llu ", direntp->d_ino);  
                            }  
      
                            printf("%s\n", direntp->d_name);  
                        }  
                        else if(mode == LS_R)  
                        {  
      
                            if(S_ISDIR(info.st_mode))  
                            {  
                                printf("%s\n", direntp->d_name);  
      
                                strcpy (dirs[dir_count],complete_d_name);  
                                dir_count++;  
                            }  
                            else  
                            {  
                                printf("%s\n", direntp->d_name);  
                            }  
                        }  
      
                    }  
                }  
      
                if(mode == LS_R)  
                {  
                    int i=0;  
                    printf("\n");  
                    for(;i<dir_count;i++){  
                        printf("%s:\n", dirs[i]);  
                        do_ls(dirs[i],LS_R);  
                        printf("\n");  
                    }  
                }  
      
            }  
      
            closedir(dir_ptr);  
        }  
    }  
      
    // 解析一个单词参数,如-l,-i  
    int analyzeParam(char* input){  
        if(strlen(input)==2)  
        {  
            if(input[1]=='l') return LS_L;  
            if(input[1]=='a') return LS_A;  
            if(input[1]=='d') return LS_D;  
            if(input[1]=='R') return LS_R;  
            if(input[1]=='i') return LS_I;  
        }  
        else if(strlen(input)==3)  
        {  
            if(input[1]=='a'&& input[2]=='l') return LS_AL;  
            if(input[1]=='a'&& input[2]=='i') return LS_AI;  
        }  
        return -1;  
    }  
      
    int main(int ac,char* av[])  
    {  
      
        if(ac == 1)  
        {  
            do_ls(".",LS_NONE);  
        }  
        else  
        {  
            int mode = LS_NONE; // 默认为无参数ls  
            int have_file_param = 0; // 是否有输入文件参数  
      
            while(ac>1)  
            {  
                ac--;  
                av++;  
      
                int calMode = analyzeParam(*av);  
                if(calMode!=-1)  
                {  
                    mode+=calMode;  
                }  
                else  
                {  
                    have_file_param = 1;  
                    do  
                    {  
                        printf("%s:\n", *av);  
                        do_ls(*av,mode);  
                        printf("\n");  
      
                        ac--;  
                        av++;  
                    }while(ac>=1);  
                }  
            }  
      
            if (!have_file_param)  
            {  
                do_ls(".",mode);  
            }  
              
        }       
    }  

2、编写makefile文件,编写编译过程

使用vim编写makefile文件,编译ls.c文件,并编写相应的清除功能。

ls.o:ls.c
        gcc -o lso ls.c 
.PHONY : clean
clean :
        -rm ls0

3、编译、链接

编译:由于该makefile命名为Make.ls,故编译选择make -f Make.ls

链接:链接.out文件形成可执行代码。由于cat.c文件的函数需要实参,故链接时写入相应的实参,即文件名,由于本题要求cat输出代码的内容,故实参分别为-a,-i,-l,-R,-d

Ubuntu gcc编译报错:format ‘%llu’ expects argument of type ‘long long unsigned int’, but argument 2 has type ‘__time_t’ [-Wformat=]百度后得知gcc ls.c -Wformat=0 就没问题了。Wformat这个配置在Centos下默认是关闭的,所以一直没报错,如果编译的时候打开,也会提示一样的错误。

修改为:

ls.o:ls.c
        gcc -o lso ls.c -Wformat=0
.PHONY : clean
clean :
        -rm lso

4、实验结果

ls -a

ls -d ,ls -i

ls -l

ls -R

删除.o文件

实验三:编写c文件实现cd命令

1、编写c文件代码

 

 

 

 

#include<stdio.h>
#define PATH_SIZE 100
#define BUF_SIZE 64
int cds(const char *p)
{
	char path[PATH_SIZE];
	char *start;
	char *end;
	int res;
	int n= 0;
 
	memset(path,'\0',PATH_SIZE); // must init 
	start = strchr(p,' ');
	end = strchr(p,'\n');
	if(!start || !end)
	{
		printf("can't support this format \n");
		return 1;
	}
 
	strncpy(path,p+3,end-start-1); // get the path in inputting command
 
	res = chdir(path); //change dir
 
	if(res != 0)
		printf("%s is nod a path,please check again \n",path);
 
	return res;
}
int pwds()
{
    char buf[PATH_SIZE];
    char *res;
 
    res = getcwd(buf,PATH_SIZE);
 
    if(res)
    {
        printf("%s\n",buf);
        return 0;
    }
    else
        return 1;
}
int main(int argc, char *argv[])
{
char buf[BUF_SIZE];
printf("|->");
fgets(buf,BUF_SIZE,stdin);
cds(buf);
printf("you have cd successfully,the directory now is:\n");
pwds();
 
}

2、编写makefile文件,实现cd.c文件的编译,以及相关文件的删除

cd.o:cd.c
        gcc -o cdo cd.c
.PHONY : clean
clean :
        -rm cdo

3、编译、链接

编译:由于该makefile命名为Make.cd,故编译选择make -f Make.cd

编译报错:

百度后得知,memset函数.需要包含include <string.h>故在源代码填上#include <string.h>

之后有报错

百度后知道了,char *getcwd(char *buf, size_t size);

作用:把当前目录的绝对地址保存到 buf 中,buf 的大小为 size。如果 size太小无法保存该地址,返回 NULL 并设置 errno 为 ERANGE。可以采取令 buf 为 NULL并使 size 为0来使 getcwd 调用 malloc 动态给 buf 分配,但是这种情况要特别注意使用后释放缓冲以防止内存泄漏。需要头文件#include <unistd.h>

故再填上#include <unistd.h>

链接:链接.out文件形成可执行代码。代码,./cdo

4、实验过程

清理.o文件(cd后是两个tab键,自动补全文件名)

实验总结

    这次实验让我更加了解了make编译器的使用和编写,也对于.c文件的编译链接过程有更进一步理解和掌握。同时对于对于编写总出现bug有了进一步应对的措施,谨记不会就问度娘,其中针对implicit declaration of function xxx,大概率就是你运用的函数没有引用函数所在的头文件,可以百度一下该函数,就可以知道它所需要的头文件了,还有一种可能就是xxx是你编写的函数,但你在用它之前没有函数说明,需要在mian()函数前写一下所用函数的函数说明,就可以用了。

参考链接

 

https://www.cnblogs.com/aiguona/p/9162500.html

https://blog.csdn.net/qq_36946026/article/details/80273842

https://blog.csdn.net/skyejy/article/details/89922298

https://blog.csdn.net/itworld123/article/details/79348693?utm_source=blogxgwz2

https://blog.csdn.net/weixin_43387612/article/details/89259944

https://baike.baidu.com/item/getcwd/4746955?fr=aladdin

https://blog.csdn.net/abc13526222160/article/details/94853883

https://www.cnblogs.com/likui360/p/5275203.html

https://blog.csdn.net/xiao_xiaoli/article/details/12321667?locationNum=3

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值