zoukankan      html  css  js  c++  java
  • 2021-2022-diocs-Linux C语言编程基础(必做)

    20191218 2021-2022-diocs-Linux C语言编程基础(必做)

    一、任务详情

    1. 基于Ubuntu或OpenEuler完成下面的任务(OpenEuler有加分)
    2. 选择教材第二章的一节进行编程基础练习(2.10,2.11,2.12,2.13,2.14任选一个)
    3. 建立自己的项目目录,包含自己学号信息(如20190100linkedlist),构建项目结构(src, include, bin, lib, docs, test...),然后把相应代码和文档放置到正确位置,用tree命令查看项目结构,提交截图(5分)
    4. 进行gcc相关练习(ESc, iso, -I等)提交相关截图(5分)
    5. 进行静态库,动态库制作和调用练习,提交相关截图(5分)
    6. 进行gdb相关练习,至少包含四种断点的设置,提交相关截图(10分)
    7. 编写makefile(5分)

    二、实践过程

    所有实践内容均在OpenEuler下完成,相应代码已上传至码云:第三周代码

    1. 习题2.11
      实现代码
    #include <stdio.h>
    #include <stdlib.h>
    #define TElemType int
    //初始化队头和队尾指针开始时都为0
    int front=0,rear=0;
    
    typedef struct BiTNode{
        TElemType data;//数据域
        struct BiTNode *lchild,*rchild;//左右孩子指针
    }BiTNode,*BiTree;
    void CreateBiTree(BiTree *T){
        *T=(BiTNode*)malloc(sizeof(BiTNode));
        (*T)->data=1;
        (*T)->lchild=(BiTNode*)malloc(sizeof(BiTNode));
        (*T)->rchild=(BiTNode*)malloc(sizeof(BiTNode));
       
        (*T)->lchild->data=2;
        (*T)->lchild->lchild=(BiTNode*)malloc(sizeof(BiTNode));
        (*T)->lchild->rchild=(BiTNode*)malloc(sizeof(BiTNode));
        (*T)->lchild->rchild->data=NULL;
        (*T)->lchild->rchild->lchild=NULL;
        (*T)->lchild->rchild->rchild=NULL;
       
        (*T)->rchild->data=3;
        (*T)->rchild->lchild=(BiTNode*)malloc(sizeof(BiTNode));
        (*T)->rchild->lchild->data=6;
        (*T)->rchild->lchild->lchild=NULL;
        (*T)->rchild->lchild->rchild=NULL;
       
        (*T)->rchild->rchild=(BiTNode*)malloc(sizeof(BiTNode));
        (*T)->rchild->rchild->data=7;
        (*T)->rchild->rchild->lchild=NULL;
        (*T)->rchild->rchild->rchild=NULL;
       
        (*T)->lchild->lchild->data=4;
        (*T)->lchild->lchild->lchild=NULL;
        (*T)->lchild->lchild->rchild=NULL;
    }
    //入队函数
    void EnQueue(BiTree *a,BiTree node){
        a[rear++]=node;
    }
    //出队函数
    BiTNode* DeQueue(BiTNode** a){
        return a[front++];
    }
    //输出函数
    void displayNode(BiTree node){
        if (node->data == 0)
        	printf("- ");
    	else printf("%d ",node->data);
    }
    int main() {
        BiTree tree;
        //初始化二叉树
        CreateBiTree(&tree);
        BiTNode * p;
        //采用顺序队列,初始化创建队列数组
        BiTree a[20];
        //根结点入队
        EnQueue(a, tree);
        //当队头和队尾相等时,表示队列为空
        while(front<rear) {
            //队头结点出队
            p=DeQueue(a);
            displayNode(p);
            //将队头结点的左右孩子依次入队
            if (p->lchild!=NULL) {
                EnQueue(a, p->lchild);
            }
            if (p->rchild!=NULL) {
                EnQueue(a, p->rchild);
            }
        }
        return 0;
    }
    
    
    

    其中,对教材上所提供的代码作出的主要修改在如下部分,添加了一个节点是否为空的判断

    void displayNode(BiTree node){
        if (node->data == 0)
        	printf("- ");
    	else printf("%d ",node->data);
    

    在OpenEuler下运行结果,实现题目要求。

    1. gcc相关练习
      同时复习C语言文件操作,实现功能为文本文件和二进制文件的转换。
      分为三个文件,BinIO.c中存放main函数,BinIO_func.c中存放其余被调用函数,BinIO.h中存放所需头文件以及结构体定义。
      BinIO.c
    #include "BinIO.h"
    /**
     *代码实例是将文本文件写入二进制文件,然后从二进制文件中读取,再写入到
     *文本文件中去
     */
    int main(int argc,char *argv[]){
        if(argc !=4 ){
            printf("缺少参数
    ");
            exit(EXIT_FAILURE);
        }
        text_to_bin(argv);
        bin_to_text(argv);
        return  0;
    }
    

    BinIO_func.c

    #include "BinIO.h"
    void text_to_bin();
    void bin_to_text();
    
    void text_to_bin(char *argv[]){
        FILE *source_file_pointer;
        FILE *des_file_pointer;
        Stu stu = {1,"demo",0,0,0};
        source_file_pointer = fopen(argv[1],"r");
        if(source_file_pointer == NULL){
            printf("open text source file failed
    ");
            exit(EXIT_FAILURE);
        }
    
        des_file_pointer = fopen(argv[2],"wb");
        if(des_file_pointer == NULL){
            printf("open bin source file failed
    ");
            exit(EXIT_FAILURE);
        }
    
        while(fscanf(source_file_pointer,"%d %s %d %d %d",&stu.xh,stu.name,&stu.math_score,&stu.english_score,&stu.chinese_score) != EOF ){
            fwrite(&stu,sizeof(stu),1,des_file_pointer);
        }
        int source_close_result = fclose(source_file_pointer);
        if(source_close_result == EOF){
            printf("close source file failed
    ");
            exit(EXIT_FAILURE);
        }else{
            printf("close source file success
    ");
        }
    
        int des_close_result = fclose(des_file_pointer);
        if(des_close_result == EOF){
            printf("close des file  failed
    ");
            exit(EXIT_FAILURE);
        }else{
            printf("close des file success
    ");
        }
    
    }
    
    
    void bin_to_text(char *argv[]){
        FILE *bin_source_file_pointer;
        FILE *text_des_file_pointer;
        Stu stu = {1,"z",0,0,0};
        bin_source_file_pointer = fopen(argv[2],"rb");
        if(bin_source_file_pointer == NULL){
            printf("open bin_source_file failed
    ");
            //perror(argv[2]);
            exit(EXIT_FAILURE);
        }else{
            printf("open bin_source_file success
    ");
        }
    
        text_des_file_pointer = fopen(argv[3],"w");
        if(text_des_file_pointer == NULL){
            printf("open text des file failed
    ");
            perror(argv[3]);
            exit(EXIT_FAILURE);
        }else{
            printf("open text_des file success
    ");
        }
    
        while(fread(&stu,sizeof(stu),1,bin_source_file_pointer)){
            fprintf(text_des_file_pointer,"%d %s %d %d %d
    ",stu.xh,stu.name,stu.math_score,stu.english_score,stu.chinese_score);
        }
    
        int bin_source_file_close_result = fclose(bin_source_file_pointer);
        if(bin_source_file_close_result == EOF){
            printf("close bin_source_close_file error
    ");
            exit(EXIT_FAILURE);
        }else{
            printf("close bin_source_close_file success
    ");
        }
        int text_des_file_close_result = fclose(text_des_file_pointer);
        if(text_des_file_close_result == EOF){
            printf("close text_des_file error
    ");
            exit(EXIT_FAILURE);
        }else{
            printf("close text_des_file success
    ");
        }
    }
    

    BinIO.h

    #ifndef _BINIO_H_
    #define _BINIO_H
     
    #include<stdio.h>
    #include<stdlib.h>
    
    typedef struct student{
        int xh;
        char name[20];
        int math_score;
        int english_score;
        int chinese_score;
    }Stu;
    
    void text_to_bin();
    void bin_to_text();
    
    #endif
    

    实践过程

    在直接编译时一定注意每次都不能忘掉-Iinclude,以确定头文件所在位置

    编译好后tree下的项目结构图

    首次运行时发现文件内容并没有被改变,检查问题
    在进行编程时,我本来是将这几部分合在一起的并且能够正常运行。为了练习gcc的使用(多文件链接)才将一个文件拆开,可是真正运行时发现程序根本没有办法终止,而是一直在往temp这个二进制文件中写入数据。我特意在较为熟悉的Windows下尝试运行,发现


    程序一直在执行文本文件向二进制文件的写入操作,可以看到new1.txt文件甚至已经到了8GB!受时间关系此问题还没解决,在此做一个占位。
    于是我又尝试了另一C程序的编译运行

    用C语言大数的阶乘(数组实现)
    实现代码

    #include <stdio.h>
    
    int a[10000];
    
    int main()
    {
    	int n, digit = 1, temp, i, j, carry;
    	scanf("%d", &n);
    	a[0] = 1;
    	for (i = 2; i <= n; i++)  
    	{
    		carry = 0;
    		for (j = 1; j <= digit; j++)
    		{
    			temp = a[j-1] * i + carry; 
    			a[j-1] = temp % 10; 
    			carry = temp / 10; 
    		}
    		while (carry)
    		{
    			a[++digit - 1] = carry % 10;
    			carry = carry / 10; 
    		}
    	}
    	for (j = digit; j >= 1; j--)
    		printf("%d", a[j-1]);
    
    	return 0;
    }
    

    1. 静态库、动态库相关练习
    • 制作静态库和动态库

      • 静态库

        注意在第一次制作静态库时加上-Iinclude链接头文件,生成.a静态库之后可以不需要再加,直接编译即可。
      • 动态库

        注意每次都要加-Iinclude。
    • myod(选做)项目中的练习
      tree下的结构图

      用静态库运行myod结果

      可以看到实现了od -tx -tc XXX的要求

    • 动态库

      上面这张截图中我忘记添加-o参数指定输出路径,在当前目录下生成了a.out,下图是修改后的。

      下图是在动态库下的运行结果

    1. gdb的练习

    首先编译生成可执行文件(这里的test.c的功能是:从键盘读入一个整数,判断其是否是回文数和素数)。

    gcc -g src/test.c src/test_fucnc.c -o resource/test
    其中-g选项告诉gcc在编译程序时加入调试信息。

    在其中遇到的问题

    开始以为是由于调用了math.h库,而本目录和include目录中都不包含的这个,需要重新写头文件并放在include目录下

    然而并不是这个问题,查阅资料发现在Linux系统下,C源文件若调用了math库里的函数,则编译时要加上-lm,表示链接到math库。

    问题成功解决

    接下来
    使用gdb resource/test

    可参考博客:https://blog.csdn.net/weixin_33881050/article/details/92279415
    然后你就会看到屏幕出现许多信息,是一些关于gdb的版本信息说明之类内容的,但是它对调试程序没用,可以加上-q参数。

    下面是一些常用的GDB调试命令

    (gdb)help:查看命令帮助,具体命令查询在gdb中输入help + 命令,简写h
    
    (gdb)run:重新开始运行文件(run-text:加载文本文件,run-bin:加载二进制文件),简写r
    
    (gdb)start:单步执行,运行程序,停在第一执行语句
    
    (gdb)list:查看原代码(list-n,从第n行开始查看代码。list+ 函数名:查看具体函数),简写l
    
    (gdb)set:设置变量的值
    
    (gdb)next:单步调试(逐过程,函数直接执行),简写n
    
    (gdb)step:单步调试(逐语句:跳入自定义函数内部执行),简写s
    
    (gdb)backtrace:查看函数的调用的栈帧和层级关系,简写bt
    
    (gdb)frame:切换函数的栈帧,简写f
    
    (gdb)info:查看函数内部局部变量的数值,简写i
    
    (gdb)finish:结束当前函数,返回到函数调用点
    
    (gdb)continue:继续运行,简写c
    
    (gdb)print:打印值及地址,简写p
    
    (gdb)quit:退出gdb,简写q
    
    (gdb)break+num:在第num行设置断点,简写b
    
    (gdb)info breakpoints:查看当前设置的所有断点
    
    (gdb)delete breakpoints num:删除第num个断点,简写d
    
    (gdb)display:追踪查看具体变量值
    
    (gdb)undisplay:取消追踪观察变量
    
    (gdb)watch:被设置观察点的变量发生修改时,打印显示
    
    (gdb)i watch:显示观察点
    
    (gdb)enable breakpoints:启用断点
    
    (gdb)disable breakpoints:禁用断点
    
    (gdb)x:查看内存x/20xw 显示20个单元,16进制,4字节每单元
    
    (gdb)run argv[1] argv[2]:调试时命令行传参 
    
    

    练习过程截图

    • 设置断点
      包括函数断点、临时断点、行断点、条件断点

    • 跟踪调试

      • 单步跟踪
      • 下一步调试
    • 综合实践
      所测试程序功能为:从键盘读入两个数,输出它们的和。



    1. Makefile的练习

      makefile在之前已经完成过,有关的练习见myod选做项目博客:20191218 2021-2022-diocs-MyOD
      注意gdb调试中参数n(next)和参数s(step)的区别,其中n是直接跳过一个函数,而s是进入函数一步。我们在调试时要优先使用n,再使用s,这样先大后小有助于缩小问题范围。
  • 相关阅读:
    刘志博 作业 2.15
    刘志博 作业2.6
    作业一
    2.6
    张靖悦
    java 2.15
    java 2.6
    java 1.12
    java 1.8
    java 1.3
  • 原文地址:https://www.cnblogs.com/20191218tangqiheng/p/15327422.html
Copyright © 2011-2022 走看看