热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

20172018120155339《信息安全系统设计基础》第六周学习总结

2017-2018-120155339《信息安全系统设计基础》第六周学习总结教材学习内容总结控制转移:从ak指令到a(k1)指令的过渡。控制转移序列称为处理器的控制流

2017-2018-1 20155339 《信息安全系统设计基础》第六周学习总结

教材学习内容总结

  • 控制转移:从ak指令到a(k+1)指令的过渡。
  • 控制转移序列称为处理器的控制流。
  • 现代操作系统通过使控制流发生突变来对系统状态做出反应,这些突变称为异常控制流。
  • 异常是异常控制流的一种形式,他一部分由硬件实现,一部分由操作系统实现。
  • 异常就是控制流中的突变,用来响应处理器状态中的某些变化。
  • 当处理器检测到有事件发生时,它会通过叫做异常表的跳转表,进行一个间接过程调用(异常),到一个专门处理这类问题的操作系统子程序。
  • 系统中可能的某种类型的异常都分配了一个唯一的非负整数的异常号,异常号是异常表的索引,异常表的起始地址放在一个叫做异常表基址寄存器的特殊CPU寄存器里。
  • 异常可以分为四类:中断、陷阱、故障和终止。
  • 中断是异步发生的,是来自处理器外部的I/O设备的信号的结果。硬件中断的异常处理程序通常称为中断处理程序。
  • 陷阱是有意的异常,最重要的用途是在用户程序和内核之间提供一个向过程一样的接口,叫做系统调用。对于程序员来说系统调用和函数调用一样,实则不同。
  • 为了允许内核服务的受控访问,使用“syscall n”指令,该指令会跳转到一个异常处理程序的陷阱,这个处理程序解析参数,并调用适当的内核程序。
  • 故障由错误引起,它可能能够被故障处理程序修正。一个经典的故障实例是缺页异常。
  • 终止是一个致命的不可控的错误。
  • Linux/x86-64故障和终止
    1.除法错误(异常0):产生原因:应用试图除零,或者当一个除法指令的操作数对于目标操作数来说太大了的时候。
    2.一般故障保护(异常13):通常是因为一个程序引用一个未定义的虚拟存储区域,或者程序试图写一个只读文本段。
    3.缺页(异常14):重新执行产生故障的一个异常示例。处理程序将磁盘上虚拟存储器相应页面映射到物理存储器的一个页面,然后重新开始执行这条指令。
    4.机器检查(异常18):在导致故障的指令执行中检测到致命的硬件错误时发生。
  • Linux/x86-64系统调用:每个系统调用都有一个唯一的整数号,对应于一个到内核中跳转表的偏移量(注意与异常表不同)。
  • 所以Linux系统调用的参数都是通过通用寄存器而不是栈传递的。
  • read函数和write函数:
    1.read:ssize_t read(int fd, void *buf, size_t count);返回:若成功则为读的字节数,若EOF则为0,若出错为-1。
    2.write:ssize_t write(int fd, const void *buf, size_t count);返回:若成功则为写入的字节数,若出错则为-1。实例练习运行结果如下:
    1071519-20171029113902226-523918566.png

  • 一个执行中的程序的实例就是进程,系统中的每个程序都是定义在运行在某个进程的上下文中的。上下文是由程序正确运行所需的状态组成的。状态包括存放在存储器中的程序代码和数据,它的栈、通用目的寄存器内容、程序计数器、环境变量以及打开文件描述符的集合。
  • 一个独立的逻辑控制流,提供一个假象,某个程序独占地使用处理器。
  • 一个私有的地址空间,提供一个假象,某个程序独占地使用存储器系统。
  • PC的值唯一地对应于包含在程序可执行目标文件中的指令,或者是包含在运行时动态链接到程序的共享对象中的指令。这个PC值的序列叫做逻辑控制流,简称逻辑流。
  • 一个逻辑流的执行在时间上与另一个流重叠,称为并发流。
  • 1.并发:多个流并发的执行。
    2.多任务(时间分片):一个进程和其他进程轮流运行。
    3.时间片:一个进程执行它的控制流的一部分的每一时间段。
    4.并行:两个流并发的运行在不同的处理机核或者计算机上。
  • 进程为每个程序提供他自己的私有地址空间,一般而言,和这个空间中某个地址相关联的存储器字节不能被其他程序读或者写。从这个意义上讲,这个地址是私有的。
  • 地址空间底部是保留给用户程序的,代码段总是从地址0x400000开始的,顶部保留给保留给内核。
  • 设置模式位,进程运行在内核模式(也叫超级用户模式),没有设置模式位就运行在用户模式。
  • linux提供了/proc文件系统,它允许用户模式进程访问内核数据结构的内容。
  • 操作系统内核使用叫上下文切换的异常控制流来实现多任务。
  • 在进程执行的某些时刻,内核可以决定抢占当前进程,并重新开始一个先前被抢占了的进程,这叫做调度。
  • 调度由内核中的调度器处的代码实现。
  • Unix系统级函数遇到错误时,它们通常会返回-1,并设置全局变量errno来表示哪里出错了。

