2021-2022-diocs-Linux C语言编程基础(必做)
2021/9/26 7:12:39
本文主要是介绍2021-2022-diocs-Linux C语言编程基础(必做),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
20191218 2021-2022-diocs-Linux C语言编程基础(必做)
一、任务详情
- 基于Ubuntu或OpenEuler完成下面的任务(OpenEuler有加分)
- 选择教材第二章的一节进行编程基础练习(2.10,2.11,2.12,2.13,2.14任选一个)
- 建立自己的项目目录,包含自己学号信息(如20190100linkedlist),构建项目结构(src, include, bin, lib, docs, test...),然后把相应代码和文档放置到正确位置,用tree命令查看项目结构,提交截图(5分)
- 进行gcc相关练习(ESc, iso, -I等)提交相关截图(5分)
- 进行静态库,动态库制作和调用练习,提交相关截图(5分)
- 进行gdb相关练习,至少包含四种断点的设置,提交相关截图(10分)
- 编写makefile(5分)
二、实践过程
所有实践内容均在OpenEuler下完成,相应代码已上传至码云:第三周代码。
- 习题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下运行结果,实现题目要求。
- 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("缺少参数\n"); 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\n"); exit(EXIT_FAILURE); } des_file_pointer = fopen(argv[2],"wb"); if(des_file_pointer == NULL){ printf("open bin source file failed\n"); 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\n"); exit(EXIT_FAILURE); }else{ printf("close source file success\n"); } int des_close_result = fclose(des_file_pointer); if(des_close_result == EOF){ printf("close des file failed\n"); exit(EXIT_FAILURE); }else{ printf("close des file success\n"); } } 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\n"); //perror(argv[2]); exit(EXIT_FAILURE); }else{ printf("open bin_source_file success\n"); } text_des_file_pointer = fopen(argv[3],"w"); if(text_des_file_pointer == NULL){ printf("open text des file failed\n"); perror(argv[3]); exit(EXIT_FAILURE); }else{ printf("open text_des file success\n"); } while(fread(&stu,sizeof(stu),1,bin_source_file_pointer)){ fprintf(text_des_file_pointer,"%d %s %d %d %d\n",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\n"); exit(EXIT_FAILURE); }else{ printf("close bin_source_close_file success\n"); } int text_des_file_close_result = fclose(text_des_file_pointer); if(text_des_file_close_result == EOF){ printf("close text_des_file error\n"); exit(EXIT_FAILURE); }else{ printf("close text_des_file success\n"); } }
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; }
- 静态库、动态库相关练习
-
制作静态库和动态库
- 静态库
注意在第一次制作静态库时加上-Iinclude链接头文件,生成.a静态库之后可以不需要再加,直接编译即可。 - 动态库
注意每次都要加-Iinclude。
- 静态库
-
myod(选做)项目中的练习
tree下的结构图
用静态库运行myod结果
可以看到实现了od -tx -tc XXX
的要求 -
动态库
上面这张截图中我忘记添加-o参数指定输出路径,在当前目录下生成了a.out,下图是修改后的。
下图是在动态库下的运行结果
- 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]:调试时命令行传参
练习过程截图
- 设置断点
包括函数断点、临时断点、行断点、条件断点
- 跟踪调试
- 单步跟踪
- 下一步调试
- 单步跟踪
- Makefile的练习
makefile在之前已经完成过,有关的练习见myod选做项目博客:20191218 2021-2022-diocs-MyOD
这篇关于2021-2022-diocs-Linux C语言编程基础(必做)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-12如何创建可引导的 ESXi USB 安装介质 (macOS, Linux, Windows)
- 2024-11-08linux的 vi编辑器中搜索关键字有哪些常用的命令和技巧?-icode9专业技术文章分享
- 2024-11-08在 Linux 的 vi 或 vim 编辑器中什么命令可以直接跳到文件的结尾?-icode9专业技术文章分享
- 2024-10-22原生鸿蒙操作系统HarmonyOS NEXT(HarmonyOS 5)正式发布
- 2024-10-18操作系统入门教程:新手必看的基本操作指南
- 2024-10-18初学者必看:操作系统入门全攻略
- 2024-10-17操作系统入门教程:轻松掌握操作系统基础知识
- 2024-09-11Linux部署Scrapy学习:入门级指南
- 2024-09-11Linux部署Scrapy:入门级指南
- 2024-08-21【Linux】分区向左扩容的方法