通信原理课设(gec6818) 001:环境配置+文件操作
目录
2、在一个1.txt的前面4个字节放了一个千位数,以 %d的形式输出它的两倍
3、写一个简单的学生信息录入系统:学生信息包括:姓名 学号 年龄 地址 从终端输入学生信息写入到文件里面保存,一个学生一行数据
简单记录一下为期两周的通信原理课设,本次课设采用交叉编译,所谓交叉编译是指一种计算机环境中运行的编译程序,能编译出在另外一种环境下运行的代码。简而言之即在一个平台上生成另一个平台上的可执行代码。此次课设的代码先在ubuntu里面使用arm-linux-gcc编译,再利用SecureCRT将编译好的文件传输到开发板上。
Securecrt网盘链接:
链接:https://pan.baidu.com/s/1pnA4HHJybezT-zPxCD3_Uw?pwd=scrt
提取码:scrt
上课之前,自己先准备了一点基础知识,主要是ubuntu的基本命令,更快上手,还挺有用的:
常用终端命令
ls 查看当前文件夹下的内容 -a:所有的 -l:表示长列表形式
pwd (print work directory)查看当前所在文件夹
cd (change directory) 切换文件夹
touch 如果文件不存在,新建文件
mkdir (make directory) 创建目录
rm 删除指定的文件夹
clear 清屏
终端命令格式
command [-optinons] [parameter]
command :命令名
-optinons:选项,用来对命令进行控制,可省略
parameter:传递给命令的参数
[]代表可选
查阅命令
command --help : 显示command命令的帮助信息
man command : 查阅命令手册
(command替换成具体的命令)
man 页数 函数接口
实用技巧(特别有用尤其电脑分屏的时候)
ctrl+shift+= 放大终端窗口的字体显示
ctrl+- 缩小终端窗口的字体显示
ctrl+c 退出选择,另起一行
编译
gcc编译c文件,g++编译c++文件。
当你的程序只有一个源文件时,直接就可以用gcc命令编译它。但是当你的程序包含很多个源文件时,用gcc命令逐个去编译时,你就很容易混乱而且工作量大.
所以出现了make工具!make工具可以看成是一个智能的批处理工具,它本身并没有编译和链接的功能,而是用类似于批处理的方式—通过调用makefile文件中用户指定的命令来进行编译和链接的。
makefile在一些简单的工程完全可以人工手下,但是当工程非常大的时候,手写makefile也是非常麻烦的,如果换了个平台makefile又要重新修改。
这时候就出现了Cmake这个工具,cmake就可以更加简单的生成makefile文件给上面那个make用。当然cmake还有其他功能,就是可以跨平台生成对应平台能用的makefile,你不用再自己去修改了。可是cmake根据什么生成makefile呢?它又要根据一个叫CMakeLists.txt文件(学名:组态档)去生成makefile。
一、设置环境
1、安装VMware-player-full-17.0.2-21581411
2、设置虚拟机共享文件夹
由于我们的开发是在win里面,因此我们写的代码要放在共享文件夹里面linux才可以看得到。
菜单栏选择虚拟机设置-> 选项 -> 共享文件夹 -> 总是启动 -> 添加 -> 下一步-> 浏览 -> 选择自己喜欢的文件夹(最好是不带中文以及空格的)-> 确定 -> 下一步 -> 完成 -> 确定。
打开终端(ctrl + alt + t),切换到我们的共享目录:
cd /mnt/hgfs/你的共享目录名字
二、学会操作文件
Linux -> 是世界上面运用做广的系统,它是一个开源的系统,这个系统是继承于unix。Linux中“everything is file !!!”,也就是一切皆文件。操作系统操作文件即可,因此系统的操作就离不开文件io。
正如把大象装进冰箱需要三步: 1 打开冰箱门 2 将大象装进去 3 关闭冰箱门
所以操作文件也类似上述三步: 1 打开文件 2 读/写文件 3 关闭文件
(特别重要,之后的文件操作都是基于这三步)
1、打开文件
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *pathname, int flags);//打开文件 int open(const char *pathname, int flags, mode_t mode)//打开或者创建一个文件 int creat(const char *pathname, mode_t mode);//创建一个文件
参数解释:
pathname:路径名 ,这个参数的原型是一个char *字符串
相对路径: "./1.txt"、 "../2.txt"(.是相对于当前目录;..是相当于上级目录或者
叫做父目录)
绝对路径:"/mnt/hgfs/share/1.txt"
flags: 打开文件的一些标志 用位域表示这里用宏去搞定这些功能的问题
如果有需求多个功能同时打开,那么直接用 | 按位或
下面的三个标志任选其一,这个标记是必须要给的
O_RDONLY :只读
O_WRONLY: 只写
O_RDWR: 读写
下面的标记根据自己的需求去选择
O_CREAT:创建标记:如果你给这个创建标记 第三个参数就要给了,给了这个标 记表示此文件存在即打开,不存在则创建并打开
O_NONBLOCK:非阻塞打开这个文件 ,文件打开默认是阻塞的
O_APPEND:追加标记, 打开文件光标默认在开头
O_TRUNC:截短标记,将内容清空
mode:权限 linux里面的权限分为三个部分:用户 组用户 其它用户
S_IRWXU 用户可读可写可执行
S_IRUSR 用户只读
....
S_IRWXG 组户可读可写可执行
.....
S_IRWXO 其它用户可读可写可执行
......
我们可以使用8进制去表示一个权限:常用的是:0664
返回值:
成功返回一个大于等于0的整数(实际上是 >= 3)
我们的进程在一启动的时候操作系统就会为这个程序打开三个文件
1 标准的输入 -> 0
2 标准的输出 -> 1
3 标准的出错 -> 2
返回给你的这个整数是一个数组(进程文件表项)的下标
这个整数我们有一个名词去描述 ---- 文件描述符(fd)
后续对于文件的操作都是基于这个fd的
失败返回-1,同时errno被设置,perror可以解析一个系统错误
perror:
#include <stdio.h> void perror(const char *s); s:程序员设计的一个标记,该接口调用会打印出系统的错误信息。
使用方法:
int fd = open(); if(-1 == fd)//马上进行错误判断 { perror("发生错误:"); }
2、读/写文件
2.1 读文件
#include <unistd.h> ssize_t read(int fd, void *buf, size_t count);
参数解释:
fd:文件描述符
buf:我们读到的内容你要放在一个内存才能操作,这个buf就是这块内存的首地址
c语言是没有边界检查的,因此我们要时刻的注意是否会越界的问题
程序员开辟内存一般是在栈空间或者堆空间
栈:在代码块里面开辟变量或者数组,代码块执行完毕,这块空间会被释放
堆:动态内存分配:malloc、calloc、realloc;在堆上面开辟的内存是不会主动释放的count: 你要读取多少个字节 (>= 0)
返回值:成功返回实际读到的字节数 <= count
失败返回-1,同时errno被设置
文件内容的读取都是从光标位置进行的,每读写一个字节,光标就会自动往后面偏移一个。
2.2 写文件
#include <unistd.h> ssize_t write(int fd, const void *buf, size_t count);
参数解释:
fd:文件描述符
buf:你要写什么样子的内容到我们的文件,实际上就是一个内存,里面存储我们要写入的 内容count:我们要写入多少个字节
返回值:成功返回实际写入的字节数 <= count
失败返回-1,同时errno被设置
3、关闭文件
#include <unistd.h> int close(int fd);
close - 关闭一个文件描述符
三、练习
1、打开一个文件
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main() { //打开一个文件 int fd=open("./1.txt",O_RDWR); if(-1==fd) { perror("open 1.txt error"); return -1; } printf("open 1.txt sucessful!\r\n"); printf("test"); return 0; }
2、在一个1.txt的前面4个字节放了一个千位数,以 %d的形式输出它的两倍
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main() { //1、打开一个文件 int fd=open("./1.txt",O_RDWR); int a,b,c,d,e; int A[5]; if(-1==fd) { perror("open 1.txt error"); return -1; } //2、读取文件内容 char buf[1025] = {0}; //在栈上开辟1024字节 int r = read(fd,buf,1024);//1025是为了\0,读取1.txt的内容并存放在了buf //以%d的形式输出两倍,前四个字节 if(-1 == r) { perror("read error"); return -2; } printf("%c\n",buf[0]); printf("%c\n",buf[1]); printf("%c\n",buf[2]); printf("%c\n",buf[3]); a = (buf[0]-'0')*1000; b = (buf[1]-'0')*100; c = (buf[2]-'0')*10; d = (buf[3]-'0')*1; e = a+b+c+d; printf("%d\n",e*2); //3、关闭文件 close(fd); return 0; }
3、写一个简单的学生信息录入系统:学生信息包括:姓名 学号 年龄 地址
从终端输入学生信息写入到文件里面保存,一个学生一行数据
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> //全局的学生信息文件 int fd_stu = -1; //初始化文件 这个文件是固定的 void StudentFileInit(void) { fd_stu = open("./student.txt",O_RDWR | O_CREAT,0664); if(-1 == fd_stu) { perror("open error"); exit(2); } } //将文件销毁 void DestoryStudentFile(void) { close(fd_stu); } //往一个文件里面写入一个字符串 void WriteStringToFile(int fd,const char * str) { write(fd,str,strlen(str)); } //存储学生信息 void SaveStudentMassage(void) { StudentFileInit();//将文件打开 char name[64]; int age; int id; char addr[128]; while(1)//录到sb250就结束输入 { //获取学生信息 printf("请输入学生姓名(sb250结束):"); fflush(stdout); scanf("%s",name); if(!strcmp(name,"sb250")) { break; } //printf("name = %s\n",name); printf("请输入学生学号:"); fflush(stdout); scanf("%d",&id); printf("请输入学生年龄:"); fflush(stdout); scanf("%d",&age); printf("请输入学生地址:"); fflush(stdout); scanf("%s",addr); char buf[1024]; sprintf(buf,"%d %s %d %s\n",id,name,age,addr); WriteStringToFile(fd_stu,buf); } DestoryStudentFile(); } //缓冲区的概念测试 void hehe(void) { int i; for(i = 0;i < 1024;i++) { printf("A"); } //我们也可以强制让它刷新 fflush(stdout); while(1); } //FILE * stdout = fopen int main(int argc,char * argv[]) { if(argc < 3) { printf("参数不对\n"); return -1; } printf("%s %s\n",argv[1],argv[2]); SaveStudentMassage(); return 0; }
代码解释:
1、flush(stdout):强制刷新
对于标准输出,需要输出的数据并不是直接输出到终端上,而是首先缓存到某个地方,当遇到行刷新标志或者该缓存已满的情况下,才会把缓存的数据显示到终端设备上。 ANSI C中定义换行符'n'可以认为是行刷新标志。 所以,printf函数没有带'n'是不会自动刷新输出流,直至缓存被填满。flush(stdout)的作用就是强制刷新,将缓冲区里的内容送到屏幕上。
2、int main(int argc,char * argv[])
argc是命令行总的参数个数
argv[]是argc个参数,其中第0个参数是程序的全名。argc和argv是你通过命令行窗口传给程序的。
当你需要程序带参数地启动的时候,就用int main(int argc, char *argv[])
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?