fork等函数的使用

fork函数

  • 首先查看fork函数的帮助文档,如下图,可知该函数为系统调用函数,该函数的头文件为#include 用法:pid_t fork(void);,从帮助文档可以知道,该函数创建了一个子程序。
    1071519-20171029113034680-234849648.png

  • 由于不怎么看得懂这些英文,之后的学习是在网上搜索学习的,fork创建的虽然是叫子程序,但是两者是同时进行的,如果fork成功,父进程中fork的返回值是子进程的进程号,子进程中fork的返回值是0,由于子进程的进程号都是大于0的,所以可以用来区分父进程以及子进程,如果fork不成功,父进程会返回错误。
  • 需要注意的是:子进程的pid是0,子进程的getpid()是它自己的进程号;父进程中的pid值为子进程进程号,只有父进程执行的getpid()才是他自己的进程号。
  • 以下运行结果展现了fork的以上特性
    1071519-20171029113930586-2067298168.png

  • 因此当留在父进程或者进入子进程之后,还有别的工作时,该进程依旧会执行完这些命令,如下面这个示例的结果
    1071519-20171029113942492-1824407867.png

wait函数

  • 通过帮助文档,可以知道其头文件为:

#include
#include

用法:pid_t wait (int *status)
wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数status 返回,而子进程的进程识别码也会一起返回。如果不在意结束状态值,则status可以设成NULL,status 是一个整型指针,是该子进程退出时的状态:status 若为空,则代表不记录子进程结束状态,status 若不为空,则由status记录子进程的结束状态值,当成功的时候,返回子进程识别码(PID),出错的时候返回-1,失败原因存于errno中。
1071519-20171029114045398-383993083.png

  • 一个练习,父进程wait子进程结束的练习,结果如下图
    1071519-20171029114057039-1338224457.png

waitpid函数

  • 头文件与wait函数头文件相同,waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用waitpid()子进程已经结束,则waitpid()会立即返回子进程结束状态值。子进程的结束状态值会由参数status返回,而子进程的进程识别码也会一起返回。如果不在意结束状态值,则参数status可以设成NULL。参数pid为欲等待的子进程识别码。
  • 用法:pid_t waitpid(pid_t pid,int * status,int options)
  • 传入的pid:
    1.pid
    <-1&#xff1a;等待进程组识别码为pid绝对值的任何子进程
    2.pid&#61;-1: 等待任何子进程&#xff0c;相当于wait()
    3.pid&#61;0&#xff1a;等待进程组识别码与目前进程相同的任何子进程
    4.pid>0&#xff1a;等待任何子进程识别码为pid的子进程&#xff0c;直到出现进程ID等于pid的进程。
  • 成功&#xff1a;1.返回子进程识别码(PID)
    2.使用选项WNOHANG且没有子进程退出返回0
    练习了书上的代码&#xff0c;比较了有无waitpid的情况&#xff0c;得到以下截图
    1071519-20171029114112367-907142247.png

exec函数

  • 其实说exec函数在严格意义上来讲是不对的&#xff0c;因为Linux中没有exec函数&#xff0c;而是有6个以exec开头的函数族&#xff0c;exec函数族提供了一个在进程中启动另一个程序执行的方法。
  • 头文件#include &#xff0c;一共有六个函数族&#xff0c;其中只有execve为系统调用&#xff0c;运行另一个程序&#xff0c;用法为

int execve(const char *filename, char *const argv[],char *const envp[]);

同时保留原程序运行的方法是&#xff1a;fork&#43;exec。
通过execve运行ls命令&#xff0c;结果如下&#xff1a;
1071519-20171029114125211-2072639894.png

getenv函数、setenv函数、unsetven函数

  • getenv函数&#xff1a;获得环境变量值的函数&#xff0c;参数是环境变量名name&#xff08;如”HOME”、”PATH”&#xff09;。如果环境变量存在&#xff0c;函数会返回环境变量值&#xff0c;即value的首地址&#xff1b;如果环境变量不存在&#xff0c;函数返回NULL&#xff0c;练习得到如下运行结果
    1071519-20171029114141383-978305742.png

  • setenv()用来改变或增加环境变量的内容。用法&#xff1a;int setenv(const char *name,const char * value,int overwrite);参数name为环境变量名称字符串&#xff08;如”HOME”、”PATH”&#xff09;。
      参数 value则为变量内容&#xff0c;参数overwrite用来决定是否要改变已存在的环境变量。如果overwrite不为0&#xff0c;而该环境变量原已有内容&#xff0c;则原内容会被改为参数value所指的变量内容。如果overwrite为0&#xff0c;且该环境变量已有内容&#xff0c;则参数value会被忽略。
  • unsetven()删除环境变量&#xff0c;删除成功返回0。
    一个综合的练习运行结果
    1071519-20171029114153742-1145608141.png

kill函数

  • kill()可以用来发送信号给其他进程&#xff08;包括他们自己&#xff09;。如果pid大于0&#xff0c;那么kill函数发送信号号码sig给进程pid。如果pid等于零&#xff0c;那么kill发送信号sig给调用进程所在进程组中的每个进程&#xff0c;包括调用自己的进程。如果小于零&#xff0c;kill发送信号sig给进程组|pid|中的每个进程。

getpid、getppid、sleep、pause、exit

  • 头文件&#xff1a;#include
  • getpid&#xff08;&#xff09;用来取得目前进程的进程识别码&#xff0c;许多程序利用取到的此值来建立临时文件&#xff0c;以避免临时文件相同带来的问题。返回值&#xff1a; 目前进程的进程识别码&#xff0c;在之前的fork中已经使用过了。
  • getppid&#xff08;&#xff09;用来取得目前进程的 父进程识别码。
  • sleep&#xff08;&#xff09;&#xff0c;对于这个函数我的理解是&#xff0c;睡眠多久再执行&#xff0c;在Linux中sleep中的单位是秒&#xff0c;对上面的wait代码进行了改进来对sleep的功能以及wait的功能做一个更深层次的剖析&#xff0c;得到以下结果&#xff1a;
  • 增加sleep前的截图&#xff1a;
    1071519-20171029114209570-1710004008.png

  • 增加sleep后的截图
    1071519-20171029114237976-1720583500.png

增加了sleep之后&#xff0c;由于睡眠了1秒钟&#xff0c;所以先输出This is the child process pid &#61;4761。

  • pause()会令目前的进程暂停(进入睡眠状态), 直到被信号(signal)所中断。
  • exit关闭所有文件&#xff0c;终止正在执行的进程&#xff0c;头文件&#xff1a;stdlib.h&#xff0c;关于参数&#xff1a;exit(1)表示异常退出.这个1是返回给操作系统的。exit(x)&#xff08;x不为0&#xff09;都表示异常退出。exit(0)表示正常退出。

signal函数

  • 头文件#include 用法&#xff1a;sighandler_t signal(int signum, sighandler_t handler);
  • signal信号函数&#xff0c;第一个参数表示需要处理的信号值&#xff08;SIGHUP&#xff09;&#xff0c;第二个参数为处理函数或者是一个表示。
  • 其中信号值有以下这些&#xff1a;
    1071519-20171029114251336-230627248.png

pipe函数

  • 管道是一种把两个进程之间的标准输入和标准输出连接起来的机制&#xff0c;从而提供一种让多个进程间通信的方法&#xff0c;当进程创建管道时&#xff0c;每次都需要提供两个文件描述符来操作管道。其中一个对管道进行写操作&#xff0c;另一个对管道进行读操作。对管道的读写与一般的IO系统函数一

致&#xff0c;使用write()函数写入数据&#xff0c;使用read()读出数据。

  • 头文件&#xff1a;#include 用法&#xff1a;int pipe(int filedes[2]);返回值&#xff1a;成功&#xff0c;返回0&#xff0c;否则返回-1。参数数组包含pipe使用的两个文件的描述符。fd[0]:读管道&#xff0c;fd[1]:写管道。
  • 必须在fork()中调用pipe()&#xff0c;否则子进程不会继承文件描述符。两个进程不共享祖先进程&#xff0c;就不能使用pipe。但是可以使用命名管道。

dup函数

  • dup函数包括dup、dup2、dup3&#xff0c;用于复制文件描述符。
  • #include

int dup(int oldfd);
int dup2(int oldfd, int newfd);

dup 和dup2都是返回新的描述符。或者返回-1并设置 errno变量。

教材学习中的问题和解决过程

&#xff08;一个模板&#xff1a;我看了教材p512的这一段文字&#xff1a; Unix系统级函数遇到错误时&#xff0c;它们通常会返回-1&#xff0c;并设置全局变量errno来表示哪里出错了&#xff0c;有这个问题&#xff1a; 通常返回-1&#xff0c;那哪些情况返回值不是-1呢。 我查了资料&#xff0c;资料中只有提到返回-1的情况&#xff0c;根据我的实践&#xff0c;我得到的也都是-1。 但是我还是不太懂&#xff0c;我的困惑是有哪些不是-1呢&#xff0c;或者这个我们是不是不需要掌握呢。

  • 问题1&#xff1a;wait和waitpid两函数的说明
  • 问题1解决方案&#xff1a;上网搜索之后得到&#xff0c;如果父进程的所有子进程都还在运行&#xff0c;调用wait将使父进程阻塞&#xff0c;而调用waitpid时&#xff0c;如果在options参数中指定WNOHANG可以使父进程不阻塞而立即返回0。waitpid提供了一个 wait的非阻塞版本&#xff0c;有时希望取得一个子进程的状态&#xff0c; 但不想进程阻塞。

代码调试中的问题和解决过程

  • 问题1&#xff1a;在练习教材上p518的代码时不知道fflush是什么
  • 问题1解决方案&#xff1a;查找帮助文档&#xff0c;其头文件#include 用法int fflush(FILE *stream);功 能: 清除文件缓冲区&#xff0c;文件以写方式打开时将缓冲区内容写入文件。如果成功刷新,fflush返回0。指定的流没有缓冲区或者只读打开时也返回0值。返回EOF指出一个错误。
    1071519-20171029114313961-1212385817.png

  • 问题2&#xff1a;在进行课上的代码的调试时&#xff0c;编译出现了的错误
  • 问题2解决方案&#xff1a;通过上网知道通过od查看问题出在哪里&#xff0c;进行修改
    1071519-20171029114327633-941760480.png

代码托管

1071519-20171029114342211-1005475667.png

上周考试错题总结

  • 6.多选&#xff1a;我们用一个十六进制的数表示长度w&#61;4的位模式&#xff0c;把数字解释为补码&#xff0c;关于其加法逆元的论述正确的是&#xff08;&#xff09;
    • A .0x8的加法逆元是-8
    • B .0x8的加法逆元是0x8
    • C .0x8的加法逆元是8
    • D .0xD的加法逆元是3
    • E .0xD的加法逆元是0x3
  • 7.大多数计算机使用同样的机器指令来执行无符号和有符号加法。
    • A .正确
    • B .错误
    • C .不确定。
  • 8.多选&#xff1a;我们用一个十六进制的数表示长度w&#61;4的位模式&#xff0c;对于数字的无符号加法逆元的位的表示正确的是&#xff08;&#xff09;
    • A .0x8的无符号加法逆元是0x8
    • B .0xD的无符号加法逆元是0xD
    • C .0xF的无符号加法逆元是0x1
    • D .0xF的无符号加法逆元是1
  • 14.多选&#xff1a;

short int v&#61;-12345;
unsigned short uv&#61;(unsigned short) v;

那么

  • A .v&#61;-12345, uv&#61;53191
  • B .v&#61;uv&#61;0xcfc7
  • C .v,uv的底层的位模式不一样
  • D .v,uv的值在内存中是不一样的
  • 解析&#xff1a;有符号数和无符号数的转换&#xff0c;值不同&#xff0c;位模式不变

  • 22.C语言中&#xff0c;字符串被编码为一个以0结尾的字符数组。
    • A .正确
    • B .错误
    • 解析&#xff1a;null的值是0
  • 23.下面和代码可移植性相关的C语言属性有&#xff08;&#xff09;
    • A .#define
    • B .typedef
    • C .sizeof()
    • D .union
    • 解析&#xff1a;#define可以定义宏使得变量可移植&#xff0c;typedef可以使得类型可移植&#xff0c;sizeof()使得不同类型长度可移植。

结对及互评

本周结对学习情况

- [结对同学学号20155306](https://home.cnblogs.com/u/0831j/)
- 结对照片
- 结对学习内容第六章学习任务

其他&#xff08;感悟、思考等&#xff0c;可选&#xff09;

这周的学习任务比较大&#xff0c;在连续几天的努力下终于完成了&#xff0c;只是还需要消化一下。
由于这周进行了缓冲区溢出攻击实验&#xff0c;虚拟机崩了&#xff0c;无法回到图形化界面&#xff0c;也无法git&#xff0c;所以现在的statistics只有本周的代码&#xff0c;并且之前的只有commit&#xff0c;没有push&#xff0c;在虚拟机崩了之后挣扎了很久&#xff0c;依旧没有办法&#xff0c;网上说只能重装&#xff0c;所以重装虚拟机后代码都是同一时间push的&#xff0c;但并非抄袭。!

学习进度条

代码行数&#xff08;新增/累积&#xff09;博客量&#xff08;新增/累积&#xff09;学习时间&#xff08;新增/累积&#xff09;重要成长
目标5000行30篇400小时
第一周200/2002/220/20
第二周300/5002/418/38
第三周500/10003/722/60
第四周300/13002/930/90
第五周300/13002/930/90
第六周706/20061/1050&#43;/140&#43;

尝试一下记录「计划学习时间」和「实际学习时间」&#xff0c;到期末看看能不能改进自己的计划能力。这个工作学习中很重要&#xff0c;也很有用。
耗时估计的公式
&#xff1a;Y&#61;X&#43;X/N &#xff0c;Y&#61;X-X/N&#xff0c;训练次数多了&#xff0c;X、Y就接近了。

参考&#xff1a;软件工程软件的估计为什么这么难&#xff0c;软件工程 估计方法

  • 计划学习时间:20小时

  • 实际学习时间:50&#43;小时

  • 改进情况&#xff1a;

(有空多看看现代软件工程 课件
软件工程师能力自我评价表)

参考资料

  • 《深入理解计算机系统V3》学习指导
  • wait函数

转:https://www.cnblogs.com/pingcpingcuo/p/7749772.html



推荐阅读
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • OO第一单元自白:简单多项式导函数的设计与bug分析
    本文介绍了作者在学习OO的第一次作业中所遇到的问题及其解决方案。作者通过建立Multinomial和Monomial两个类来实现多项式和单项式,并通过append方法将单项式组合为多项式,并在此过程中合并同类项。作者还介绍了单项式和多项式的求导方法,并解释了如何利用正则表达式提取各个单项式并进行求导。同时,作者还对自己在输入合法性判断上的不足进行了bug分析,指出了自己在处理指数情况时出现的问题,并总结了被hack的原因。 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • 本文介绍了Android中的assets目录和raw目录的共同点和区别,包括获取资源的方法、目录结构的限制以及列出资源的能力。同时,还解释了raw目录中资源文件生成的ID,并说明了这些目录的使用方法。 ... [详细]
  • 统一知识图谱学习和建议:更好地理解用户偏好
    本文介绍了一种将知识图谱纳入推荐系统的方法,以提高推荐的准确性和可解释性。与现有方法不同的是,本方法考虑了知识图谱的不完整性,并在知识图谱中传输关系信息,以更好地理解用户的偏好。通过大量实验,验证了本方法在推荐任务和知识图谱完成任务上的优势。 ... [详细]
  • EPICS Archiver Appliance存储waveform记录的尝试及资源需求分析
    本文介绍了EPICS Archiver Appliance存储waveform记录的尝试过程,并分析了其所需的资源容量。通过解决错误提示和调整内存大小,成功存储了波形数据。然后,讨论了储存环逐束团信号的意义,以及通过记录多圈的束团信号进行参数分析的可能性。波形数据的存储需求巨大,每天需要近250G,一年需要90T。然而,储存环逐束团信号具有重要意义,可以揭示出每个束团的纵向振荡频率和模式。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 本文总结了淘淘商城项目的功能和架构,并介绍了传统架构中遇到的session共享问题及解决方法。淘淘商城是一个综合性的B2C平台,类似京东商城、天猫商城,会员可以在商城浏览商品、下订单,管理员、运营可以在平台后台管理系统中管理商品、订单、会员等。商城的架构包括后台管理系统、前台系统、会员系统、订单系统、搜索系统和单点登录系统。在传统架构中,可以采用tomcat集群解决并发量高的问题,但由于session共享的限制,集群数量有限。本文探讨了如何解决session共享的问题。 ... [详细]
  • 本文介绍了在Cpp中将字符串形式的数值转换为int或float等数值类型的方法,主要使用了strtol、strtod和strtoul函数。这些函数可以将以null结尾的字符串转换为long int、double或unsigned long类型的数值,且支持任意进制的字符串转换。相比之下,atoi函数只能转换十进制数值且没有错误返回。 ... [详细]
  • 本文讲述了作者从最初对软件工程的选择迷茫到逐渐喜欢并坚持学习的经历。作者在大学期间通过学习专业课和参与项目开发,不断挑战自己并取得成就感。虽然曾考虑过转专业和复读,但最终决定坚持学习软件工程,并为自己的未来努力奋斗。作者还提到了大学生活与自己最初的预期不同,但对此并没有太多抱怨。 ... [详细]
author-avatar
惠萍孝正慧云
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有