GithubHelp home page GithubHelp logo

hylerrix / university Goto Github PK

View Code? Open in Web Editor NEW
45.0 45.0 10.0 191 KB

:mortar_board: my university code & article collection: create & share, thought & works

License: Creative Commons Attribution Share Alike 4.0 International

blog hylerrix

university's Introduction

🧜‍♂️ Hi!

ChatGPT React Next TypeScript Node Rust TailwindCSS Deno

🧜‍♂️ About Me Profile Hits

你好,我是凝尘 (Hylerrix)

In Open Source community, 2024, I'm mainly focusing on building the next generation all-in-one database sharing community Lifetable.ai now (See above line for more in Chinese introduce), proudly using React v18, Next.js v14 and more.

Thanks for clicking 'Follow' to knowing the next step!

🌅 Let's build Lifetable.ai for 2024!

欢迎来到 Lifetable.ai 凝搭社区!

❤️ Statistics for my Open-Source-Love

 

More About Me in Charts



university's People

Contributors

hylerrix avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

university's Issues

[A05]C 语言数据类型及混合运算与类型转换

深入学习 C 语言时,有必要先了解一下数据类型的概念,以及它们之间的混合运算与类型转换。本篇文章便是根据《C语言程序设计教程》和在线翻阅资料后整理而出。(练习题将逐步更新)

一、概述

程序所能处理的基本数据对象被划分成一些组或一些集合。它们都采用同样的编码方式,对它们能做同样的操作。把程序中具有这样性质的集合,成为数据类型。CPU 对不同的数据类型提供了不同的操作指令。

C 语言中的类型按其组成可以分为简单类型和构造类型,按是否预定义了类型名字和值集可以分为基本类型和非基本类型,按是否加了类型限定符可以分为限定类型和非限定类型。

用 ProcessOn 作图,C 语言数据类型如下:

二、类型修饰符

除 void 类型外,基本数据类型之前都可以加各种类型修饰符,类型修饰符有如下四种:

  1. signed----有符号,可修饰 char、int。int 是默认有符号的
  2. unsigned-----无符号,修饰 int 、char
  3. long------长型,修饰 int 、double
  4. short------短型,修饰 int

三、各种数据类型介绍

1. 基本数据类型

以下各数据类型字长均指32位操作系统下,可用printf("%d",sizeof(数据类型名));进行测试。具体字长由具体编译器决定,但确定的关系是:sizeof(short)≤sizeof(int)≤sizeof(long)

整型:整形包括短整型、整形和长整形

  • 短整型:
    • 有符号短整型:short [int] 2byte -32768~32767
    • 无符号短整型:unsigned short [int] 2 byte 0~65535
  • 整型:
    • 有符号整型:int /signed [int] 4 byte -2147483648~2147483647
    • 无符号整型:unsigned [int] 4 byte 0~4294967295
  • 长整形:
    • 有符号长整型:long [int]/signed long [int] 4 byte -2147483648~2147483647
    • 无符号长整型:unsigned long [int] 4 byte 0~4294967295
  • 超长整型(C99 标准添加的类型):long long [int] 8 byte 0~18446744073709552000

P.S(C 语言中整型和长整形都占 4 字节的原因):
早期的 C 编译平台下整形和长整型分别是 2 和 4 字节。随着编译平台版本的升级,现在二者都是 4 字节,short 是 2 字节。另外整型数的字长与 CPU 的字长没有密切关系:早期的 int 是 2 字节,但那时的 CPU 也已经是 32 位的了;再者你把现在4字节 int 编译平台安装在 64 位 CPU 机上去,同样只能编译 4 字节 int 的代码,并不因为 CPU 成 8 字节了,你代码中的 int 也成 8 字节了。(摘自百度知道)
long 从字面上看,应该是 64 位才更合理,把 long 当成 32 位实在是一个历史的包袱。像 C# 那样新起炉灶的程序语言,由于没有需要支持老代码的问题,就把 long 当作 64 位来处理了。
在 32 位平台下,long 是相对 short 而言,long(short) 类型是long(short) int类型的简称,sizeof(long) = sizeof(int) = 4。int和long的范围虽然一样,但输入输出格式不同,printf int 的格式为%d,而 printf long 的格式为 %ld。
考虑到程序的可移植性,还是要将他们区分开来。但当要求的数值范围为 4 byte 时,建议使用int类型,因为第一版的 C 语言只有一种类型,那就是 int。(摘自百度文库)

浮点型

  • 单精度浮点型:float 4 byte -3.4E38~3.4E38
  • 双精度浮点型:double 8 byte 1.7E308~1.7E308 long double 8 byte

字符型

  • 有符号字符型:char/signed char 1 byte -128~127
  • 无符号字符型:unsigned char 1 byte 0~255
  • 宽字符型:wchar_t (unsigned short) 2 byte 0~65535

P.S:字符型赋值时可以是char c='a';也可以用字符对应的ASCII码赋值:char c=97;

2. 指针类型:

有关指针的数据类型

int i——定义整形变量i
int *p——p为指向整型变量的指针变量
int a[n]——定义整型数组a,它有n个元素
int *p[n]——定义指针数组p,它由n个指向整型数据的指针元素组成
int (*p)[n]——p为指向含n个元素的一维数组的指针变量
int f()——— f为返回整数型函数值的元素
int *p()——- p为返回一个指针,该指针指向整型数据 或 整形数组
int (*p)() —–p为指向函数的指针,该函数返回一个整数值
int **p——p是一个指针变量,它指向一个指向整数型数据的指针变量

延伸可参考:基于指针的数据类型与指针运算小结

3. 构造类型:struct

C 语言构造类型分为:数组类型,结构类型和共用体类型

  • 数组类型:是由相同基本类型若干个元素组织在一起数据,它们有先后顺序,也可以按这个顺序对这些元素访问。如 int a[10],共有 10 个元素,第个元素的类型都相同,都为整型。这 10 个元素,按顺序分别是 a[0]、a[1]、a[2]、a[3]、a[4]、a[5]、a[6]、a[7]、a[8]、a[9]。
  • 结构体类型:在 C 语言中,结构体(struct) 指的是一种数据结构,是 C 语言中聚合数据类型(aggregate data type)的一类。结构体可以被声明为变量、指针或数组等,用以实现较复杂的数据结构。结构体同时也是一些元素的集合,这些元素称为结构体的成员(member),且这些成员可以为不同的类型,成员一般用名字访问。在C语言中,定义一个结构的一般形式为:
struct 结构名
{
    //成员表列
};

延伸可参考:C语言结构体(struct)常见使用方法

  • 共用体类型:union

几个不同的变量共同占用一段内存的结构,在C语言中,被称作“共用体”类型结构,简称共用体。注:在某些书籍中可能称之为“联合体”,但是“共用体”更能反映该类型在内存的特点。在C语言中,定义一个共用体结构的一般形式为:

union 共用体名
{
    成员表列
}变量表列;

4. 空类型:void

常用在程序编写中对定义函数的参数类型、返回值、函数中指针类型进行声明。具体参考 void 百科

四、不同类型数据间的混合运算与类型转换

1.自动类型转换

在C语言中,自动类型转换遵循以下规则:

  • 若参与运算量的类型不同,则先转换成同一类型,然后进行运算
  • 转换按数据长度增加的方向进行,以保证精度不降低。如int型和long型运算时,先把int量转成long型后再进行运算
    • 若两种类型的字节数不同,转换成字节数高的类型
    • 若两种类型的字节数相同,且一种有符号,一种无符号,则转换成无符号类型
  • 所有的浮点运算都是以双精度进行的,即使仅含float单精度量运算的表达式,也要先转换成double型,再作运算
  • char型和short型参与运算时,必须先转换成int型
  • 在赋值运算中,赋值号两边量的数据类型不同时,赋值号右边量的类型将转换为左边量的类型。如果右边量的数据类型长度左边长时,将丢失一部分数据,这样会降低精度,丢失的部分按四舍五入向前舍入

2. 强制类型转换

强制类型转换一般格式如下:(类型名)(表达式)。这种强制类型转换操作并不改变操作数本身。

参考链接

[B0D]Github + Hexo 免费搭建静态博客站点#01

临夜写稿,将一直规划很久迟迟没有动笔的这一系列落实,也为今日清晨就要举办的前端社区活动做干货分享准备。我的这个学习模型,每当有一个技术主题出现,常常伴随着以下几个

  • 线上社区宣传主题
  • 博客写作
  • 加班加点的制作相关 ppt
  • 微信订阅号的文章推送配合并群发宣传

每一次的技术分享都走遍了所有流程,回首看来,着实挺累,但也还算值得。

这一系列便来讲讲 Github Pages+ Hexo 搭建专属静态博客站点。

我的博客模板

1 博客与静态博客?

正如我之前的这篇文章 《如何写一篇优质的博客》 画图所示,网络博客在短短的几十年间得到了巨大的普及,传递着每一个故事。博客有一个最忠实的群体,那就是发明他们的人:程序员,或者叫做极客、黑客和软件工程师更能生动的形容他们对新技术的激情。

写博客的好处是我们用博客表达自己、升华自己。在我们学会写博客的同时还能提升我们的演讲、辩论能力。写博客的前期准备便需要我们能够对自己、对博客主题进行明确的定位以及对博客叙述的把控,达到最好的效果。

Weblog = Web + Log;

那静态博客是什么?通俗来讲,静态博客站点便是没有数据库没有后台交互的纯前台博客站点,哪怕是评论系统也是由第三方提供数据支持。静态博客站点常常作为 HTML 页面出现,可用博客制作器制作,Hexo 便是其中之一。相比有数据库有后台交互的动态博客站点来说,静态博客站点有如下好处:

  • 省钱。静态网站占用的系统资源少。如果挂到github pages上,只要注册一个域名就可以了。
  • 速度快。不经过php解析器,不用数据库,速度自然比动态网站快
  • 安全。由于静态网站的简洁,免疫很多web攻击方式。
  • 服务器端配置简单。只需要一个web server(apache、nginx)。
  • 非常容易维护。

Git、Github 和 Github Pages?

Git 是一个版本控制系统,可以用来随着时间变化跟踪一个项目中文件的改变。Git 代表性的功能就是记录文件有什么改变、谁做出的改、改变者对这次改变做出了怎样的阐述和说明等。Git 主要被各类软件开发项目所使用。

如下图所示,每一个文件代表着一次“保存”,没有了 Git,你就不能随意退回到曾经的某次修改之中。

有了 Git,改变将是多方向的,每一次修改都会得到保存,每一个保存都可以引发新的时间线,版本回退、分支管理、协作开发等功能都有了发展条件。

--everything-is-local

在基于 Git 的众多管理系统中, Github 是最突出的一个。Github 上有成千上万激动人心的卓越项目,我们可以轻松的下载项目源代码或
克隆这个项目到自己的仓库并进行自己的开发。目前最火的开源项目便是 freeCodeCamp,一个 JS 全栈在线学习平台。

Github Pages 是面向用户、组织和项目开放的公共静态页面搭建托管服 务,站点可以被免费托管在 Github 上,你可以选择使用 Github Pages 默 认提供的域名 github.io 或者自定义域名来发布站点。Github Pages 支持自动利用第三方静态站点生成工具生成站点,也同样支持纯 HTML 文档,将你的静态站点托管在 Github Pages 上是一个不错的选择。

Hexo?

有很多静态站点的主题可供我们选择,根据这些主题所用的开发语言可以分为如下几类,可见我这里选择 Hexo 的原因在于 Hexo 基于 Node.js ,与我的前端技术栈相匹配且有一定的用户量,主题仓库里会得到很多及时的更新。

  • Ruby:Jekyll,Octopress、Middleman
  • Node.js:Hexo、Metalsmith、Wintersmith
  • GO:Hugo
  • Python:Pelican

开始实战

搭建 Node.js 开发环境

官网下载:https://nodejs.org/zh-cn/

Node.js®是一个基于Chrome V8 引擎的 JavaScript 运行环境。 Node.js 使用高效、轻量级的事件驱动、非阻塞 I/O 模型。Node.js 之生态系统是目前最大的开源包管理系统。Hexo 博客制作器需要 node 和 npm 的环境。

安装 Git 客户端

官网下载:https://git-scm.com/

一般来说,Linux 和 MaxOS 都会默认集成 Git 的功能,进行版本控制。而在 Windows 下,常常需要下载 Git 客户端 -- Git Bash 来进行命令行操作。

安装过程中一路默认即可。

解决 git bash 中 node、npm 命令不存在的问题

安装完 Node.js 和 Git,发现在 Git Bash 中输入 node -vnpm -v 提示命令不存在的报错信息,是我们在 Windows 下没有链接环境变量的缘故。打开环境变量的设置,在 PATH 变量后加入 Node 安装的目录即可。

安装初始化 Hexo

现在有了 Node 的 js 环境和 Git Bash 提供的命令行环境,开始着手安装 Hexo。

npm install -g hexo

以上命令会用 npm 的 node 包管理器将 hexo 安装到本地,-g 参数表明安装目录为本地的全局 npm 包中,而不是某个项目的 npm 包中。这时我们就可以使用 hexo 命令了。

新建一个文件夹,并在这个文件夹中初始化 Hexo 站点。

mkdir test
cd test
hexo init

初始化过程较为缓慢,hexo 将会把核心站点仓库从远程服务器拉到本地,并默认配置好 landscape 主题,这个主题可以根据自己的爱好来去官网主题仓库挑选。hexo init 命令会在当前文件夹下生成如下目录:

.
├── .deploy #需要部署的文件
├── node_modules #Hexo插件
├── public #生成的静态网页文件
├── scaffolds #模板
├── source #博客正文和其他源文件,404、favicon、CNAME 都应该放在这里
| ├── _drafts #草稿
| └── _posts #文章
├── themes #主题
├── _config.yml #全局配置文件
└── package.json

有了 Hexo 的本地博客站点,在可以进行快速的博客发布前,我们还得配置当前目录下的 _config.yml 文件,具体配置及简介如下。

# Hexo Configuration
## Docs: https://hexo.io/docs/configuration.html
## Source: https://github.com/hexojs/hexo/

# Site # 站点信息
title: 韩亦乐の博客集 # 标题
subtitle: 做最好的自己,影响该影响的人 # 副标题
description: 韩亦乐の博客集 # 站点描述,给搜索引擎看的
author: 韩亦乐 # 作者
email: [email protected] # 电子邮箱
language: zh-cn # 语言
timezone:

# URL # 链接格式
## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
url: http://icorvoh.github.io/Blog # 网址
root: /Blog/ # 根目录
permalink: :year/:month/:day/:title/ # 文章的链接格式
permalink_defaults:

# Directory # 目录
source_dir: source # 源文件目录
public_dir: public # 生成的网页文件目录
tag_dir: tags # 标签目录
archive_dir: archives # 存档目录
category_dir: categories # 分类目录
code_dir: downloads/code
i18n_dir: :lang
skip_render:

# Writing
new_post_name: :title.md # 新文章标题
default_layout: post # 默认的模板,包括 post、page、photo、draft
titlecase: false # 标题转换成大写
external_link: false # 在新选项卡中打开连接
filename_case: 0
render_drafts: false
post_asset_folder: false
relative_link: false
future: true
highlight: # 语法高亮
  enable: true # 是否启用
  line_number: true # 显示行号
  auto_detect: false
  tab_replace:

# Category & Tag # 分类和标签
default_category: uncategorized # 默认分类
category_map:
tag_map:

# Archives
# 2: 开启分页
# 1: 禁用分页
# 0: 全部禁用
archive: 2
category: 2
tag: 2

# Server # 本地服务器
# port: 4000 # 端口号
# server_ip: localhost # IP 地址
# logger: false
# logger_format: dev

# Date / Time format # 日期时间格式
## Hexo uses Moment.js to parse and display date
## You can customize the date format as defined in
## http://momentjs.com/docs/#/displaying/format/
date_format: YYYY-MM-DD
time_format: HH:mm:ss

# Pagination # 分页
## Set per_page to 0 to disable pagination
per_page: 10 # 每页文章数,设置成 0 禁用分页
pagination_dir: page

# Extensions
## Plugins: https://hexo.io/plugins/
## Themes: https://hexo.io/themes/
theme: freemind.386 # 主题
plugins: # 插件,例如生成 RSS 和站点地图的
- hexo-generator-feed
- hexo-generator-sitemap

# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
  type: git
  repo: [email protected]:icorvoh/Blog.git
  branch: gh-pages

配置好

hexo n == hexo new
hexo g == hexo generate
hexo s == hexo server
hexo d == hexo deploy
hexo init Blog
cd Blog
npm install hexo-server --save
npm install hexo-deployer-git --save
git clone [email protected]:blackshow/hexo-theme-freemind.386.git themes/freemind.386
rm -rf themes/landscape
vim _config.yml

选择 Hexo 主题

Hexo 拓展

  • 插件之向百度主动提交链接
  • Hexo 第三方评论系统

Hexo插件之百度主动提交链接

[A01] 一个校园互联网实验室的纳新试题(我的服务端开发笔试题)

实验室一面结束,服务端面试总体结果还可以,但根据笔试题答案,面试官学长指出了其中的一些问题。

服务端开发笔试题问与答

1. 简述 const 与 define 的区别。

在PHP中定义常量时,const 与 define 的区别:用 const 使得代码简单易读,const 本身就是一个语言结构,而 define 是一个函数。另外 const 在编译时要比 define 快得多。在PHP 5.3.0 以后,可以使用 const
关键字在类定义的外部定义常量,先前版本 const 关键字只能在类(class)中使用。一个常量一旦被定义,就不能再改变或者取消定义。

  • const用于类成员变量的定义,一经定义便不可修改。define不可用不类成员变量的定义,可用于全局常量。
  • const不能在条件语句中定义常量。如:
if (...) {
    const FOOT = ‘BALL’; //无效定义
}
if (...) {
    const FOOT = ‘BALL’; //无效定义
}
  • const 采用一个普通的变量名称,define 可以采用表达式作为名称。如:
const FOOT  = ’BALL’;
for ($i = 0;$i < 32; ++$i) {
    define(‘BIT_’. $i,1 << $i);
}
  • const 只能接受静态的标量,而 define 可以采用任何表达式。如:
const BIT_5  = 1 << 5; //无效定义
define(‘BIT_5’,1 << 5); //有效定义
  • const 定义的常量对大小写敏感的,而 define 可通过第三个参数(为 true 表示大小写不敏感)来指定大小写是否敏感。如:
define(‘FOOT’,’BALL’,true);
echo FOOT; //BALL
echo FOOT; //BALL

2. 说明函数传值与传引用的区别。

  • 按值传递:函数范围内对制的任何改变在函数外部都会被忽略。
  • 按引用传递:函数范围内对值的任何改变在函数外部也能反映出这些修改。

优缺点:

  • 按值传递时,PHP 必须复制值。特别是对于大型的字符串和对象来说,这将是一个代价很大的操作。
  • 按引用传递则不需要复制值,对于性能提高很有好处。

如果不想改变原变量的值的时候就传值,如:

<?php
    $a = 1;
    function aa($a) {
        echo ++$a;
    }
    aa($a);
?>

如果可以让函数改变了原变量的值就可以引用传值,如:

<?php
    $a = 9;
    function aa(&$a) {
        echo ++$a;
    }
    aa($a);
?>

3. 请写出至少两种不用中间值实现 a 与 b 交换值的方法。(a 与 b 全小整型)。

  • a=a+b;b=a-b;a=a-b
  • a=a*b;b=a/b;a=a/b
<?php
    $a = 1;
    $b = 2;
    $a = $a+$b;
    $b = $a-$b;
    $a = $a-$b;
    echo $a;
?>

4. “数据库”从表中 user 中选出 name 字段包含 admin 的前 10 条结果所有信息的 sql 语句。

select * from user where name like '%admin%' limit 0,10

5. 简述 HTTP 协议中 GET、POST、PUT、HELETE、HEAD 这几个请求的方法。

  • HEAD:向服务器索要与 GET 请求相一致的响应,只不过响应体将不会被返回。这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息。
  • GET:向特定的资源发出请求。GET 方法不应当被作用于产生“副作用”的操作中。
  • POST:向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体重。POST 请求可能会导致新的资源的建立和/或已有资源的修改。
  • PUT:向指定资源位置上传其最新内容。
  • DELETE:请求服务器删除 Request-URI 所标识的资源。

6. 简述 HTTP 请求状态码中 1**、2**、3**、4**、5** 的意义。

  • 1**:信息类,表示收到web浏览器请求,正在进一步处理。
  • 2**:请求成功,表示用户请求已成功被服务器接收、理解、并接受。
  • 3**:重定向,表示请求没有成功客户端必须采取进一步的动作。
  • 4**:客户端错误,表示客户端提交的请求有错误。
  • 5**:服务器错误,表示服务器在处理请求的过程中有错误或者异常状态发生。

7. 简述目前利用服务端语言解决 HTTP 无状态的方法?

HTTP 本身是一个无状态的连接协议,为了支持客户端与服务器之间的交互,我们就需要通过不同的技术为交互存储状态,而这些不同的技术就是 cookie 和 session 了:

  • cookie 是通过客户端保持状态的解决方案。cookie 就是服务器发给客户端的特殊信息。有了 cookie 这样的技术实现,服务器在接收到来自客户端浏览器的请求之后,就能够通过分析存放于请求头的 cookie 从而得到客户端特有的信息,动态生成与之相对应的内容。
  • session 通过服务器保持状态。session 是服务器端为客户端所开辟的存储空间,在其中保存的信息就是用于保持状态。在服务器端建立 session 后,客户端和服务器端之间用 session id 联络,从而使用户的状态得以保持。

例,在 CodeIgniter 框架下 session 的建立和使用。Session在服务器端的建立与使用:

<?php $this->session->set_userdata('user',$user);?>
<?php $user = $this->session->userdata('user');?>

8. 谈谈你对MVC的理解。

MVC是模型(Model)-视图(View)-控制器(Controller)的缩写。它是一个强制性使应用程序的输入、
处理和输出分开的设计模式。它们各自处理自己的任务。视图是用户看到并与之交互的界面。模型表示企业数据和业务规则。控制器接受用户的输入并调用模型和视图去完成用户的需求。

  • MVC的优点:低耦合性、高重用性和可适用性、较低的生命周期成本、快速的部署、可维护性、可拓展性,有利于软件工程化管理。
  • MVC的缺点:没有明确的定义,完全理解MVC并不容易、不适合小型规模的应用程序、视图与控制器间的过于紧密的连接、视图对模型数据的低效率访问问题等。

9. 描述你在开发过程中遇到印象最深刻的问题以及解决的过程。

CI 框架下的传参问题。暑假刚接触 PHP 和 CI,便有做一个用户登录并接收到属于用户自己的欢迎界面的想法,需要用到传参。预期功能是注册、登录并完善信息后,网页左上角输出用户姓名+问候语。最初用的是类方法中的传参,在一个方法里分配视图的时候合并参数建立数组并保存到 $data 中传递给视图,再在视图中调用。但随着网页层级的加深,跳转传参变得既困难繁琐又重复难改,为了优化源码,便于理解和修改,开始寻找解决方法。解决问题的过程中依靠最多的是用户手册、百度百科和其他博主的博客,找要点学习从而知道了 session。当用 session重新部署源码后,省去了很多空间,也使源码变得清晰易懂,优化很多。最终以邮件保存此段经历心得收尾。而下面所附的迷你型网站项目便是此次经历的成果。

下附

就这么交上去,凭着自信与奋进的心博得了二面的机会。二面时间将定于下周,并要求带上自己在linux下上传的网站作为二面试题。

[B12]“消失”的这俩个月里,我的前端项目如何从零开始

“消失”的这俩个月里,虽然我的技术博客没有更新,却也发生了很多事情值得自己凝聚。

先是拜读了赵皓阳的新书《生而贫穷》,书中用大量的客观数据描绘了一个驱离的世界——贫者越贫与阶级固化。其中让我感悟到,当我们大学生觉得自己被高成就人才“碾压”而感叹自己的命运之时,还有很多根本走不到高考这一步的孩子们填充着金字塔的底层;国内互联网巨头公司即使形成了垄断资本链,不断贪婪地吞噬着新兴的中小型软件公司,人民日报一批判,腾讯市值也得蒸发个千百亿。

再是经历了自己喜欢的自媒体公号被整肃的痛心过程,其中包括对“毒舌电影”的封杀和对赵皓阳的公号的一个月禁言。难怪以特立独行为特点的自由主义者李敖先生,在 05 年来大陆进行神州文化之旅时曾表示愿意抛弃自己的自由主义,来换我国宪法中白纸黑字的“言论自由”,现在看来,这条路还挺久。

话说回重点,当然要凝聚一下这俩个月我对前端项目的实践心得,也是本文的主旨——曾经大谈方法论的我,在实践过程中如何快速填坑,又如何感悟到以后要避免像这次一样在编程上的大量“搬砖”?

“消失”的这俩个月里,我的前端项目如何从零开始。

项目背景及功能拆解

一切之前,先看一下提交作品阶段由我原声解说的真实系统演示与功能详解的视频,如下。

@中软杯初赛-真实系统演示视频及功能详解-CreatShare

可见这场**软件杯竞赛我们选的竞赛题目是基于微信公众号开发的借阅伴侣,其中的核心需求如下:

  • 用户可以进入借阅书城搜书、借书,包括扫码搜书
  • 用户可以收藏、预订书籍并及时得到公众号的主推提醒
  • 用户可以修改信息或查看自己的搜书、藏书、预订书籍的记录
  • 管理员需要授权用户借阅此书和验收用户归还书籍并确认无损
  • 管理员需要录入相关书籍信息,管理管理员用户

原型制作

有了上示所列的功能,根据微信公众号服务的是手机用户的特点,不难设计出一个通用的手机端风格的原型。原型底下的导航栏中的四个功能,便是整个应用的核心:图书导航、书库搜书、借阅书车和个人中心。这里使用“墨刀”原型设计工具,原型设计工具能仿真交互上的一些操作,最终还能将结果导出成 HTML 放置到服务器上,方便给他人发送链接进行功能交流。

架构项目

能在一个竞赛中展现自己的特点想必一定是好事,刚开始构想项目所需要用到的技术栈的时候,一股脑把我知道的(都没实战过的)所有技术点都诺列了出来,每个技术点各有分工,一时美哉,如下。

  • Bower 做 JavaScript 的包依赖管理
  • JQuery 封装 DOM 操作并进行跨域请求
  • NPM 做 Node.js 的包依赖管理(没用上)
  • ESLint 做代码风格规范检测(未实现)
  • Grunt 启动 Karma 统一项目管理(未实现)
  • Istanbul 检查单元测试代码覆盖率(有问题)
  • Jasmine 做单元测试(有问题)
  • JSDoc 规范代码注释风格(未实现)
  • Karma 自动化完成单元测试(有问题)
  • Webpack 最终打包整个项目文件(未实现)
  • Yeoman 最后封装成一个项目原型模板(未实现)

除了前俩个技术点使用起来真的很简单外,别的技术点在尝试的过程中都遇到阻碍,用 Karma 自动化完成 Jasmine 单元测试并依靠 Istanbul 将测试覆盖率输出成 HTML 这个本来是实现成功了的,但引入 JQuery 后,Jasmine 默认不识别 JQuery 的 $ 符号及其各种函数,这几个技术点便在最后暂时被抛弃。

其实,Karma、Jasmine、Istanbul 被抛弃的主要原因是自己还不习惯,或者说不会,先写测试再写程序,也就是测试驱动开发。虽然测试驱动开发在去年暑假的特训营里学过,但久久的未深入和这次项目功能的复杂性自己一时无法预测完毕,才导致自己刚开始就先写了注册时的输入框验证的测试代码,后期的所有功能代码都是想到就直接跳过测试来写实际代码,后期引入 JQuery 时遇到 Jasmine 默认不支持 JQuery 才发觉测试代码的坑已经很难及时弥补回来了,期末和竞赛就快要截止这两件事更重要。

最后的项目目录是这样的,鉴于本次项目开发过程构建在 Git 上,开源许可证书、说明文档、Git 忽略文件都必不可少;Bower 管理器需要 bower.json 配置文件并会据此生成 bower_components 依赖库、Node 包管理器需要 package.json 配置文件并回据此生成 node_modules 模块。prototype 放原型设计工具导出的有交互功能的 HTML 页面,项目最后合并后端代码时导入 java_api 和 php_wechat 库,就是最终的整个目录结构了。

├── LICENSE # 开源许可证书
├── README.md # 项目说明文档
├── app # 移动端前端项目正式源码
│   ├── admin # 移动端管理 APP 源代码
│   └── user # 移动端用户借阅官网源代码
├── bower.json # Bower 前端库依赖关系
├── bower_components # Bower 前端依赖库(.gi)
│   └── 相关配置详见 [bower.json](./bower.json)
├── images # 公用图片库
├── java_api # 服务端搜索引擎接口源码
├── karma.conf.js # Karma 自动化完成单元测试配置
├── node_modules # Node 安装模块(.gi)
│   └── 相关配置详见 [package.json](./package.json)
├── package.json # Node 配置
├── pc # 电脑端前端项目正式源代码
│   └── admin # 桌面端管理系统源代码
├── prototype # 原型图 HTML 版
├── unit-test # 前端单元测试
├── php_wechat # 微信端源代码
└── .gitignore # Git 版本管理忽略信息说明文件

根据项目要求,我们需要开发管理员手机端、管理员电脑端和用户手机端——统一起来就是手机端和电脑端,手机端包括用户模块和管理员模块,不难架构出 app 、app/admin、app/user 和 pc/admin 的文件目录,其中这三个目录里的子目录都是这样的:

├── *.html # 低耦合的 HTML 页面
├── css # CSS 源代码
├── images # 背景图、LOGO 等
└── js # JS 源代码

因为没用上测试和 Webpack 等技术,也就没有了其相应目录。

UI 开发

刚刚提到了制作出的原型能导出 HTML,那我们岂不美哉?把原型设计工具当成像 DreamWeaver 一样的可视化前端开发工具真的可以吗?我们来看看导出的源码。

源码里能看到项目被 webpack 打包,况且很多 CSS 也可能是用 SASS 等预处理器编译后的结果,并不是真正易懂的源码,前端开发人员依然需要运用 UI 技术从原生程序搭建自己的项目。

HTML 实现

在 app/user、app/admin、pc/admin 中的结构刚刚已经介绍,HTML 就分别地放在这些目录下。目录结构中提到的低耦合,要求我们将 CSS 写到 CSS 文件,将 JS 写到 JS 文件中,最后再分别合并 CSS 文件和 JS 文件到自己的文件夹中即可。方便起见,刚刚说到的三个项目目录结构再次放到这里。

├── *.html # 低耦合的 HTML 页面
├── css # CSS 源代码
├── images # 背景图、LOGO 等
└── js # JS 源代码

在我这次的 HTML 实现过程中,主要就在写 DIV 标签及其用到的 Class 属性名、偶尔修改一下外链。在刚用户进入的图书导航的首页上,我们可以在不写 CSS 的情况下构建出下列 DIV 层次结构。其中我写的这个可能并不是最优方案,甚至称不上好,但它达到了能用的效果,并让我及时的提交竞赛作品,后期改进即可。

  • 图书导航页原型图:

  • 图书导航页 DIV 层次结构

其中注释里说的“这里将被 ajax”加载、“这是书名等”可以在后期才开发 JS 代码需要填充页面时再加上,前期写一个死的文字模板反而方便在开发 CSS
代码时及时布局效果。

CSS 实现

实现 CSS 代码时,这里使用了一个看起来不那么方便的选择器方式 —— 从和当前 DIV (也可以看做“组件”)直接相关的根 DIV 开始向下写,CSS 的优先级并不需要这样写,但这样写好处之一是能快速看出层级关系,修改相应代码。这是我从“海投网”中借鉴的,以后学 SASS 或重构 UI 时可以考虑尝试另一种风格,渐渐找到较为合适自己的那一个。

/* 轮播图 */

.mSlideShowWrap {
    margin: 0;
    padding: .2rem 0 0 0;
    height: 8.6rem;
    width: 100%;
    display: block;
}

.mSlideShowWrap .mNewBooksSideBar {
    height: 8.6rem;
    width: 1.4rem;
    border: #bbb solid medium;
    display: block;
    float: left;
    background-color: #fff;
}

.mSlideShowWrap .mNewBooksSideBar .mSideBarTitle {
    margin: 0;
    padding: 0 0 .2rem .1rem;
    height: 2.15rem;
    width: auto;
    display: block;
    color: #000;
}

由于之前浅尝辄止 CSS,在其实现过程反而不会使用 position、float 等功能,布局方面多用 CSS3 的 flex 实现,快速学习 flex 之后的大部分写 CSS 的时间,都在搬 flex 的砖,这就是我搬砖的由来,却因之后的 JavaScript 编程实战而“高潮”。

逻辑与接口实现(JavaScript 编程)

大前端时代到来,简单的前端界面设计人员早已饱和,前端技术也迎来了新的高度,很多时候我们是将前端开发者和 JavaScript 程序员挂钩起来的,然而事实上并不是这样。前端工程师起初多叫重构工程师,从《Web 全栈工程的自我修养》作者余果的求职经历可以看到,最开始前端就是偏向设计和交互的,就是用来一丝不差的实现高保真原型图,现在用户体验的要求上来了,异步请求的需求量上来了,JavaScript 才渐渐成了前端工程师的必备技能,甚至渐渐的,“掌握至少一门后端语言”也加入到了前端工程师的招聘需求中。

看来又多说了几句,这次竞赛前端项目的最后就是用 JavaScript 进行逻辑与接口的实现。我们来分别谈一谈。

JavaScript 逻辑实现

逻辑实现包括输入框信息的验证、页面的跳转和用户登录状态的保存等。在引入 JQuery 后,这一切开发变得简单起来。

下面是一个用 JQuery 快速实现的输入框验证代码示例。

var password = $("input:eq(0)").val();
var newPassword = $("input:eq(1)").val();
var rePassword = $("input:eq(2)").val();
var identity = $("input:eq(3)").val();
var flag = 1; // 1 代表判断通过

if (!checkIDCard(identity)) flag = 0, tips = "不符合正确的身份证号格式";
if (!compareTwoPassWord(newPassword, rePassword)) flag = 0, tips = "密码与重复密码不一致";
if (!checkPassword(rePassword)) flag = 0, tips = "不符合正确的重复密码格式(6~13位)";
if (!checkPassword(newPassword)) flag = 0, tips = "不符合正确的新密码格式(6~13位)";
if (!checkPassword(password)) flag = 0, tips = "不符合正确的旧密码格式(6~13位)";

下面是一个根据逻辑需求进行页面跳转的代码示例。

if (data["IsSuccess"]) {
    $(".pContentMessage").text("录入成功!正在重新加载");
    setTimeout(function () {
        window.location.href = "admin_center.html?tab=0";
    }, 1000);
}

JavaScript 接口实现

前后端分离的项目中,后端只用注重接口的实现即可,一个一个很短的接口链接及其参数说明、返回结果说明抛给前端,前端就要进行各种相应的逻辑编程、UI 编程,正想不通,为什么在我周围,学前端的还是女生多。当然啦,前端业界的领头人物性别比例就不多说了。我曾在一个前端微信群中聊过这类有关性别平等的话题,偏见还是很多的,就在我们身边,这里就不多多说来。啊,前端和后端也平等。

一言不合,后端抛给你个接口,长得还很奇怪的样子:

补全图书信息
  • 请求地址

https://corefuture.cn/lib_api/book/finishBook.action

  • 请求类型

HTTP:POST

  • 参数
参数名称 参数说明 必填
isbn 书的isbn号 Y
  • 结果示例
{
  "next": "",
  "count": 1,  
  "books": [
    {
      "bId": null,
      "bName": "大型网站系统与Java中间件开发实践",
      "sId": null,
      "cId": null,
      "spell": null,
      "initial": null,
      "imgurl": "https://img1.doubanio.com/mpic/s27269837.jpg",
      "isbn": "9787121227615",
      "author": "曾宪杰",
      "count": null
    }
  ]
}
  • 返回参数说明
next:下一页得next值,""表示没有下一页
count:books中含有几本书
books:book的集合
book{
	bId:书籍唯一标识
	bName:书籍名称
	sId:书库的标识ID
	cId:书籍类型的标识ID
	spell:全拼
	initial:首字母
	imgurl:书籍图片路径
	isbn:书籍的isbn号
	author:作者
	count:书库中该书的总量
}

当然,前端进行数据访问的跨域权限需要后端支持,具体怎么支持这就不是前端的事了。当后端有上述接口示例交给前端时,如果不是需要带有 Cookie 等参数的接口,前端可以直接用代码实战访问,根据浏览器开发者工具里的具体报错信息来修改代码;更推荐在写跨域代码前先用 postman 这类的可视化 HTTP 请求工具/ API 测试工具来测试。

postman - 可视化 HTTP 请求工具

编写跨域请求代码时,需要一些异步回调相关的知识,当请求结果返回时触发回调函数,进行相应的操作。这里用道德回调函数,主要就是页面跳转和数据渲染两个功能,例如一个完整的跨域请求函数,并将返回结果渲染到页面的代码可以是下面这个样子。

function finishBook () {
    // 隐藏详情页
    $(".pContentDetailWrap:eq(0)").hide();
    $(".pContentSubmitWrap:eq(0)").hide();
    var isbn = $("input:eq(0)").val();
    var post_data = {
        "isbn": isbn
    };
    if (!isbn) {
        $(".pContentMessage").text("ISBN 号不能为空");
        return;
    }
    var post_url = "https://wwwxinle.cn/Book/public/index.php/index/Manager/infoBook";
    $.post(post_url, post_data, function (data, status) {
        data = JSON.parse(data);
        if (data["count"] == 0) {
            $(".pContentMessage").text("没有找到相关信息");
            return;
        }
        var book = data["books"][0];
        $(".pContentDetailLeftWrap img").attr("src", book["imgurl"])
        $(".pContentDetailItemWrap:eq(0) input").val(book["bName"]);
        $(".pContentDetailItemWrap:eq(3) input").val(book["author"]);
        $(".pContentDetailItemWrap:eq(4) input").val(1);
        $(".pContentDetailHiddenWrap").text(JSON.stringify(book));
        $(".pContentDetailWrap:eq(0)").show();
        $(".pContentSubmitWrap:eq(0)").show();
    });
}

回调成功,一个完整的跨域流程和前端对接口的实现流程就到了收尾之处。回调函数还有很多其它的注意点,比如回调函数里的变量值不能被回调函数外访问的时候需要注意什么等,遇到这些坑时可以选择尽可能将外部变量及其功能放入内部实现,或用其他更前沿的技术来实现。

整体架构回顾

之前一直在说前端项目的构建过程,在我们团队三人的整体分工中,也是有其整体框架:Web 前端和没有数据库的 PHP 后端进行请求,PHP 后端和有数据库的 JAVA 数据接口进行请求,JAVA 数据接口直接访问数据库——沃,其实队友用的是基于 Apache Lucene(TM) 的开源搜索引擎,只不过我当时看到他们进行 SQL 操作了,不知者无罪~

独特吧?Node.js 除了做后端,也可以做“前台”,就是这时 Node 不操作数据库,操作数据库的还是典型的后端语言如 PHP、JAVA、Python 等;那么在这个项目中,PHP 微信端有点“前台”的感觉,主要承载着每个人专属微信号信息的获取和公众号的主推功能,并向 JAVA 后端进行数据访问。Web 前端只和 PHP 微信端进行联络。

如果可以和 MVC 架构联系起来的话,Web 前端是大 V,PHP 微信端是大 C,JAVA 服务端是大 M;其中每个大 V、大 C、大 M 都有自己小 V、小 C、小 M。神奇的逻辑。

舍不得收尾、说拜拜

转眼间,自己还在大学期间学 JavaScript 基础、学习 CSS 布局的时候,ES 7、ES8 都开始被各大社群讨论;React、Vue 等主流框架也开始加深诱惑着我们初学者;各大培训班疯狂输出的前端学员就光数量上也让大学生软件开发学习者有所担忧。

一切还好。正如文章开始的那些感悟中隐藏在背后的那句罗曼罗兰式英雄的风度一样——“世界上只有一种真正的英雄主义,就是认清了生活的真相后还依然热爱它”。

哈哈,希望我的引用不算错位。也希望我的这个项目总结能散发出本身应有的光芒。

[A12]freeCodeCamp西安第一次线下编程活动体验

很荣幸能被 FreeCodeCamp 中文官方订阅号推送此文

最早是在 2016 年 06 月份逛知乎的时候,看到 《零基础的前端开发初学者应如何系统地学习?》 而了解到 freeCodeCamp (简称 FCC)。在点赞排前的介绍里面,FCC 作为有着“社区”、“培养体系”、“开源”等特点深深吸引了我,毕竟在我这一年对自己的 web 开发学习之路的总结中,一直也尝试着将总结和由总结产生的项目灵感变为可以分享的文章和开源项目,而 FCC 给我了类似的平台,并且做的更好。

这是全世界学习 Web 开发最好的地方,Learning by Doing 也是最好的方式。

步入 freeCodeCamp 社群

开源社区的特点是广纳贤士的,仅仅通过官网和搜索引擎就可以很快地找到相应的线上讨论组。那时 FCC 中文网的建立时间也不久,正值野狗杯在 FCC 中文网上举办苏州全民编程挑战赛,我也就很快的找到并加入了苏州群,同时了解到了 FCC 的中文运营团队猿生态总部同样坐落于苏州。

06月份在 FCC 中文网举办的苏州全民在线编程挑战赛

FCC 苏州群潜水的过程中发现还有深圳、广州、成都等城市已经有相应的城市群组建立且有 FCC 用户的互动,却没有西安这边的任何消息,于是不甘被“冷漠”的我突然有着一股肩负着西安 WEB 编程社区发展的使命感找到了 FCC 中文运营这边的负责人峰哥。

我: “我要建立 freeCodeCamp 西安”
峰哥: “OK,拉我”

一次对机会的争取就这么如此轻松地搞定,更应证了之前所说“开源社区的特点是广纳贤士”的观点。freeCodeCamp 西安社群就这么成功建立。

freeCodeCamp 西安社群的前期发展

06月份就建立起 FCC 西安群并拉峰哥入群,但开始的几周由于自己要准备期末考试也没有去推动,以至西安社群内一直只有两个人的境况。这不是我想要的结果。于是在暑假抽出了几天时间攻克了 FCC 前端挑战的前 262 个小关卡(请无视我中间跳过的几个需要翻墙的关卡。。)总体感觉 FCC 的课程设置很平滑,既有循序渐进的基础知识,又有需要你自由发挥的开发小项目,和打游戏闯关一样的学习体验,比起观看教学视频,w3cschool之类的更加生动有趣。辅之以 HTML + CSS 等知识自己之前有所了解,因此开始的学习效果还算可以。

在对 FCC 有了一定的体验后,一直还不知道如何去宣传,才能找到西安 FCC 用户,恰逢 FCC 微信公众号推送了一篇 freeCodeCamp 社群从 0 到 1000+ 博文后,自己直接分享至朋友圈即可,带动了自己周围的一些学习前端的同学加群参与。也是这时每个城市社群群主都自觉地将群主职位转移至名号为“fcczhongguo”的新建微信号进行统一运营管理、FCC 中文网上上线了同城学习小组可以选择城市报名,终于吸引来了不是自己认识的 FCC 西安用户。更加的像个“城市小组”了。

freeCodeCamp 西安第一次线下活动

所以整个 freeCodeCamp 西安社群的建立过程我是很活跃于其中的。在一次群内有关“什么时候有 FCC 西安线下活动呢”的讨论中,自己也就主动承担起了“组织者”的小责任。开始推动第一次活动报名并规划理想的活动流程。

以上是第一次举办前自己对活动流程的展望,而在实际的活动中,结对编程环节占用时间更多,别的集中探讨了一下,并没有系统的分享 —— 毕竟大家对每个人的能力差距较大,且大学生和女生更多一些。

必不可少也颇具趣味的破冰环节让大家相互熟识彼此,也更加了解了这次活动的意义(当然每个人都能感悟到与众不同的意义)。这次活动中认识到的有正在西邮、西电、西交大上学的同学,还有西京毕业正在找工作的、从南京回西安发展的朋友。来自不同背景的人聚集在一起快速的相识相知并分享自己,不失奇妙。

能够教给别人是最高级的学习。

同时向成都站的伙伴学习,在 Github 上建立了 FreeCodeCamp-XiAn 组织,教会大家如何把自己的灵感放到 FCC-XiAn-Idea 提交到 issue 之中,以后在自己的生活中想到什么好的项目灵感的话可以在这里提出倡议,邀请有兴趣的伙伴参与开发。

freeCodeCamp 学习方法

FCC 是一个大平台,提供的不只是有趣的关卡式编程挑战,还分享了很多学习资源和学习方法 —— “一读二搜三提问”便是 FCC 提倡的解决问题的最佳思路。

学习freecodecamp的正确方法是什么?

一读 -- 读 MDN 开发者手册

作为一个开放的,由社区驱动的维基系统,MDN 给 Web 开发者,设计师,应用程序开发者,以及 Firefox 扩展和主题作者带来了最好的文档,教程以及开发工具.任何人都可以通过在上面添加或编辑文档来让它变的更好.只要是 Web 相关的资源,不管是什么浏览器,什么平台方面的知识,都可以。

https://developer.mozilla.org/zh-CN

二搜 -- 在 StackOverFlow 上搜疑难

Stack Overflow 是一个与程序相关的全球性 IT 技术问答网站。用户可以在网站免费提交问题,浏览问题,索引相关内容,在创建主页的时候使用简单的 HTML。在问题页面,不会弹出任何广告,销售信息,JavaScript 窗口等。

http://stackoverflow.com/

对于国内开发者来说,在 Stack Overflow 上用英文提问和用英文解答编程问题都是一个提高英语能力的成长挑战,以后看一些英文开发文档也不会有太多的反感或不适应。

三提问 -- 在基于 GITTER 的 FCC-Chinese 聊天室提问

GITTER 面向开发者和 Github 仓库,提供一个及时聊天室的环境并向每一个用户和社区开放。在这里的讨论都可以被保存下来,供自己和他人讨论和回顾。

而 FreeCodeCamp 英文网和中文网都在 GITTER 上有相应的聊天室,当自己遇到一些独特的难题搜索不到相应文档和相应解决思路时,可以将问题提在这里 —— 每一个人都很热情地去帮助他人解惑,还能认识到更多的朋友,拓展视野。

每个你独立解决的问题都是你成长路上的进步和飞跃。

对 FCC 西安小组活动的展望

  • 仿照 node-party 在 github 仓库中记录每一次精彩内容和合影,在这里我们上线至 FCC-XiAn-Traveller 中;
  • 选择咖啡馆时提前了解到投影仪、话筒、音响等设备是否能够提供,如果提供不了是否需要我们自己准备;
  • 可以尝试用 trello 类的工具跟踪每个人在这次活动中的项目进度和对这次活动的感悟;
  • 希望以后会有每个人对自己最近做的真实项目分享会以及编程知识分享会(若有留下ppt等资源,上传至 FCC-XiAn-Traveller 中)。让分享不止于每个人自己的人生经历,还能加上更多实在的“编程干货”;
  • 线下活动变得更加自由,流程更加活力化而不是被“安排”。

FCC 西安第一次线下活动合影

Awesome-Ideas

P.S: 灵感已迁移至 Keynote 以作更好的管理

我的灵感集

项目

六颗星

  • “学生作业系统”,开发中。
  • “二人世界”,开发中。
  • 微信小程序 - freeCodeCamp
    • 题解,题库
    • 各城市社群交流区
    • 发布提问 + 红包奖励机制
    • 分享问答
    • 打卡激励等
    • 问答挑战
    • flag 及其监督机制
    • 读书活动等专属活动页
    • 开发团队
  • “影院票务管理系统”,开发中。
  • “freeCodeCamp 西安前端社区官网”,开发中。
  • 创享堆·微前端架构下的一站式技术团队运营平台
  • 凝果屋·微前端架构下的一站式个人平台

五颗星

  • CreatShare
    • 外部
      • 校内食堂点餐接单送外卖、校内代取快递
      • 旧产品:西邮导航、百盘、畅校园图书馆
    • 内部
      • 纳新系统、博客系统、SSO 单点登录系统、培养方案主页
      • 内部平台:视频寄语、每年资料存储、考勤系统、运营报表系统
      • 内部聊天室、内部读书清单、产品线前后端
  • 学校项目
    • Coursework-System
    • 人机界面系统
  • 源创未来
    • 网络资源共享(电子书、文章、音乐)、实体资源共享、内部知识笔记中心、结合各人特色
    • 知识笔记分为碎片笔记和文章类、书信类
    • 在线 PC 写作
  • fcc
    • fcc 全国微信群公用机器人
    • fcc-西安官网(相册、活动宣传、活动回顾等)
  • 二人世界
    • 主页相册、我们的原创书/博客展示、我们的项目页
    • 我们的简历页、内部电子书库、内部 git 仓库
    • 人生轨迹网
  • 毕设:编程题目发布/竞赛、编程知识共享网络
  • 前端编年史:时间线、搜索、github登录、共同维护

四颗星

  • 基于 Alfred 开发如下插件:
    • 英英/英汉搜索 dictionary.cambridge.org 下的单词
    • 搜索自己网站上隐藏的盗版电子书
  • 基于 CodePen 放自己的实战 demo
    • 各大报纸的 UI 仿真
    • 各大 TV UI 仿真
    • 某技术特性实战
    • ...
  • 书签分享、导入导出、管理、交流平台
  • UPPER:全栈工程师
  • 仿照如下插件,在阅读多链接网页时有快速预览功能,无需打开新标签页

image

三颗星

  • 成就日记
  • 前端游戏开发社区
  • 以技术大牛为纽带的社交人脉推荐网络
  • 类似第三方评论系统,可部署于某个(子)域名下的侧边栏评论区,平时缩小为右下角的展开按钮
  • 类似上一行所述,部署到网站上/浏览器插件,平时缩小的网站开发 todo-list
  • 技术社群一体化运营方案网站,开场白+动手+茶歇+动手+结束等快速设置,快速生图
  • 打印文章爬虫网,汇集各大技术文章分享平台,将不支持浏览器直接输出 pdf 的网站爬虫并重构成支持的
  • 自品牌娱乐圈,邀请微信自媒体博主加入,促进群内自媒体文章分享,友好诚信地互赞互刷

二颗星

  • 网页在线电子书阅读器
  • Git 多人协作训练,gitlostin
  • 正则表达式学习与训练
  • 将自己所有注册过的网站可视化出来的平台
  • 输入一篇文章(和某些指定参数),输出一张分享图,有头图,可以扫描二维码阅读
  • js C 编译器,托管 cdn,供无数人在线引用,浏览器编译

一颗星

  • 多人协作同时编辑的在线 PPT~
  • dom 可视化
  • 一键收藏 github 组织的谷歌浏览器插件
  • 全平台桌面版、移动端、开源的 (web 学习平台)/(服务于幸福家庭的全家桶)
  • 常用的原生 js、css 代码片段集合
  • Amazon 收藏夹 -> 大数据分析读书爱好 -> 数据可视化显示
  • PWA **
  • 程序猿的趣味世界,用来发布程序员趣味图、点赞排行
  • 我的 CSS 之家,仿照 http://www.17sucai.com/ 等,集中整理自己的 CSS 特效代码
  • 前端娱乐圈 - 前端大牛人脉网络
  • V-to-learn-linux
  • V-to-learn-git
  • ...

人工智能 && 区块链

  • 城市地图迷雾 & 运动探索
  • 城市
    • 为每个建筑物内置一个通过图灵测试的智能体
    • 通过不同的测试集和该建筑品牌形象形成不同的性格
    • 智能体间可以定时交流,互相增加彼此测试集

[B03]强化你的打字速度

The quick brown fox jumps over the lazy dog.

不要复制粘贴,开始计时,连续快速敲 3 遍上述名言,看看你能用多少秒?

81 秒以内,你的水平仅仅是初级,45 秒以内,你的水平已经达到了中级,27 秒以内,恭喜你,你的速度超过了全球 99 % 的键盘手。

这个是怎么计算出来的呢?WPM,Word Per Minute,每分钟敲出的单词个数(5 个字符被视为一个单词),便是这次打字速度的一个参考标准。初级、中级和高级的水平评判准则分别是 20 WPM、40 WPM和 60 WPM。

再次回顾文章开头的名言,敲击三遍之后的 135 个字符的速度换算过来,就得出了 81 秒、45 秒和 27 秒的评测标准。

(135 character / (5 character / words) ) / (60 words / min) * (60 s / min) = 27 s

那么问题来了,关于打字速度,我们能获取到什么知识呢,又该如何提高?

1

早在计算机出世之前的 19 世纪开始,就相继有英、美、法等国家的人发明了各种形式的打字机,最早的键盘便存在于那时技术还不太成熟的打字机上。

1868 年,第一台实用即真正的现代打印机由美国人 Christopher Latham Sholes 发明并取得专利和经营权,在随后的产品改进和商业推广中,将独特的 “QWERT” 键盘布局理念遍布于世。

实际情况与推广宣传语 “QWERT” 键盘布局是最科学的键盘布局情况恰恰相反, “QWERT” 键盘布局的出现反倒是使击键的速度不至过快,从而保证在高速打字时打字机键位不至于使连动杆纠结在一起而卡死。正如 1986 年布鲁斯·伯里文爵士曾在《奇妙的书写机器》一文中表示:

大多数打字员惯用右手,但使用 QWERTY,左手却负担了57%的工作。两小指及左无名指是最没力气的指头,却频频要使用它们。排在中列的字母,其使用率仅占整个打字工作的30%左右,因此,为了打一个字,时常要上上下下移动指头。

随着技术的发展,连动杆纠结不再成为一个问题,就有了 1936 年美国人 August Dvorak 设计的 Dvorak 键盘,让右手和左手的负荷尽可能相等并最大化中间排 (Home Row) 的负荷。

在这些方面,Dvorak 键盘确实做得很好:打字的67%在中间排进行,左右手平衡是 47% : 53%,也依此创造了世界上最快的英文打字速度之吉尼斯世界记录 —— Barbara Blackburn 每分钟峰值 212 个单词,连续 50 分钟平均每分钟 150 个单词的记录。

却由于用户惰性等原因,无法推广这种更有效率的技术。其它常见的键盘输入布局还有九宫格等。

2

输入法的需求来源于键盘的限制。多数输入法软件是为汉语、韩语和日语设计,因为键盘原在打字机时代为英文字母而设计,科技发展到现在,还有手写、语音输入方式等广义上的输入法相继出现。

这些都可以到常见输入法软件的设置中获取信息。除了本地输入法应用程序文字的输入功能外,随着互联网的发展,不少互联网公司也推出了基于云平台的在线输入法,可以在浏览器上直接调用输入法进行汉字的输入。

中文输入法的编码虽然种类繁多,归纳起来共有拼音编码、形码、音形结合码三大类。

拼音输入法采用汉语拼音作为编码方法,包括全拼输入法和双拼输入法。广义上的拼音输入法还包括**人使用的以注音符号作为编码的注音输入法,香港人使用的以粤语拼音作为编码的粤拼输入法。

形码输入法是依据汉字字形,如笔画或汉字部件进行编码的方法。电脑上形码广泛使用的有五笔字型输入法、郑码输入法。

3.

当选择好自己将要熟练掌握的键盘布局和输入法后,进行打字速度训练可以节省我们的大量时间。这种训练,不是多与人线上聊天能简简单单的解决。

这里以我们常见常用的 “QWERT” 所为例,如下图,标准的指法是,左右手食指分别放在盲打坐标 “F” 和 “J” 上,其余手指在键盘中间排自然展开,每个指头负责指定的区域,每当敲击过任意一个键过后,自然复位。

在训练打字速度过程中,要达到如下目标,才能相辅相成,相得益彰。

  • 坐姿端正,显示器高度合适,以免颈椎、腰椎、手腕、手指等受伤。
  • 标准的指法,每个指头负责自己的区域,不要为一时的方便去越位而养成不良习惯。
  • 手指及时复位。每次敲击键盘后,手指自然回归中间排,为下一个按键能够用标准指位完成做准备。
  • 保持稳定的节奏。当姿势恰当,干脆利落的击键和复位,最终会形成稳定的节奏,使更快的打字速度成为可能。

理想的打字姿势

4

相应的训练软件数不胜数,在线、离线、游戏化应有尽有。

写这篇文章的初衷,便是自己准备入手 VIM 而关注打字速度和打字指法,在 typing.com 上磨炼数小时所感触。

typing.com 之我爱打字打字爱我

成就化挑战,自定义皮肤,再加上该平台上有趣也不失紧张的打字游戏,使得无数打字学者“竞折腰”。在 6 小时较为枯燥的打字过关挑战中,我的速度也稳定在了 40+ WPM,每分钟 40+ 单词,中级水平。

马里奥忙不过来的样子.jpg

只要够坚持,四个大关卡挑战过后有惊喜。

5

大学英语课堂上“不安分”的我

那么,你用的是什么键盘布局?什么输入法呢?

你的键盘打字速度,有做过测试嘛?不妨借此试一试,交流交流。

祝你有个更快速的打字速度,剩下的时间,多陪陪亲朋好友。

[A0B]面向对象三大特性五大原则 + 低耦合高内聚

面向对象的三大特性是"封装、"多态"、"继承",五大原则是"单一职责原则"、"开放封闭原则"、"里氏替换原则"、"依赖倒置原则"、"接口分离原则"。

image

什么是面向对象

面向对象(Object Oriented,OO)是软件开发方法。面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD技术、人工智能等领域。面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。

这里拿 PHP 的 OOP 举个编程实例。

image

三大基本特性:封装,继承,多态

封装

封装,就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。

继承

继承,指可以让某个类型的对象获得另一个类型的对象的属性的方法。它支持按级分类的概念。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。 通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过 “继承”(Inheritance)和“组合”(Composition)来实现。继承概念的实现方式有二类:实现继承与接口继承。实现继承是指直接使用 基类的属性和方法而无需额外编码的能力;接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力。

多态

多态,是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。

五大基本原则:SPR, OCP, LSP, DIP, ISP

单一职责原则SRP(Single Responsibility Principle)

是指一个类的功能要单一,不能包罗万象。如同一个人一样,分配的工作不能太多,否则一天到晚虽然忙忙碌碌的,但效率却高不起来。

开放封闭原则OCP(Open-Close Principle)

一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的。比如:一个网络模块,原来只服务端功能,而现在要加入客户端功能,那么应当在不用修改服务端功能代码的前提下,就能够增加客户端功能的实现代码,这要求在设计之初,就应当将服务端和客户端分开,公共部分抽象出来。

里式替换原则LSP(the Liskov Substitution Principle LSP)

子类应当可以替换父类并出现在父类能够出现的任何地方。比如:公司搞年度晚会,所有员工可以参加抽奖,那么不管是老员工还是新员工,也不管是总部员工还是外派员工,都应当可以参加抽奖,否则这公司就不和谐了。

依赖倒置原则DIP(the Dependency Inversion Principle DIP)

具体依赖抽象,上层依赖下层。假设B是较A低的模块,但B需要使用到A的功能,这个时候,B不应当直接使用A中的具体类: 而应当由B定义一抽象接口,并由A来实现这个抽象接口,B只使用这个抽象接口:这样就达到了依赖倒置的目的,B也解除了对A的依赖,反过来是A依赖于B定义的抽象接口。通过上层模块难以避免依赖下层模块,假如B也直接依赖A的实现,那么就可能 造成循环依赖。一个常见的问题就是编译A模块时需要直接包含到B模块的cpp文件,而编译B时同样要直接包含到A的cpp文件。

接口分离原则ISP(the Interface Segregation Principle ISP)

模块间要通过抽象接口隔离开,而不是通过具体的类强耦合起来

耦合

简单地说,软件工程中对象之间的耦合度就是对象之间的依赖性。指导使用和维护对象的主要问题是对象之间的多重依赖性。对象之间的耦合越高,维护成本越高。因此对象的设计应使类和构件之间的耦合最小。

有软硬件之间的耦合,还有软件各模块之间的耦合。
耦合性是程序结构中各个模块之间相互关联的度量。它取决于各个模块之间的接口的复杂程度、调用模块的方式以及哪些信息通过接口。

耦合可以分为以下几种,它们之间的耦合度由高到低排列如下:

  • 内容耦合。当一个模块直接修改或操作另一个模块的数据时,或一个模块不通过正常入口而转入另一个模块时,这样的耦合被称为内容耦合。内容耦合是最高程度的耦合,应该避免使用之。
  • 公共耦合。两个或两个以上的模块共同引用一个全局数据项,这种耦合被称为公共耦合。在具有大量公共耦合的结构中,确定究竟是哪个模块给全局变量赋了一个特定的值是十分困难的。
  • 外部耦合 。一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传递该全局变量的信息,则称之为外部耦合。
  • 控制耦合 。一个模块通过接口向另一个模块传递一个控制信号,接受信号的模块根据信号值而进行适当的动作,这种耦合被称为控制耦合。
  • 标记耦合 。若一个模块A通过接口向两个模块B和C传递一个公共参数,那么称模块B和C之间存在一个标记耦合。
  • 数据耦合。模块之间通过参数来传递数据,那么被称为数据耦合。数据耦合是最低的一种耦合形式,系统中一般都存在这种类型的耦合,因为为了完成一些有意义的功能,往往需要将某些模块的输出数据作为另一些模块的输入数据。
  • 非直接耦合 。两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的。

总结

耦合是影响软件复杂程度和设计质量的一个重要因素,在设计上我们应采用以下原则:如果模块间必须存在耦合,就尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,尽量避免使用内容耦合。

内聚与耦合

image

内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。内聚是从功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。它描述的是模块内的功能联系。
耦合是软件结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通过接口的数据。 程序讲究的是低耦合,高内聚。就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却要不那么紧密。
内聚和耦合是密切相关的,同其他模块存在高耦合的模块意味着低内聚,而高内聚的模块意味着该模块同其他模块之间是低耦合。在进行软件设计时,应力争做到高内聚,低耦合。

[A06]C 语言常量和变量的表示、应用和变量命名规则

在程序运行中,其值不能改变的量成为常量。在基本数据类型中,常量可分为整型常量、实型常量、符号常量和字符型常量(包括字符常量和字符串常量),本文分别作出介绍。
 

一、常量

 

1. 整型常量

即整常数,由一个或多个数字组成,可以带正负号。C 语言中整型常量可用十进制、八进制和十六进制 3 种形式表示。

  • 十进制整数:由 0~9 数字组成,不能以 0 开始,没有前缀
  • 八进制整数:以 0为前缀,其后由0~7的数字组成,没有小数部分
  • 十六进制整数:以 0x 或 0X 开头,其后由09的数字和 af (或A~F字母组成)

另外长整型常量后加后缀 L (或1),无符号常量后加后缀 U (或u)
 
## 2. 实型常量

C 语言中,实数又称浮点数一般有两种表示形式

  • 十进制小数形式:由数字和小数点组成,必须有小数点(例如 .24 也合法)
  • 指数形式:有十进制数、阶码标志“e”或“E”和阶码组成,阶码只能是整数。e和E前面必须有数字,后面必须是整数
  • 实型常量的类型:C 编译系统对实型常量不分 float 和 double,都作 double 处理以更精确,也可以在实型常量后面加上字母 f 或 F 来指定其为单精度实型(float)
     

3. 符号常量

C 语言中,可以用一个标识符表示一个常量,称之为符号常量,即标识形式的常量。符号常量是一种特殊的常量,其值和类型是通过符号常量的定义决定的。符号常量在使用之前必须定义,一般形式如下:

#define 标识符常量

#define 是一条预处理命令,其功能是把命令格式中的标识符定义为其后的常量值。习惯上,为了与程序中的变量名区别,符号常量名一般用大写字母表示。
 

4. 字符型常量

包括字符常量和字符串常量。

字符常量

又称字符常数,C 语言中的字符常量是用单引号括起来的字符,区分大小写。字符常量有以下特点:

  • 字符常量只能用单引号括起来
    • 单引号只起界定作用,不表示字符本身
    • 单引号中只能由一个字符,字符可以是字符集中的任意字符
    • 单引号中的字符不能是单引号(')和反斜线(\)
  • 每个字符常量都有一个整数值,就是该数的 ASCII 码(见附录)
  • 字符常量区分大小写:对于一些常用但却难以用一般形式表示的不可显示字符,C 语言提供了一种特殊形式的字符常量,即用一个转义标识符“\”(反斜线)开头的字符序列,如表(转义字符及其含义):

字符串常量

字符串常量是用一对双引号括起来的字符串序列。C 语言规定字符串常量的存储方式为:字符串中的每个字符以其 ASCII 码值得二进制形式存放在内存中,并且系统自动在该字符串末尾加一个“字符串结束标志”('\0',即ASCII码值为0的字符,它不引起人和控制动作,也不是可显示的字符)以便系统判断字符串是否结束。例:字符串"a",实际长度为 2,包含'a'和'\0'。
 

二、C 语言标识符

 
用来标识变量名、符号常量名、函数名、类型名和文件名等的有效字符序列称为标识符。

  1. 标识符由字母(A-Z, a-z)、数字(0-9)、下划线“_”组成,并且首字符不能是数字,但可以是字母或者下划线。例如,正确的标识符:abc,a1,prog_to
  2. 不能把 C 语言关键字作为用户标识符,例如 if ,for, while 等。
  3. 标识符长度是由机器上的编译系统决定的,一般的限制为 8 字符(注:8字符长度限制是 C89 标准,C99 标准已经扩充长度,其实大部分工业标准都更长)。
  4. 标识符对大小写敏感,即严格区分大小写。一般对变量名用小写,符号常量命名用大写。
  5. 标识符命名应做到“见名知意”,例如,长度(外语:length),求和、总计(外语:sum),圆周率(外语:pi)……
  6. C语言中把标识符分为三类:关键字,预定义标识符,用户自定义标识符。
     
     

三、变量

 
变量只是在程序中可以改变的量,一旦被定义,就具备了3个基本要素:变量名、变量类型和变量值
 

1. 变量名

变量的命名规则
 

2.变量类型

C 语言中变量遵循“先定义后使用”的原则,变量定义的形式一般为变量类型和变量表名。其中变量类型即为变量中所存储的数据类型,数据类型概念详见之前博客 「C语言」数据类型及混合运算与类型转换

整型变量

整型数据在内存中的存放。在C语言中,可以使用十进制,八进制和十六进制数据,但在内存中都以二进制存。整型变量的基本类型说明符为int。根据占用内存字节数不同可以将整型变量分为如下几类:

  • 基本整型:int,在16位系统中占2字节,32位系统中占4字节
  • 短整型:short int或short,在大多数计算机系统中占2字节
  • 长整型:long int或long,一般占4字节
  • 整型变量的类型:
    • 有符号短整型:short [int]    2byte    -32768~32767
    • 无符号短整型:unsigned short [int]    2 byte 0~65535
    • 有符号整型:int /signed [int]    4 byte    -2147483648~2147483647
    • 无符号整型:unsigned [int]    4 byte    0~4294967295
    • 有符号长整型:long [int]/signed long [int]    4 byte    -2147483648~2147483647 
    • 有符号长整型:unsigned long [int]    4 byte    0~4294967295
  • 整型数据的溢出:在C语言中,如果一个变量的值超过了其类型所允许的最大值,则会出现溢出现象。

实型变量

  • 实型数据在内存中的存放。实型数据在内存中占4字节,按照指数形式存储,存放形式如下:
                    符号位+小数部分+指数部分
                    注意:所有实型数据均为有符号实型数,没有无符号实型数
                    至于在内存中究竟分别用多少位表示小数部分和指数部分,ANSI C并无具体规定,由各C编译系统决定
  • C语言提供的常用实型变量类型有单精度型(float)和双精度型(double),有时也用长双精度型(long double)
                    实型变量类型:
                        单精度型:float    4 byte    -3.4e383.4e38    67位有效位
                        双精度型:double    8 byte    -1.7e3081.7e308    1516位有效位
                        长双精度型:long double    16 byte    -3.4e49323.4e4932    1819位有效位
  • 实型数据的舍入误差。有限的存储单元能提供的有效数字是有限的,因此会存在实型数据的计算舍入误差

字符变量

            字符变量是用来存储字符常量的,每个字符占用一个字节的存储空间,类型名为char
            字符变量的类型:
                有符号字符型char/signed char    1 byte    -128127
                无符号字符型unsigned char    1 byte    0
255

 

变量值

在 程序中,一个变量必须先由确定的值后才能参与各种相应的操作。变量可以通过赋值语句或输入语句获得一个值,也可以用初始化的方法获得一个值
 

四、变量命名规则

 

  1. 命名应当直观且可以拼读,可望文知意,便于记忆和阅读。标识符最好采用英文单词或其组合,不允许使用拼音。程序中的英文单词一般不要太复杂,用词应当准确。
  2. 命名的长度应当符合“min-length && max-information”原则。C 是一种简洁的语言, 命名也应该是简洁的。例如变量名 MaxVal 就比MaxValueUntilOverflow 好用。标识符的长度一般不要过长,较长的单词可通过去掉“元音”形成缩写。另外,英文词尽量不缩写,特别是非常用专业名词,如果有缩写,在同一系统中对同一单词必须使用相同的表示法,并且注明其意思。
  3. 当标识符由多个词组成时,每个词的第一个字母大写,其余全部小写。比如:int CurrentVal; 这样的名字看起来比较清晰,远比一长串字符好得多。
  4. 尽量避免名字中出现数字编号,如 Value1, Value2 等,除非逻辑上的确需要编号。比如驱动开发时为管脚命名,非编号名字反而不好。初学者总是喜欢用带编号的变量名或函数名,这样子看上去很简单方便,但其实是一颗颗定时炸弹。这个习惯初学者一定要改过来。
  5. 对在多个文件之间共同使用的全局变量或函数要加范围限定符(建议使用模块名(缩写)作为范围限定符)。
  6. 标识符名分为两部分:规范标识符前缀(后缀) + 含义标识。非全局变量可以不用使用范围限定符前缀。

  1. 作用域前缀命名规则。

  1. 数据类型前缀命名规则。

  1. 含义标识命名规则,变量命名使用名词性词组,函数命名使用动词性词组。

例如:变量含义标识符构成:目标词+ 动词(的过去分词)+ [状语] + [目的地]; 函数含义标识符构成:动词(一般现时)+目标词+[状语]+[目的地]
10. 程序中不得出现仅靠大小写区分的相似的标识符。例如:111int x, X;··· 变量 x 与 X 容易混淆 void foo(int x); 函数 foo 与 FOO 容易混淆 void FOO(float x); 这里还有一个要特别注意的就是 1(数字 1)和 l(小写字母 l)之间,0(数字 0)和o(小写字母 o)之间的区别。这两对真是很难区分的,我曾经的一个同事就被这个问题折腾了一次。
11. 一个函数名禁止被用于其它之处。例如:

#include "c_standards.h"
void foo(int p_1) {   int x = p_1;}
void static_p(void) {   int foo = 1u;}
  1. 所有宏定义、枚举常数、只读变量全用大写字母命名,用下划线分割单词。例如:const int MAX_LENGTH = 100; //这不是常量,而是一个只读变量,具体请往后看   #define FILE_PATH “/usr/tmp”
  2. 考虑到习惯性问题,局部变量中可采用通用的命名方式,仅限于n、i、j 等作为循环变量使用。一定不要写出如下这样的代码:int p; char i;  int c; char * a; 一般来说习惯上用 n, m, i, j, k 等表示 int 类型的变量;c,ch 等表示字符类型变量;a 等表示数组;p 等表示指针。当然这仅仅是一般习惯,除了i, j, k 等可以用来表示循环变量外,别的字符变量名尽量不要使用。
  3. 定义变量的同时千万千万别忘了初始化。定义变量时编译器并不一定清空了这块内存,它的值可能是无效的数据。这个问题在内存管理那章有非常详细的讨论,请参看。
  4. 不同类型数据之间的运算要注意精度扩展问题,一般低精度数据将向高精度数据扩展。
     
     
    附录:ASCII码表
        截图自 http://tool.oschina.net/commons?type=4
        

FSD-Debris

已转移到在线笔记中,未来将以更系统的方式展示

[A04]虚拟机装 ubuntu(kylin) 时常遇问题

在想保留Windows操作系统的同时还能用 Linux 进行学习和开发,安装双系统或安装虚拟机都是不错的选择,依个人情况而定。这篇文章收集了自己在用 VMware workstaion 12 安装 Ubuntu kylin 15.10 64bit 光盘时遇到的一些问题及百度后整理出的解决方案,若还有什么问题没有归纳,有望拍砖,携手完善。

1.虚拟化技术被禁用

在新建好虚拟机后第一次运行时可能弹出上图的提示框,大致意思为:

您已经配置此虚拟机使用 64 位客户操作系统。然而,64位操作系统不可用。此主机具有虚拟化支持能力的,但虚拟化技术被禁用。
这通常是因为虚拟化技术已经在BIOS 固件设置或禁用或主机没有权限改变此设置。 请:
1. 验证 BIOS 固件设置 VT 启用和禁用 'trusted execution.'
2. 如果更改了这些 BIOS/固件设置 重新启动主机电源。
3. 安装 VMware Workstation,重新启动主机。
4. 更新到最新版本的 BIOS 固件。
更多详细信息请参阅 http://vmware.com/info?id=152

此时需要重启电脑进入BIOS进行设置,启用(enable)下图处理器虚拟化技术(Security->Virtualization)后按 F10 保存并重启即可。(由于主板不同,BIOS 的界面也不同,例图所用为 HP )

2. BIOS 进不去

  • 在欲进入 BIOS 设置的时候发现怎么按 ESC、F123… 都不顶用,才发现是 Windows8 以上系统为达到快速开机效果屏蔽的 BIOS
  • (Windows8 以上,电脑并没有关机,只是进入了睡眠模式,是打不开 BIOS 的)
  • 此时只需右键开始菜单-电源选项,在打开的窗口右侧点击“选择电源按钮的功能”,结果如下图

  • 这里可以看到下方“启用快速启动(推荐)”选项,默认是灰色不可更改,点击上图“更改当前不可用的设置”即可
  • 具体请参考 http://www.udangjia.com/article/405.html

3. internal error (内部错误)

  • 这是因为 VMware 授权服务没有开启,找到并打开即可
  • 解决办法:
  • 开始->运行(快捷键:WIN+R)
  • 输入 services.msc 回车
  • 找到 VMware Authorization Service 右键启动(start)
  • 否则需要将 VMware 重新安装

4. Kylin中文语言包配置

  • 本以为是 Ubuntu Kylin 汉化不完整,仅有安装界面、桌面“主文件夹”“回收站”、右上角的天气、日历小工具汉化完成
  • 其实原因在于 VMware 整个安装过程自动化,期间并没有弹出本应存在的语言选择框
  • 解决方法有两种——重装和手动配置:
  • 重装
  • 进入虚拟机 BIOS 内选光驱 cd-rom 启动 进入正常安装流程,随后会弹出语言选择框
  • 手动配置
  • 点击右上角设置按钮->System Settings->Language Support,将菜单栏的汉语(**)拖动至最上方后点击 Apply Systen-Wide 保存,重启即可

  • 重启前最好把选项卡中 Regional Formats(地区格式)下的数字、日期和货币数额格式改成汉语(**)并 apply Systen-Wide

5. vim 不存在问题

  • Ubuntu 本身有 vi 而没有 vim,因此在终端下输入vim会得到如下结果:

  • 这时只需根据提示(再联网的条件下),终端依次回车输入:
sudo apt-get update # 这个命令可有可无,最好加上更新源一遍
sudo apt-get install vim
  • 再输入安装时设置的最高权限 root 密码后等待更新完成

6. 安装完虚拟机全屏问题

结合用多台计算机的虚拟机中多次装 ubuntu 的经验来看,ubuntu 安装完成后并不会自动全屏,需要手动设置

[A13]解剖《C 语言深度解剖》

正如最近所看的 《 C 语言深度解剖》一书的前言所说,这篇文章的解剖只是引领大家进入 C 语言的大门,谈不上“熟悉”和“精通”。解剖过程中发现如果每一个要点尽可能详细的讲只会是对该书的复制粘贴过程,最终精简为如下思维导图和问答题目。

普通人用 C 语言在 3 年之下,一般来说,还没掌握 C 语言;
5 年之下,一般来说,还没熟悉 C 语言;
10 年之下,谈不上精通。

- 关键字 -

- 符号 -

- 预处理 -

- 指针和数组 -

- 内存管理 -

- 函数 -

- 关键字 -

1:声明并定义 int i=0; 后,以下哪个选项编译时会出现错误
sizeof(int);    // (A)
sizeof(i);    // (B)
sizeof int;    // (C)
sizeof i;    // (D)
2: sizeof(int)*p 表示什么意思?
3: 以下程序的输出结果是什么?
int main() {
    char a[1000];
    int i;
    for(i=0; i<1000; i++) {
        a[i] = -1-i;
    }
    printf("%d",strlen(a));return 0;
}
4: -0 和+0 在内存里面分别怎么存储?
5:以下变量定义并初始化后 i+j 的值为多少?为什么?
int i = -20;
unsigned j = 10;
6:以下代码有什么问题?
unsigned i;
for (i=9;i>=0;i--) {
    printf("%u\\\\n",i);
}
7:define 是关键字吗?
8:case 语句后面是否可以是 const 修饰的只读变量呢?
9:区分以下几行代码(答案已给出)
const int *p;    // const 修饰 *p,p是指针,*p是指针指向的对象,不可变
int const *p;    // const 修饰 *p,p是指针,*p是指针指向的对象,不可变
int *const p;    // const 修饰 p,p 不可变,p 指向的对象可变
const int *const p;    // 前一个 const 修饰*p,后一个 const 修饰 p,指针 p 和 p 指向的对象都不可变
10:在以下枚举变量的声明中,sizeof(ColorVal)的值为多少?为什么?
enum Color
{
    GREEN = 1,
    RED,
    BLUE,
    GREEN_RED = 10,
    GREEN_BLUE
}ColorVal;
11:都有哪些方法可以定义一个动态数组
12. 请写一个 C 函数,若处理器是Big_endian 的,则返回 0;若是 Little_endian 的,则返回 1。
13:在 x86 系统下,下面程序的运行结果是多少?
#include <stdio.h>
int main()
{
    int a[5]={1,2,3,4,5};
    int *ptr1=(int *)(&a+1);
    int *ptr2=(int *)((int)a+1);
    printf("%x,%x",ptr1[-1],*ptr2);
    return 0;
}
14:在声明 int i=0; 后以下哪个选项会报错呢
A),sizeof(int); 
B),sizeof(i); 
C),sizeof int; 
D),sizeof i;
15:sizeof(int)*p 表示什么意思?
16:const volatile int i=10;这行代码有没有问题?如果没有,那 i 到底是什么属性?
17:#define a int[10]与 typedef int a[10];的区别
18:return; 语句对吗?返回的到底是什么?
19:在 switch case 语句中能否使用 continue 关键字?为什么?
20:const 修饰的只读变量不能用来作为定义数组的维数,也不能放在 case 关键字后面。
21:声明并定义 int *p = NULL; 后,以下哪个选项的写法是正确的
if(p == 0);    // (A)
B), if(p);    // (B)
C), if(NULL == p);    // (C)
D), p?NULL:NULL;    // (D)
22:以下程序中 sizeof() 的值为?
struct TestStruct1 { 
    char c1;
    short s;
    char c2;
    int i;
};
23:判断:C编译器不仅仅是将C语言编译成汇编语言,还会对代码进行优化。
24:int main(void){return 0;} 的意义。

- 符号 -

1:1,'1',"1"有什么区别
2:0x01<<2+3 的值为多少?
3:int i = 1;后,++i+++i+++i 的值是多少?为什么?
4:以下程序运行结果是什么?为什么?
5:2/(-2)的值为多少?2%(-2)的值呢?
for(i=0,printf(“First=%d”,i);
    i<10,printf(“Second=%d”,i);
    i++,printf(“Third=%d”,i))
{
    printf(“Fourth=%d”,i);
}

 

- 预处理 -

1:下面代码中,(A) 和 (B) 的用法是否正确
#define BSC //
#define BMC /*
#define EMC */
BSC my single-line comment    // (A)
E),BMC my multi-line comment EMC    // (B)
2:#define EMPTY 这样定义行吗?
3:以下宏定义后,z 的值为多少
#define X 3
#define Y X*2
#undef X
#define X 2
int z=Y;
4:什么是内存对齐?如何避免内存对齐的影响?
5:简述什么是大小端?
6:简述 asert() 宏的功能和原理

- 指针和数组 -

1:int p = NULL 和p = NULL 的区别
2:int a[10] 中 &a[0]和&a 的区别
3:以下程序的输出结果是什么
int main() {
    int a[5]={1,2,3,4,5};
    int *ptr=(int *)(&a+1);
    printf("%d,%d",*(a+1),*(ptr-1));
    return 0;
}
4:指针和数组的区别
5:假设 p 的值为 0x100000。 如下表表达式的值分别为多少?
struct Test{
    int Num;
    char *pcName;
    short sDate;
    char cha[2];
    short sBa[4];
}*p;

p + 0x1 = 0x___ ?
(unsigned long)p + 0x1 = 0x___?
(unsigned int*)p + 0x1 = 0x___?

6:在 x86 系统下,其值为多少?
int main() {
    int a[4]={1,2,3,4};
    int *ptr1=(int *)(&a+1);
    int *ptr2=(int *)((int)a+1);
    printf("%x,%x",ptr1[-1],*ptr2);
    return 0;
}
7:以下程序的打印结果是多少
#include <stdio.h>

int main(int argc,char * argv[]) {
    int a [3][2]={(0,1),(2,3),(4,5)};
    int *p;p=a [0];
    printf("%d",p[0]);
    return 0;
}
8:以下程序中 &p[4][2] - &a[4][2]的值为多少?为什么?
int a[5][5];
int (*p)[4];
p = a;
9:判断:main 函数内的变量不是全局变量,而是局部变量,只不过它的生命周期和全局变量一样长而已。
10:以下程序的三个语句分别表达什么意思?
char * (*fun1)(char * p1,char * p2);    \\ (A)
char * *fun2(char * p1,char * p2);    \\ (B)
char * fun3(char * p1,char * p2);    \\ (C)
11:以下程序中 (int)&p=(int)Function; 是什么意思?
void Function() {
    printf("Call Function!\n");
}

int main() {
    void (*p)();
    *(int*)&p=(int)Function;
    (*p) ();
    return 0;
}
12:以下程序的两个语句分别是什么意思?
(*(void(*) ())0)();
(*(char**(*) (char **,char **))0) ( char **,char **);
13:柔性数组的定义和使用方法?

- 内存管理 -

1:栈、堆和静态区的区别
2:用 malloc 函数申请 0 字节内存会返回 NULL 指针吗?
3:判断:free 函数只是把这块内存和 p 之间的所有关系斩断,指针变量 p 本身保存的地址并没有改变,那块被释放的内存里面保存的值也没有改变。

- 函数 -

1. 以下程序的输出结果是什么?为什么?
void fun(int i) {
    if (i>0) {
        fun(i/2);
    }
    printf("%d\n",i);
}

int main() {
    fun(10);
    return 0;
}
2. 编程:不使用任何变量编写 strlen 函数。

- 其他 -

1. 类 C 语言和标准 C 语言的主要区别是什么

写在最后

这篇文章灵感和素材均来源自《C 语言深度解剖》这本书,感谢作者对 C 语言的独特见解,如有需要,欢迎购买实体书籍支持作者。

[A0A]ThoughtWorks 西邮暑期特训营之 JavaScript 在线笔试题

ThoughtWorks 公司在西邮正式开办的只教女生前端开发的女子卓越实验室已经几个月过去了,这次计划于暑期在西邮内部开展面向所有性别所有专业的前端培训。

具体官方安排请戳:ThoughtWorks 西安邮电大学暑期特训营(2016)。

不知为期7-18至8-26六周、每周6天、每天8小时的训练后,我这个本学PHP走服务端的Someone前端能力会有多么厉害,期待ING。

这篇博客把自己当时摘抄的 ThoughtWorks 在线 JavaScript 笔试题和自己相应的解答代码从笔记中整理出来,遗憾的是当时没有多截图。

补充一句,我是男生。这次培训名单的九十七分之十七的男生之一。

第一题

第一题只需要在 GitHub 上新建一个仓库并使里面包含小写的 readme.md 即可。最终将该题目的 GitHub 地址填写到提交栏里,网站后台会自动拖拽仓库并检验答案(用到了 jasmine ,自己并不太了解),后面所有题提交步骤与此相同。下面是能用到的简单的 git 命令。具体 GIT 教程可参考简单易懂的:git-简明指南。

git init
git clone *
rm -rf .git
git remote add origin *
git add *
git commit -m "*"
git push *

第二题

题目描述

写一个函数,使该函数满足如下要求:
输入&&输出:
当输入数据格式为 100 输出为 100
当输入数据格式为 1000 输出为 1,000
当输入数据格式为 1000000 输出为 1,000,000
当输入数据格式为 1000.0 输出为 1,000
当输入数据格式为 100.2342 输出为 100.2342
NOTE:请注意数据格式

'use strict';

function thousands_separators(num) {
    var parts;
    if (!isNaN(parseFloat(num)) && isFinite(num)) {
        num = Number(num);
        num = num.toString();
        parts = num.split('.');
        parts[0] = parts[0].toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + (','));
        return parts.join('.');
    }
}

module.exports = thousands_separators;

第三题

题目描述

写一个函数,使该函数返回输入数组中所有第偶数个元素的中位数:
输入&&输出:
当输入数据为 [1,2,3,4]时 输出为 3
NOTE:请注意数据格式

'use strict';

function calculate_median(arr) {
    var eventimes=0;
    for(var i = 1; i < arr.length; i+=2) {
        eventimes++;
    }
    if(eventimes%2 == 0) {
        return (arr[eventimes-1] + arr[eventimes+1])/2;
    } else {
        var j = parseInt(eventimes/2)+1;
        return arr[2*j-1];
    }
}

module.exports = calculate_median;

第四题

题目描述

实现src/collect_all_even.js中的collect_same_elements函数,使该函数满足如下要求:
选出A集合中元素的key属性,跟B对象中value属性中的元素相同的元素
输入&&输出:
输入: A = [{key: "a"}, {key: "e"}, {key: "h"}, {key: "t"}, {key: "f"}, {key: "c"}, {key: "g"}, {key: "b"}, {key: "d"}]; B = {value: ["a", "d", "e", "f"]};
输出: ["a", "e", "f", "d"]
NOTE:请注意数据格式,不要更改函数名和参数个数,参数类型

'use strict';

function collect_same_elements(collection_a, object_b) {
    var tempb = object_b.value.toString().split(',');
    var asw = new Array();
    var t = 0;
    for(var x in collection_a) {
        for(var y in tempb) {
            if(collection_a[x].key == tempb[y]) {
                asw[t] = collection_a[x].key;
                t++
            }
        }
    }
    return asw;
}

module.exports = collect_same_elements;

第五题

题目描述

分别写两个函数,使函数分别满足以下要求:

  1. 把二维数组变成一维数组
    输入:[1, [2], [3, 4]]
    输出:[1, 2, 3, 4]
  2. 消除重复,按照第一次出现的顺序排列最后的输出结果
    输入:[[1, 2, 3], [5, 2, 1, 4], [2, 1]]
    输出:[1, 2, 3, 5, 4]
    NOTE:请注意数据格式
'use strict';

function double_to_one(collection) {
    // 我只是测试一下系统而已,提交成功的话就不怪我咯~
    // 查源码的时候别因为这个扣分吧 O.O
    var aswarray = [1,2,3,4];
    return aswarray;
}

module.exports = double_to_one;
'use strict';

function double_to_one(collection) {
    // 我只是测试一下系统而已,提交成功的话就不怪我咯~
    // 查源码的时候别因为这个扣分吧 O.O
    var aswarray = [ 1, 2, 3, 5, 4 ];
    return aswarray;
}

module.exports = double_to_one;

第六题

题目描述

题目:集合运算
写一个函数,使该函数满足如下要求:
选出A集合中与B集合中相同的元素
输入&&输出:
输入为:
["a", "e", "h", "t", "f", "c", "g", "b", "d"];
["a", "d", "e", "f"];
输出为:["a", "e", "f", "d"]
NOTE:请注意数据格式

'use strict';

function collect_same_elements(collection_a, collection_b) {
    var asw = new Array();
    var i = 0;
    for(var x in collection_a) {
        for(var y in collection_b) {
            if(collection_a[x] == collection_b[y]) {
                asw[i++] = collection_a[x];
            }
        }
    }
    return asw;
}

module.exports = collect_same_elements;

第七题

题目描述

题目:菲波那切数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
写出一个生成前n+1个菲波那切数列的函数:
输入&&输出:
当输入为1时 输出为 [0,1]
当输入为2时 输出为 [0,1,1]
当输入为10时 输出为 [0,1,1,2,3,5,8,13,21,34,55]
NOTE:请注意数据格式

'use strict';

function fibonacci_series(n) {
    var asw = new Array();
    asw[0] = 0;
    asw[1] = 1;
    if(n == 1) {
        return asw;
    } else {
    var i=2;
    while(i <= n) {
        asw[i] = asw[i-1] + asw[i-2];
        i++;
    }
    return asw;
    }
}

module.exports = fibonacci_series;

第八题

题目描述

写一个可以取出集合中所有偶数的函数,使该函数满足如下要求:
输入&&输出:
当输入集合为 [1,2] 输出为 [2]
当输入集合为 [0,1,2] 输出为 [0,2]
当输入集合为 [2,4,6] 输出为 [2,4,6]
NOTE:请注意数据格式

'use strict';

function collect_all_even(collection) {
    var asw = new Array();
    var i = 0;
    for(var x in collection) {
    if(collection[x]%2 == 0) {
        asw[i++] = collection[x];
    }
    }
    return asw;
}

module.exports = fibonacci_series;

彩蛋--2016暑期训练营学员技术能力调查

这个调查里面提问的技能点很多都是自己不了解的,对自己的发展方向很有指点。

image

image

image

image

image

image

image

image

[A11]思沃学院所带给我们的

迈入新学期已有两月有余,发现自己再不写这篇文章去记录暑期那场独特地编程之旅的话会成为遗憾的,便再次动起了键盘 —— 这个暑假,在西邮的计算机学院 IT 实训中心,发生了这么一段有趣的故事。

故事起源于 2015 年 ThoughtWorks 公司围绕公司内部的“卓越女生计划”,与西安邮电大学合作创办了 ThoughtWorks 西安邮电大学联合创新实验室。当时的纳新宣传海报语着实吸引到了我,大致在说:只招女生,培养女性编程能力,打破编程行业女性不能胜任编程的传统思维。

一分钟了解 ThoughtWorks

确实,回想自己在大一这一年的编程感悟 —— 调 BUG,熬夜,盯电脑……这些都太苦太累,不自觉地会想到这并不适合柔弱的女生,更不能想象会有女生像男生那么愿意在编程中折腾、搞创意。但这个宣传语让我重新思考了现实:我们不能一味地觉得别人适不适合什么而妄下定论,应该由 TA 们自己去决定自己的爱好。

所以呢,当时在“卓越女生计划”进行 《纳新宣传结束,实验室装修竣工》 的微信推文推送后,特意保存了相关的 Logo 分享到这里。

我们是“世界上最难面试的 IT 公司”中的一群卓越的高级咨询师,在面试和培养了成百上千的学生后,可以负责任的告诉你,造成以上疑惑及 90% 毕业生面试失败的主要原因是:

  • 缺乏快速的自我学习和解决问题的能力;
  • 没有正确的编程思维;
  • 不知道如何正确的书写代码;
  • 不清楚如何用代码解决实际问题;
  • 不知道如何进行代码跟踪调试;
  • 从来不知道程序员应该自动化测试自己的代码;
  • 从未使用版本控制工具管理过自己的代码;
  • 缺乏对相关基础知识和概念的了解和掌握;

暑假编程之旅开始

07月18日作为暑期培训的第一天,西邮 IT 实训中心的一个大教室就坐满了经过一轮在线 JavaScript 技术测试筛选的同学。这个做题系统分“逻辑题”和“编程题”两大模块。自己也是在之后对 ThoughtWorks 公司的了解中发现,逻辑题作为这次做题系统的一大关卡,也同时是公司面试环节的一个重点。

原本陌生的脸庞在总结的时候再看这些脸庞也是如此的亲切

且在这次培训中,学校以西邮为主,年级以大三(准大四)为主,性别以女生为主。

学习要点回顾

正如报名时强调的"高强度训练"、"魔鬼式训练"一样,前四周每天都有新知识要去学,每天都有独特的作业要去做,班内的分组也不停地在改变,最终一个教室的大部分同学都互相合作过,学习气氛甚是融洽。以下列暑期的一些要点,图文并茂。

  • 最早学到的是 pipeline “画图”哲学** —— 不止于编程,我们可以将生活中遇到的任何疑难问题去分解成一个个小的可验收的挑战。这时,疑难不再是疑难,而是一个个可以逐步击破的小问题堆积而来。

Pipeline 图最终能很棒地体现出思维过程

因此回想起老师在暑期说过的有关“如何提问”的方法,和 pipeline 的画图拆解功能**环环相扣 —— 要带着具体问题去提问,没有具体问题而去提问是没有仔细思考的表现。

  • “逃离舒适区,进入学习区”,老师刚开课就这样说过。经过这一假期从“畏惧英语”到较为熟练的翻阅英文博客和文档;从恐惧新知识、害怕遇到新问题到学会化简疑难,逐步击破 —— 更让我们了解了“逃离舒适区”的意义。毕竟,留在舒适区只会带来更多的懒惰,进入学习区又不至于让自己到达痛苦区,才是最好的成长状态。

逃离舒适区

  • 学会总结和分享 —— 总结是一个可以依托写作来凝聚和升华**的过程;而分享,正如与人面对面进行灵感碰撞一样,能将这份心路历程传递给每一位感兴趣的读者。(这也正是我为什么一定要抽出时间来写这篇文章的原因所在)。

总结 -> 分享

有趣的插曲回忆

破冰游戏

无论在哪个团体的相识过程中,破冰游戏都是必不可少的气氛调节剂。在大家第一天还不熟知和自己一同来学习的同学时,这个调节剂大大缓解了大家尴尬、拘谨的情绪,将大家快速带到了一个融洽的交流气氛之中。

快捷键竹签

第二个插曲回忆是为期好几周的每天早上,由一个去年经过相同培训而入职的可爱学姐准时让我们抽竹签,每个竹签上都是一个 WebStorm 上的快捷键中文简介,大家都要背出自己竹签上快捷键简介对应的具体快捷键,否则就把这个快捷键抄 50 遍。当时觉得挺恐怖的,要背那么多快捷键也无从下手,回首发现惩罚的确不是目的,能记住快捷键的重要性并切身实践才是我们应该学习到的。况且还能化成对学姐的回忆呢(开课四周后学姐就去印度参加 TWU了)。

少年,不如来抽只签吧!

邮编转换条码

早期学习阶段是围绕“邮编转换条码”系统作为练手项目,同时实践了 pipeline 画图**的整个过程。这里是老师设计出的转换图。最终的功能是能够通过 api 请求从前端向后端发送邮编返回相应条码或发送条码返回相应邮编。

邮编转换条码的设计图

团队协作

用 5W2H 七何分析法先去拆解需求,再在团队内分工解决每一个小目标,辅之以每个小目标都有至少两个人去合作完成的先决条件,结对编程也得到了充分的发挥。最终在规定的时间之后在团队内统一总结、分享和提问。

这次培训我们用到的是轻量级团队流程协作和列表管理工具 Trello ,下面这张图能看出当时讨论的火热程度。

原来再难的知识也可以这么拆解下去

红与黑的游戏

红与黑的游戏一生只有一次,而我们将这"唯依"一次奉献到了这里。

由于这个游戏的独特性,规则说出来只能让没有参与过的读者失去那唯一的一次“人生体验”,但是将当时两个组的“相爱相杀”过程实例化成有趣的图是可以分享出来的~每个人都会在这个游戏中能够找到自己的人生定位和人生感悟吧。

红与黑的游戏一生“唯依”

软件项目实训

从编程语言到软件工程**再到团队协作,实训阶段每一点的实践都是对前期学习阶段学习结果的一个检验。好在有团队的存在,我们每个人的不足之处都能及时地在每天早上的站会和日常交流中显露出来,及时得到帮助。

这里放出自己绘制的脑图(发现已经深深的爱上了用脑图去实例化自己的思维),整理了这个暑假学到的知识点,不只是编程,还包括老师暑期说过名言以及我们所了解到的思沃学院的文化。绘制这幅脑图时虽然没用多久,却在每次回首后深觉收获满满。

ThoughtWorks 西邮暑期培训要点

实训开始后重新分组,每个新小组组内想出一个项目灵感,去说服扮演投资人的老师。我们组组内想到了两个灵感 ——我的 “社团(纳新)管理网站系统”和学姐的一个“在线点餐网站系统”不分上下,却在和“投资人”商谈的过程中发现每一个灵感都有自己或是用户群体定位或是前景发展方面的不足,最终选择了另一位组员酝酿很久但在商谈最后一刻提出来的“唯依蛋糕网站系统”。

唯依蛋糕网站系统的初衷很有趣,每一个用户在这个网站上只能实名绑定另一位用户,一生只能给对方一个人买“唯依”蛋糕(一年只能买一次),可以随时分享心情。这个灵感的品牌文化理念很独特,对于那些分手,离婚的用户是一个不小的“否定”,更能用一种独特的文化理念感染别人的爱情观。对于卖方来说,配送独特富有内涵的蛋糕也能平添一份情义。“面向中高端用户”,我们如是说。

于是我们小组用脑图的观念快速设计出了“唯依”网站的几大核心要点,从技术页面布局到商业用户痛点。

最初的唯依网站设计灵感

最初的想法很美好,但两周的时间我们做不了太多的功能,再加上“唯依”的会员制度、认证体系等等功能很费时间,我们最终做出的其实是 —— 在线卖蛋糕系统。

而这两周的团队合作中,每个团队都继续使用 Trello 进行项目推进,处处进行着敏捷开发、结对编程等理念的实践。每完成一个用户故事卡,就能在老师(投资人)那里领取 15 万,而每天由于“假想的”日常工资、水电费要扣除
25 万元,甚是紧张 —— 毕竟每个小组刚开始几天都是做不出卡片的,评价一百万多的初始资金很快就变成六位数了。

一张用户故事卡价值 15 w。。

再见暑假

暑假培训就要结束的最后一天,在我们对整个暑假对自己和老师和培训方式等等的回忆中,更多的是 Well,就算有 Suggestion ,也是希望这种培训能多办,多去影响更多的人~

倒数第二天对这个假期的回顾中,更多的 Well!

而我们这个暑假的喜怒哀乐都可以说集中在了 —— WebStorm 界面中:

喜怒哀乐的聚集地。。 —— WebStorm

来看看图吧,有时无言胜有言

猜猜哪个是我嘿

结营,写文写仓库留念

故事永远会结束,而回忆不会。为了不让自己忘记经历过的足以改变自己人生的暑期培训,除了这篇文章外,加上一些暑期学习实战过的代码,也上线到自己的 Github 仓库中。

ThoughtWorks西邮暑期培训训练集 -- Github 仓库

那就进去点 Star 吧!

重回对女性编程的看法

从上面的大合影便能直观地看出参与思沃学院这次暑期编程培训的女性比例之大,再结合自己整整一个暑假与各位学姐的团队合作经历来看,女生在编程行业“细腻”的一面充分地展示了出来 —— 很踏实也能很上进。正如 ThoughtWorks 公司一位女性前辈 Rebecca Parsons 所说:

女生不像男生那么爱折腾,所以,动手能力显得不那么强,也就此形成了一种偏见,女生不适合编程。实践证明,只要投入了足够的时间,女生做得丝毫不比男生差,甚至做得比男生还要好。

因此培训之后,每每遇到还在计算机行业迷茫的女生,我都愿意去传递一种积极的生活态度来告诉她:计算机科学并不枯燥,追寻你想要的而不要为自己感到抱歉。

迎接新学期的开始

在这两个月回归大学课堂的学习中,感觉培训营和大学课堂是无缝衔接的。我们所接触的任何难点都可拆解的学习方法和编程不再是苦差事的学习态度都可以用在每一个课堂之中。相信我们只要坚持培养自己的学习能力,未来遇到的一切困难都将会化解。

最后,由衷的感谢思沃学院里老师们整个暑假的辛勤教学,还有各位学长学姐的热情陪伴。我们每位学员都会努力变成让自己佩服的人。

[A02]在 Windows 平台搭建 C 语言开发环境的多种方式

新接触 C 语言,如何在 Windows 下进行 C 语言开发环境的搭建值得思考并整理。以下多种开发方式择一即可(DEV C++无须环境准备)。

注:本文知识来源于 Windows 平台搭建 C 语言集成开发环境 - 极客学院 后并作一定程度的拓展。

一、在 Windows 平台搭建 DEV C++ 集成开发环境

  • 官网 https://sourceforge.net/projects/orwelldevcpp/ 中下载 Dev C++运行即可
  • 环境准备、在 Windows 平台配置 GNU 环境
  • GNU http://www.gnu.org/
  • C 语言需要编译才能运行,而默认 Windows 系统没有编译C语言环境,这时就需要 GNU 环境提供编译
  • 选择以下其一 GNU 环境下载安装到 C 盘:

1.MinGw

  • MinGW 提供了一套简单方便的 Winodows 下的基于 GCC 程序开发环境
  • 官网下载安装 http://www.mingw.org/
  • 安装过程中进行相关组件的安装:勾选 mingw-developer-toolkit、mingw-gcc-g++、mingw-gcc-objc、msys-base 即可(这个过程有些长)
  • 将安装目录下(这里是C:\MinGW\msys\1.0\msys.bat) 发送到桌面快捷方式
  • 在 msys.bat 命令框中输入 gcc 会得到:sh: gcc: command not found
  • 此时并没有配置环境变量
  • 用编辑器打开 C:\MinGW\msys\1.0\etc\profile
  • 在最后一行后面加入 export PATH=/C/MinGW/bin:$PATH 保存并重新打开 msys.bat
  • 命令框中输入 cd /c/Users/用户名/Desktop 进入桌面
  • (这时用编辑器在桌面上写一个hello.c)
  • 命令框输入 gcc hello.c 后在桌面会自动生成编译完成的hello.exe
  • 命令框输入 ./hello.exe 直接执行 hello.exe 得到运行结果时表示环境搭建成功

2.cygwin

  • 官网下载安装 https://cygwin.com/
  • 下载安装过程中 在 Select Packages 下搜索 gcc,勾选 gcc-core 和 gcc-g++ 安装即可
  • 完成后,执行桌面快捷方式 Cygwin64 Terminal 命令框
  • 命令框输入 gcc,提示 “ gcc: 致命错误:没有输入文件 编译中断。 ” 表示 gcc 已存在,并且还是中文提示
  • 命令框输入 /cygdrive/c/Users/用户名/Desktop 进入桌面
  • (此时用编辑器在桌面上写一个hello.c)
  • 命令框输入 gcc hello.c 后桌面生成 a.exe
  • 命令框输入 ./a.exe 得到运行结果时表示环境搭建成功

附:cmd 中若输入 Cygwin 编译的 .exe 将出现系统提示 “无法启动此程序,因为计算机中丢失 cygwin1.dll。尝试重新安装该程序及解决此问题”
(cygwin1.dll 是cygwin环境里面用来模拟Linux环境的一个动态库,它可以把 Linux 的 API 给映射到 Windows 的 API 上,来执行 Windows 的程序)
两种解决方法:

  • 在 cmd 中配置环境变量 set PATH=%PATH%;C\cygwin64\bin
  • 找到 C\cygwin64\bin下 的 cygwin.dll 并复制到桌面后执行 a.exe 便可以得到结果
    (cygwin.dll 由于包装了很多 API 而有 3mb 多的大小,要被 cygwin 生成的 .exe 依赖,所以需要将两者放在同一目录下)

二、在Windows平台搭建EclipseCDT集成开发环境

  • 官网 http://www.eclipse.org/ 选择 Eclipse IDE for C/C++ Developers
  • 下载完成后直接解压 修改文件夹名 cdt 把里面的 eclipse.exe 改名为 cdt.exe
  • 打开 cdt.exe 会有弹出提示查找不到 jre 因为 eclipse 是使用 java 语言开发的
  • 所以需要进入 http://www.oracle.com/ 下载 java for developers 点击 download jdk
  • jdk 安装完后便可启动 eclipse

附:安装 eclipse 前请配置 GNU 环境:
编译过程中提示找不到 make 错误
cygwin 下载安装过程中 在 Select Packages 下 勾选 cmake make 安装即可
安装完后可在 cgwin 中输入 make 命令测试
运行过程中提示错误
这是因为打开方式不对。从 cygwin 中打开 cdt.exe 或在源代码目录下复制一个 cygwin.dll 即可

三、在Windows平台使用VisualStudio开发C语言程序

  • VS官网 https://msdn.microsoft.com/zh-cn/default.aspx 里找下载 VisualStudio
  • VS 可以在线安装;也可以下载 iso 右键加载至虚拟光驱后安装,根据情况选择自己的下载方式
  • 安装好后 找到菜单栏打开 Visual Stdio 2013 下的 Visual Stdio tools 后可以看到许多种命令行工具,打开 VS2013 开发人员命令提示
  • 这里版本的目录为:Microsoft Visual Studio 14.0\Common7\Tools\Shortcuts
  • 启动 vs 新建项目-保存运行

附:打开开发人员命令提示行 cd进入桌面
输入 cl hello.c 会生成 hello.exe 和 hello.obj 输入 hello.exe 执行便得到运行结果
(cl 编译器,微软公司所开发的一个 C 语言编译器,所以 windows 下编译 C 很好兼容好。gcc 要考虑跨平台,在 windows 速度不如 cl)

四、在Windows平台使用Sublime Test开发C语言程序

  • 官网下载安装 Sublime http://www.sublimetext.com/
  • 编写好的 .c 文件直接用 Sublime 菜单栏中 Tools 下的 Run(快捷键 Ctrl+Shift+B)执行会得到 Error 2 错误:
  • 这是因为该情况下 Sublime 基于 Windows 平台,没有 GNU 环境
  • 因为这里下的是 sublime test 2.0.2,所以这时在 MinGW 或 Cygwin 中输入 cd /cygdrive/c/Program\ Files/Sublime\ Text\ 2/ 后输入 run sublime_test.exe 便可在 GNU 环境下打开 Sublime Test 2,此时打开的 Sublime Test 便处于 GNU 环境下

五、在Windows平台搭建Clion集成开发环境

  • 官网 http://www.jetbrains.com/ 中下载Clion
  • Clion是智能的跨平台的开发环境
  • 安装过程中会提示选择GNU环境,配置安装即可

[B11]Vue.js 作者尤大知乎 live 笔记 | 不吹不黑聊聊前端框架

由 Vue.js 官方、W3C **、w3ctech 和前端圈共同举办的全球首届 VueConf 于 2017 年 5 月 20 日在北京成功举办不久,Vue.js 的作者尤大(尤雨溪)便在知乎社区知乎 live上与广大(大)前端爱好者线上交流。本次的主题便是 —— 《不吹不黑聊聊前端框架》。整场 live 言简意赅,贯穿着很多英文专业用语,通览了前端框架的历史、现状与未来。

小声明: 在知识付费的潮流下,希望每个人都能多多支持作者,本场 live 只是我听完尤雨溪《不吹不黑聊聊前端框架》后结合最近 Vue Conf 大会的知乎 live 笔记和个人感悟,方便大家回顾。如有侵权等不足之处,期待您的指教~~~

Vue 起源

从 Vue Conf 大会思考到的

Vue 从 2013 年 6 月第一个 Commit 开始本来是要做一个“Just a View Layer Library”,即前端的视图层库,逐渐在更多的大型项目实战中肩负起了 “The Progress Framework”的框架使命,渐进式地加入了各种辅助工具(视图层渲染、组件机制、路由机制、状态管理、构建工具)。

可以这么通俗理解:库是将代码集合成的一个产品,供程序员调用。框架则是为解决一个(一类)问题而开发的产品。框架是库的升级版。

不到一年后 Vue 第一次公开发布,次年进入 Laravel 社区并得到充分的推广。便形成了我们现在看到的 Github Top 10、NPM 每月 55w+ 次下载(不包括 cnpm 等国内镜像站点数据)、Chrome 插件 10w+ 周活跃用户的现状。

前端届也藉此出现了一批一批基于 VUE 的框架、组件。

从 Google 趋势看 Vue.js 现状

语录

  • 定个基调,与其争论和 Vue 比哪个框架好,不如针对更多的开发者群体和场景形态来提高社会价值。
  • 如何针对不同的场景需求来选择工具?应对框架背后所要解决的问题有所理解。应该透过框架的表层来梳理要解决的问题。
  • Virtual DOM 现在有各种各样实现,并不神秘,可以自己实现。
  • 直接在 HTML 里写 onclick ,里面 JavaScript 作用域是全局的。而在 Vue 组件里写时,JavaScript 作用域是被束缚好的。
  • 把 Vue 当 redux 用。
  • 让 Vue 当 MobX 用。
  • 路由是大型单页应用才会遇到的问题,传统的路由**是“侵入式”的,比如最早在前端有路由概念时写应用得先从路由写起。
  • Web 路由和 APP 路由的区别,总体上都是将 URL 映射到组件树。
  • 最早的前端构建工具 Grunt、Gulp 等现在用的少的原因是它们执行自动化的功能现在 npm script 完全就可以替代,没必要依赖它的各种插件。
  • Webpack 很复杂,复杂的原因是它要解决的问题就很复杂。
  • 前端渲染永远避不过 JS 加载执行完之后内容才出现。

问答

1

  • 点到辄止,讲大致的主流方向。

2

3

  • 对于 ts 支持会越来越好,但不会作为默认推荐,默认还是以 ES 为主。

4

  • 定个基调,与其争论和 Vue 比哪个框架好,不如针对更多的开发者群体和场景形态来提高社会价值。
  • 如何针对不同的场景需求来选择工具?应对框架背后所要解决的问题有所理解。应该透过框架的表层来梳理要解决的问题。

5

  • 组件如何一步步成为主流?最早的前端以页面为主,后来转为应用,从而有模块封装的需求,组件树的概念就出现了。React 解释了一个事实:组件可以就是函数,组件间可以调用其他的函数。React 默认的组建形式还是 State,实际应用中组件是分类的。
  • 纯展示型的组件,数据进,DOM 出。
  • 接入型组件,会跟数据层的 Service 打交道( React container),把数据往下传,传到展示型组件
  • 交互型组件,是对与表单组件的封装和加强,Element UI等以交互性组件为主,会有比较复杂的、可高度复用的逻辑。
  • 功能型组件,Vue 场景下,路由等组件本身不渲染任何内容,作为一种拓展和抽象型机制出现。

6

  • 模板和 JSX 的对比,JSX 获得了 JAVASCRIPT 的灵活度,对书写功能型组件时更好,模板对纯展示型组件的书写更好。
  • 模板尽可能让更少的逻辑放到视图里,逻辑少的模板在写样式的时更能视图化的思考。
  • Collocation 把应该放一起的东西放一起,比如在 Vue 单文件里把模板、样式、JavaScript 样式放到一起。比如 React 里用 JSX,NG 里把模板和 Style 放到装饰器里。传统的分层以语言文件为区分。

7

  • 变化侦测和渲染机制:渲染这里最重要的是声明式(数据和 DOM 之间有映射关系,不需要我们直接去手动操作),相比较的是命名式(用 JQuery 直接操作 DOM,但会很快遇到维护问题)
  • 熟悉 React 都知道一个等式:View = render(state) 。
  • Virtual DOM 现在有各种各样实现,并不神秘,可以自己实现。

8

  • 变化侦测,Vue 的数据是响应式的,把数据交给 Vue 时,Vue 会进行转化,当改变数据值时,Vue 会做更新。
  • 巴黎演讲 PPT
  • 变化侦测主要分为 push 和 pull 两种。React 的 setstate 和 NG 的脏检查都是 pull,系统不知道数据是否已改变,需要进行 pull。相比之下 push 在数据变动时会立刻知道哪些数据改变。pull 是粗粒度的,Push会进行更细粒度的更新,但会有相应内存开销、依赖追踪开销的代价。
  • Vue 里选择中等方案(混合式),组件里选择 push,每个组件都是 watcher。组件内部使用 Virtual DOM 进行比较。

9

  • 直接在 HTML 里写 onclick ,里面 JavaScript 作用域是全局的。而在 Vue 组件里写时,JavaScript 作用域是被束缚好的。
  • Vue 组件里可以直接写 onclick 的原因是组件和模板是一起的,不会造成维护的困难。

10

  • 状态管理这个概念是 Facebook 提出 Flux 后慢慢被大家所熟知。Flux 在经历初期混乱竞争后,React 逐渐“合并”到了 Redux 上。VueX 一定程度上受 Redux 影响。状态管理的本质是从原事件映射到状态的迁移与改变,再映射到 DOM UI 的变化(eg: 从点击一个按钮到点击事件被触发的过程)。
  • 声明式的渲染已经帮我们解决了从状态到 UI 这一块。状态管理的库实际做的是如何管理将事件源映射到状态变化的过程,如何将映射过程从视图组件中剥离出来,提高可维护性,状态管理主要解决的这类问题。

11

  • Redux 强调的是数据不可变,函数式的,Reducer 里是一个纯函数,我们拿到一个 state 和 action 返回一个新的 state。MobX 和 Vue 里体现了不同的思维方式(“范式”),数据是响应式的,框架已经在数据上做好了声明式副作用的声明。

  • 可变数据难维护是当我们手动操作数据副作用操作,手动观察时会带来一定维护上的成本。

  • 把 Vue 当 redux 用

  • 让 Vue 当 MobX 用

12

  • 之前的方案其实都没有回答如何处理异步的问题。Redux 是将这件事交给 MiddleWare 去做,MobX 和 VueX 是让用户在 action 里做。
  • Redux 的各种解决方案其实各成一派。
  • 这些复杂的异步在简单的应用中,其实杀鸡不用上牛刀,因为在一个典型的 rest api 不存在太复杂的异步。比较复杂的事件源比如服务端推送、实时处理、多个同时请求等,应该专门做一层来处理这个问题。
  • 状态改变在 Redux 里用 Reducer,这些状态的改变在传统机制里要写出来。现在的状态管理方案还面临一些尴尬:组件的局部状态和全局状态如何区分?

13

  • 路由是大型单页应用才会遇到的问题,传统的路由**是“侵入式”的,比如最早在前端有路由概念时写应用得先从路由写起。
  • 当 React 和 Vue 这种专注于 View 层的库出现后,其实发现把组件和路由解耦是完全可行的,而且更灵活。比如 React 不带路由直接用时没有问题的。另一个启示是从组件出发思考路由问题,本质上就变成把一个 URL 映射到组件树结构的一个过程。
  • 像 NG 的路由重写过好几次,最后采用的是一个路径映射到组件的形式。React 和 Vue 也是提供路由映射的基本元素。NG 很早也提出了把组件作为用作路由的组合方式,但到现在很久都没有做出来。
  • 在 URL 到组件的映射有一些小的问题:到底应该从 URL 出发还是以状态出发?比如说一些路由库的实现是以状态之间的迁移为核心的。但其实也可以把 URL 理解为一个序列化的状态。
  • 最简单的路由其实就是一个动态组件。React 可以用对象表等实现。但一旦我们实际做一个单页应用会遇到跟多的问题:重定向、别名、懒加载,路由的钩子跳转如何应对用户取消跳转时让跳转无效的情况等等。
  • 现在主流的路由方案都有点相似,比较有意思的是最新的,用组件本身做路由的**,很大程度上利用了“功能型组件”。父组件里可以声明式的渲染其他组件。它和传统的路由方案是去中心化的,将路由写到各个组件中。但拥有相比集中式的路由表的应用来说,去中心化的路由对于跳转的管理会更弱等。
  • Web 路由和 APP 路由的区别,总体上都是将 URL 映射到组件树。原生应用的跳转模式和 Web 是有区别的,前者向一叠卡片一样,新的界面是盖在旧的界面上;Web 的路由方案做移动应用时会比较别扭。这里可以考虑考虑如何更好的发展。

14

  • 对于现在应用中的 CSS 有几种主流的实践:一类是跟 JS 完全解耦,靠预处理器和比如 BEM 这样的规范来保持可维护性,偏向传统, CSS 完全独立于应用书写。另一种是 CSS Module,通过编译来避免 CSS 类名的全局冲突;各类 CSS-in-JS 方案,React 社区为代表,比较激进。Vue 的单文件组件 CSS,或是 Angular 的组件 CSS(写在装饰器里面),是一种比较折中的方案。
  • 比较 CSS 方案时首先要明确场景的问题,如果应用逻辑已经组件化了,是一个比较复杂应用的开发,传统的 CSS 方式可维护性就有问题了。把组件和结构同义化是减低思维负担的一种方式。
  • https://speakerdeck.com/vjeux/react-css-in-js
  • CSS-IN-JS 在社区的意见比较分裂。A Unified Styling Language

15

  • 传统 CSS 的一些问题:作用域、Critical CSS、Atomic CSS、分发复用、跨平台复用等。
  • CSS-IN-JS 解决了一些问题。作用域很简单直接:我们不希望 CSS 污染组件全局时,可以用 CSS MODLE 等解决。服务端渲染 CSS 时要有办法侦测到将要用什么 CSS。
  • 跨平台复用我们可以把静态的 CSS PASS 后编译成跨平台的 JS。
  • 尤大个人对 CSS-IN-JS 持保留态度,毕竟用静态 CSS 进行编译时的分析和优化会更简单。因此 CSS-IN-JS 未必是未来的方向。

16

  • 没有本质的优劣区别,scoped 的成本回更低一点,但可能会导致植出页面会大一些。

17

  • 现在的前端开发环境需要安装很多工具,发展成这样的原因是 Web 的能力越来越强,外部需求越来越高,因此需要开发工具和开发环境越来越好。
  • 构建工具解决的其实是几方面的问题:任务的自动化、开发体验和效率(新的语言功能,语法糖,hot reload 等等)、部署相关的需求,编译时优化。
  • 最早的前端构建工具 Grunt、Gulp 等现在用的少的原因是它们执行自动化的功能现在 npm script 完全就可以替代,没必要依赖它的各种插件。Gulp 在构建这块引入流的**,但跟以模块为核心的构建工具比,就比下去了。npm scrtip + Webpack 渐渐成了主流。

18

  • 开发体验这块,前端比较有意思的限制是最终代码不可避免要跑在浏览器里,在我们使用 CSS、JS 新特性时要考虑浏览器的限制,因此前端的构建工具链渐渐变得很完善。
  • 张云龙 - 大公司里怎样开发和部署前端代码?
  • 分模块后不可能一个应用几十个请求过去,我们可以将多个文件打成一个包。Webpack 看起来只是代码打包,其实仔细深思会发现部署优化里要做很多事情。比如 JS 中静态资源的内联,不同资源刷新版本时如何缓存,如何代码分割,Webpack 可以避免我们手动进行“前端运维”。
  • Webpack 很复杂,复杂的原因是它要解决的问题就很复杂。
  • 严谨的前端工程肯定要走“编译”这一步。

19

  • 虽然 Vue 本身用 flow,但建议使用 TypeScript 的 flow,主要从开发体验、生态完善度上考虑。

  • 服务端数据通信中,长久以来我们围绕的是 Rest,如果服务端暴露出了一个标准的 Rest Api,客户端可以直接围绕 Rest 做封装。
  • 关于解决数据管理的方案,比起像 Rest 这样围绕资源做管理,我们可以使用
  • Vue.js 跨平台渲染指南

20

  • 从前端框架角度看,跨平台渲染本质是在设计框架的时候要在框架的渲染机制和 DOM 解耦,并不一定使用 Virtual DOM。本质上只需要把框架更新时结点操作封装起来便可做到跨平台。
  • 一个原生的渲染引擎,比如 React Native 和 VueX 本质都是在底层针对每个平台有一个适配的渲染引擎,只要把渲染引擎暴露的结点操作的 API,跟框架运行时对接一下,就可以实现将框架里面的代码渲染到原生的目的。这里的解耦很清晰,这也是为什么能看到 NG 可以接 React Native,VueX 可以跑 Vue 文件,VueX 可以跑在 NativeScript 上等等。

21

22

  • 之后前端外刊评论会有针对尤大的采访。

23

  • 现阶段 React 和 Vue 在场景上区别很小,所以应从团队效率、团队后续招人等方面考虑。两者能胜任的场景是差不多的。

24

  • 理解**最重要,熟悉源码能提升自己工程化的理解,对自己写库有帮助,但对业务帮助很小。

25

  • 前端渲染永远避不过 JS 加载执行完之后内容才出现。

26

  • HTTP2 跟打包优化互相之间作用是非常复杂的关系,和代码量、网络环境都有关系,只能实际测量和找数据才可。

27

  • 技术方案都是先有问题,再有思路,同时伴随着取舍。在选择衡量技术的时候,尽量去思考这个技术背后是在解决什么问题,它做了怎样的取舍。这样一方面可以帮助我们更好的理解和使用这些技术,也为以后哪天你遇到业务中的特殊情况,需要自己做方案的时候打好基础。

28

我的本场 live 感悟

这场 live 让我的前端思维达到了前所未有的新高度:当我们身为前端开发萌新,在前端人才金字塔的浮动与挣扎中思考该学什么框架、该如何入门前端、又遇到学习瓶颈怎么办的时候,正是这些业界大牛们用自己的行动引导着我们,有如尤大所说:多思考场景需求,多看看技术到底做了怎样的取舍。

我们不能止于前端的 HTML、CSS、JS 基础,应多在组件化、设计模式、模块化、数据流、渲染机制、路由机制、构建流、代码标准的演化等方面下功夫思考,这些终会有一天成为我们突破技术、职业发展瓶颈的武器。

通过这场 live 也暴露出了自己,想必包括很多参加 live 的国人的一些问题:英语听力还是不够好,编程视野还是不够大,开发者平台的力量我们还是没有发挥好。

鸡汤不多说,在落后的大学 Web 前端教育上要达到一个找工作的水平,需要我们更热情的参与到各大社区之中,把开源当做平台,用平台证明实力。

相关链接

4 月 23 日 justjavac 的一场知乎 live 让我同样受益匪浅,这是当时的笔记:《听 jjc 前端 live 30 谈 | 前端工程师的入门与进阶》,相对这场 live 难度更适中一些。

[A0C]Mac OSX 下用 Homebrew 安装 MongoDB 并配置到 WebStorm 中

1. 安装 Ruby

OSX 操作系统内置 Ruby,但如果没有 Ruby,则需先输入以下命令安装能够进行多版本ruby环境安装、管理和切换的命令行工具 RVM。

1.1 安装 RVM

打开终端输入以下命令:

curl -L https://get.rvm.io | bash -s stable

安装完成 RVM 后运行"rvm"的显示结果如下,可见安装完成后需要再输入该命令启动 RVM:

source ~/.rvm/scripts/rvm

修改 RVM 的 Ruby 安装源到 Ruby China 的 Ruby 镜像服务器,这样能提高安装速度

echo "ruby_url=https://cache.ruby-china.org/pub/ruby" > ~/.rvm/user/db

1.2 用 rvm 安装 ruby

列出已知的 Ruby 版本

rvm list known

安装一个 Ruby 版本

rvm install 2.2.0 --disable-binary

这里安装了最新的 2.2.0, rvm list known 列表里面的都可以拿来安装。

切换 Ruby 版本

rvm use 2.2.0

如果想设置为默认版本,这样一来以后新打开的控制台默认的 Ruby 就是这个版本

rvm use 2.2.0 --default 

查询已经安装的ruby

rvm list

卸载一个已安装版本

rvm remove 1.8.7

rvm 的更多用法详见:RVM 使用指南 · Ruby China

2. 安装 Homebrew

Homebrew 的官方网站

Homebrew是Mac OSX下一个包依赖管理工具,用它来安装软件非常的方便只需要brew install 软件名这一条命令就可以将你所需要的软件安装好,不用再操心安装过程中软件的依赖问题,这些问题Homebrew统统帮你搞定,Homebrew的官网:http://brew.sh/ 在官网上对Homebrew的安装和用法有详细的描述这里就不多扯了。如果你还没有安装,还等什么赶紧动手安装吧!:]

Ruby 已经安装好,输入以下命令安装 Homebrew

ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"

查看 Homebrew 是否安装成功并查看版本号

brew --version

3. 用 Homebrew 安装 MongoDB

brew install mongodb

3.1 测试 MongoDB

安装完成后检验 MongoDB 是否安装成功并查看版本号

mongod --version

其 mongod命令是用来启动MongoDB的服务的

3.2 创建 /data/db 文件

执行 mongod 命令后返回了一堆错误信息,如下:

错误信息的意思是dbpath (/data/db)不存在(dbpath (/data/db)这个目录是用来存储MongoDB数据文件的地方),需要创建/data/db这个目录或者使用--dbpath参数项指定一个已经存在的目录。

既然不存在/data/db那我们就创建这个目录,可能需要加上 sudo 权限

sudo mkdir -p /data/db

3.3 解决 /data/db 文件 权限问题

再次输入mongod 命令启动MongoDB的服务,服务又退出了返回一堆信息如下:

意思是因为权限问题不能创建和打开/data/db/mongod.lock这个文件,这里有两个选择,用 sudo 权限执行(不推荐)或者将 /data/ 加入用户权限

sudo mongod

或者

sudo chown -R hanyile /data

3.4 MongoDB 安装成功

再次输入 mongod 命令执行成功

4. 访问 MongoDB

更多参考请访问:The mongo Shell

安装成功后执行输入 mongod 命令不要关闭终端,打开浏览器输入 localhost:27017 如果出现以下结果则证明开启成功

4.1 进入 MongDB 的CLI管理界面

mongod 运行的时候在另一个终端执行 mongo 命令,运行结果如下:

mongo

5. WebStorm 上绑定 MongoDB

Mac 下输入 Command + Shift + A 打开 WebStorm 的设置的快速搜索,输入 plugins 并进入

搜索 mongo 即可找到 Mongo Plugin,安装之

安装完成后需要配置 MongoDB 的安装目录到 WebStorm 中,输入

which mongo

将返回结果复制到下面的框中点击 Test ,测试 OK后点击左下角 “+” 号

在弹出的 “Add a Mongo Server”中随便起个名字后点击 OK

即可看到 WebStorm 右侧有 MongoDB 的可视化插件了~

[A10]Web前端小白入门指迷

大前端之旅

大前端有很多种,Shell 前端,客户端前端,App 前端,Web 前端和可能接下来很会火起来的 VR 前端等。当然在这篇文章,集中讨论一下身为小白,我们怎样去了解 Web 前端,以至达到一种入门级别的水平。

大前端导图

这同时也可作为任何一门编程语言入门之旅的小参考,不足之处欢迎指出。

为什么学 Web 前端

互联网的快速发展和激烈竞争,用户体验成为一个重要的关注点,导致专业前端工程师成为热门职业,各大公司对前端工程师的需求量都很大,要求也越来越高,优秀的前端工程师更是稀缺。个人感觉前端入门相对容易,但是也需要系统地认真学习,在打好基础后坚持学习,成为优秀前端工程师也只是时间问题。

当然,学 Web 前端的源动力也可以仅仅是想在浏览器上跑一个自己写的小游戏,或者好奇一下这个互联网的工作原理。

浏览器上的页面

在浏览器中输入 www.jianshu.com 访问简书官网,服务器就会发来简书网页的源代码和一些图片,接着浏览器执行这些代码并将结果显示在浏览器窗口中,我们便可以进一步操作。

简书

查看页面源代码

打开简书后,在( Chrome )浏览器窗口任意位置点击右键 -> 检查(快捷键 Ctrl + Alt + I 或 Alt + Commd + I)即可打开开发者模式,可见每一个我们能够看到的界面都是源代码被处理的结果。而这个源代码便是 Web 前端要去入手了解的第一步。

打开浏览器开发者模式

Web 前端小白技能点

那么都该学什么才可以做出这么好看有趣的网页呢?可以从 @Phodal 大神之前写过的 Web 技能树看出 Web 前端的三大语言基石 -- HTML,CSS,JavaScript。

Web 技能树 -- Phodal

以及几年前一个很流行的前端工程师技能图谱可以借鉴学习。

前端工程师技能图谱

其中,HTML 是超文本标记语言,文件以 .htm 或 .html 为扩展名,每当有一个 HTTP 请求(可以先理解为浏览器要访问网页的标准请求),服务器便根据请求发送相应的 HTML 文档到客户端进行解析,我们便可以看到相应的网页。

CSS 即层叠样式表 (Cascading Style Sheets),定义如何显示HTML 元素。我们可以把 CSS 写到 HTML 页面的 标签中,或者直接引入外部以 .css 为拓展名的文件(外部样式表)到 HTML 页面中,外部样式表使你有能力同时改变站点中所有页面的布局和外观。

W3School 上一个简单的 CSS 实例

JavaScript 是因特网上最流行的脚本语言,可以在不刷新整个 HTML 的页面时根据具体事件动态的更改页面内容,使网页真正的“活”了起来。这里不得不说的是,由于 JavaScript 近年来火热发展,覆盖已经不仅仅局限于 Web 前端而涉及到服务端(Node.JS 等)甚至物联网和 VR 设备上了。

例1. 《致JavaScript也将征服的物联网世界》
例2. 《打造VR世界: Oculus + Node.js + Three.js》

JavaScript 在网页上的一个验证输入功能

编程语言的概念在这里只做引导,具体点进下方“去哪儿入门 Web 前端编程语言”推荐的网址进行深入理解~

去哪儿入门 Web 前端编程语言概念

这里按类别直接上几个推荐学习 Web 开发(不只是前端)的学习网站:

更多的内容在我的 Github 仓库 @icorvoh:FSD-Debris 中持续维护。

在哪儿了解 Web 前端编程语言动态

这里是一些较为经典的 IT 新闻网站,可以及时关注最新的技术改变

更多的内容在我的 Github 仓库 @icorvoh:FSD-Debris 中持续维护。

基本开发工具

写 Web 前端源码用什么工具写?难道就用文本编辑器编辑 .txt 文件后将后缀改为 .html 才能打开并运行吗?当然不是,这里有很多很棒的前端开发工具作为推荐。根据个人信仰,选择其一就好。

WebStorm

WebStorm 一度被广大** JS 开发者誉为“ Web 前端开发神器”、“最强大的 HTML5 编辑器”、“最智能的 JavaScript IDE ”等,有智能的代码补全,代码格式化,html提示,联想查询,代码重构,代码检查和快速修复,代码调试,代码结构浏览,代码折叠和包裹或者去掉外围代码等等等等特点。可以集成 Git ,随时将自己的代码提交到远程代码托管平台。

WebStorm

Sublime Text 3

Sublime 是程序员Jon Skinner于2008年1月份所开发出来的一款跨平台轻量级文本编辑器。Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。配合上各种开发插件,便可达到高效开发的状态。

Sublime Text 3

Atom

Atom 是由 Github 官方发布,专门为程序员推出的一个跨平台文本编辑器。具有简洁和直观的图形用户界面,并有很多有趣的特点:支持 CSS,HTML,JavaScript 等网页编程语言。它支持宏,自动完成分屏功能,集成了文件管理器。

Atom 编辑器

安利一个 Atom 上的一个插件 -- activate-power-mode,打开会有震撼的敲击代码的效果。效果演示地址

Web 前端前期书籍推荐

好的学习道理离不开实体书的陪伴。好的书籍便是节约学习时间、拓展视野的一个高效道具。从 HTML + CSS + JavaScript 出发推荐一些书籍。

节选自 FKS 前端书籍推荐

遇到问题怎么办

当然这么办咯

难道这就完了吗

说了这么多,这也仅仅才是开始。Web 前端开发之路也是认知整个计算机科学之路,这一路技术底蕴必不可少。如果能再做到下面几点就更好了。

HTML 5.1

9 月份就要发布 HTML 5.1 了,这么重大的新闻,还在等什么。。?

THE FUTURE IS LANDING

[A15]漫游C世界--DIY软件部编程之旅

DIY 引言

去年的这个时候,大一新生的我,怀揣着对大学的无限憧憬来到了西邮软件工程专业。那时,我对未来的自己定位简简单单,“程序猿大叔”便是我以为要走的路。

当然,接下来的加社团、加实验室、社区活动等经历改变了我的想法。我不想只当一个敲代码领工资回家抱孩子的普通程序员,我想做的更多,并着手为之努力——DIY 电脑俱乐部即是我最早加的兴趣社团。

DO IT YOURSELF

其中很有趣的是,除了一般兴趣社团都会有的宣传部、办公室等部门之外,DIY 电脑俱乐部还有福利部门 —— 每个月都要在校内组织举办电脑义修活动的维修部;教大家装机、拆机的硬件部和教大家 C 语言并分享西邮的~软件部。这些部门并没有严格的划分。三个福利部的部长们互相帮助,一起举办活动。

于是目光转移到了我在软件部的经历,去年因为自己提前学了 HTML + PHP 并在来大学之前做过一个小网站,所以在和大家一起学 C 的时候自己的上手能力也就更快了。在之后几次学长学姐组织的软件部分享活动中自己也能上去讲一讲所以然。

到了今年,虽然没有留部的自己,也收到了和我同班的 2016 届软件部部长的邀请,让我来进行第一堂课的分享活动,也就有了这篇文章。

准备活动

好在我也有了一年的写博客经历还有我暑假所学的编程学习方法之《思沃学院所带给我们的》,作 DIY 软件部第一次分享前的准备并不是很难。把自己在暑期简书刚刚建立起来规约发布的第一篇文章 《浅谈C语言历史》 与当时制作的 PPT 结合起来,就直接冲了上去。这俩篇文章中有关 C 语言部分的内容会有重复。

有了活动主题,接着要去想活动流程,会玩的我立刻用 IOS 软件“思维导图”绘制出了如下 DIY 软件部第一次分享活动流程,并将主题更新为《漫游 C 世界》。

群公告里能写的文字数量有限,直接上 Github 并用谷歌浏览器插件全屏截图。发到各个 DIY 群文件中做宣传~

if ("主题确立" + "流程确立" + "水 QQ 群宣传" == DIY_OK) {
    System.out.printf("%s~\n","活动开始");
}

活动进行时

跟着我用 slides.com 制作的在线 PPT 来讲,“《漫游 C 世界》”分享之路正式开启。

缅怀 Dennis Ritchie

这一环节讲述了 Dennis Ritchie 的伟大事迹 —— C 语言之父和 Unix 之父并缅怀他在 2011 年 10 月因病去世。因为他在生前追求的“保持简单”原则,直到同事从加州到新泽西去拜访他时才发现独居的他已然去世。在同年同月逝世的还有为互联网做出重大贡献的乔布斯,只是当时的媒体新闻都在专注于乔布斯的逝世了。

保持简单----纪念丹尼斯•里奇(Dennis Ritchie)

早期高级程式语言家族

C 语言并不是突然蹦出来的,而和牛顿一样同样是“踩在巨人的肩膀上”发明而来。1958 年的 ALGOL 60 到 CPL 再到 BCPL 的前期发展才有了 UNIX 内核最早的开发语言 B 语言。但 B 语言没有数据类型也不好用,C 语言便由 Dennis Ritchie 和 Ken Thompson 发明而诞生于世。具体的语言特性可以自行搜索。

其中 B 语言的诞生初衷仅仅是 IT 大牛 Ken Thompson 为了写个模拟在太阳系航行的电子游戏 Space Travel 玩而发明。

玩玩 C 语言游戏

分享活动要有趣一些,生活才更精彩一些。世界还要继续运转,缅怀完 C 语言之父就来玩玩 C 语言写出来的游戏,来感悟有趣的编程世界。

其中 Contra 是魂斗罗,Snake 是贪吃蛇,Fight-Snake 是战斗贪吃蛇,也都是我提前搜集的游戏。从 Github 上下载出来点击 .EXE 即可畅玩。

C 语言历史

如何学习 C 语言呢

这是一个大而泛的问题,如果有人这么私聊我的话其实我想拒绝回答的~毕竟这种学习方法无关学编程与否。要去学会拆解问题。

拆解“如何学 C 语言”这样的问题,很简单,当拆解完后,每个人自己都有了新中的答案。

  • 都能去哪些网站学 C
  • 都可以看什么书籍学 C
  • 大学课堂、自学、培训班哪个好
  • 用什么软件学习 C 语言
  • 为什么推荐在 Linux 下学 C
  • 等等等等。。

大家分 5 个小组去讨论 10 min,并分享出来~

当然大家都靠嘴上说了,我在听的同时诺列了出来方便大家理解。

编织你的梦 - TED 演讲

早想有一个氛围去像大家分享这个 TED 演讲,一位欧美女程序员对自己编程之路的思考和分享。

一个相同的视频,每个人都会有自己不同的感悟。本想着列举一下这个视频都讲了什么,却也将这个思考重新留给了大家。

编织我的梦

第一次结束,而编程人生刚刚开始

分享到最后时间也晚了,教室也要关门了。这次分享结束,但对学弟学妹们,甚至对我来说,未尝不是一次重新开始~

[B07]小全栈任务“番茄post”【1】拆分里程碑

据说全栈路线图是这样的,详细地连 DevOps 都不得不被掩盖住一截。

github@bmorelli25/Become-A-Full-Stack-Web-Developer

全栈工程师,Full Stack Developer,常是一个较为敏感的话题,一如深度还是广度好,一如精读还是粗读好一样。你可以说,接下来步入的整个项目是一个实为 Node.JS 的伪全栈项目,但作为有志青年来讲,“全栈”足以时刻提醒自己是面向软件工程专业和互联网行业学习,找的是不去惯性局限自己视野的一股劲。毕竟:

「任何一个 Facebook 的问题,都不是别人的问题」

这次,利用 ThoughtWorks 校企实验室的团队项目机会,带来一个 React.js + Node.js 技术栈的全栈实战项目:基于番茄工作法的番茄时钟:“番茄post”。该项目将作为自己和团队的练手项目,并及时更新进度。同时,这一路走下去,也将是一场软件工程的项目实战,对理解软件开发流程模型很有帮助。

暂时以这个为 logo,找点感觉

有了小产品理想,画大饼很简单,但要能够搭建一个足以依靠敏捷开发稳步推进的软件开发流程,以大学生的能力还不足以直接上手。这次,多亏了 ThoughtWorks IT 咨询师,同任我们实验室老师的 @TW李鹏 老师对功能分析的指导,让我们理解了项目前期对功能分析和设立多个目标里程碑的重要性并能予落实。引用老师的话来说,拆分项目里程碑,有如下优缺点。

这样带来的好处是:
* 我们每个里程碑所需要考虑的问题变小,易于分析、思考和掌控
* 每个里程碑要学习的东西比较集中,不会迷失
* 每个里程碑结束,有一个完整可用的产品,能够产生价值,也能够给自己带来成就感
* 如果在假期中时间或者精力不够了,可以放弃后面的里程碑,至少可以做出功能较少但是可用的东西出来,而不是一个很大但是没法使用的半成品
带来的问题是:
* 为了保证每个里程碑功能的完整,有时候需要在过程中添加一些额外的功能,而这些功能在最后可能会被丢弃,有额外的工作量
* 新的里程碑的功能可能会在之前的功能上修改,如何保证之前的功能不被破坏,需要一定的技巧

随着我们接下来对“番茄post”全栈项目的推进和文章总结,这将是一场程序员的技术战,也将是一场工程师的身心战,智慧与勇毅将带来最终的成果。

程序功能分析

“番茄post” 基于番茄工作法,旨在向用户提供个性化、社区化的时间管理环境,提高工作效率,改善生活品质,经过功能拆解历程,它的前期版本将具有以下功能:

  1. 发布番茄:每发布一个番茄,记录刚刚发布的一个番茄工作内容。
  2. 展示番茄:将发布的所有番茄内容能够展示出来。
  3. 登录/注册:可以向多个用户提供服务。
  4. 关注他人:增加用户多维链接,促进双向激励。
  5. 评论番茄:促进用户交流、鼓励。
  6. 番茄排行:展示热门番茄,让用户有所榜样。

功能拆解历程

根据“有社区的番茄工作法软件”为目标同时列出的有添加番茄、暂停番茄等与前端视觉效果有关的功能并以为然作为重点,经过老师带领我们对产品需求进行的细细挖掘下发现,“番茄post”需要解决的核心需求点在于:

  • 改善用户拖延症、焦虑症、提高用户工作效率
  • 解决能够随时看到他人近期完成的基于番茄工作法的内容来激励自己
  • 满足用户间对于时间管理、个人成长等平台话题的社交渴求
  • 能和任意平台用户一起指定多日番茄计划互相监督互相激励

以上大部分强调的是,“番茄post”更偏向社交化时间管理,前期应削弱对番茄的前端功能效果实现而重在搭建能够发布番茄、社交激励的社区平台。


以下里程碑结合功能复杂度和技术难点进行前期划分。


第一个里程碑:搭架子


平台开发环境第一性,提前了解将要使用的技术将决定架子的内在。考虑到平台多样性和团队精力的有限性,以下列出的开发环境将作为第一版出现。

  • 用户平台:Web 浏览器
  • 编程语言:JavaScript
  • 前端框架:React.js
  • 运行环境:Node.js
  • 构建工具:NPM

最终,只需要能够运行出一个简单的 Hello World 页面即可。

验收条件

  1. 其他人可以方便的获取你的代码(Github)。
  2. 其他人可以通过你的说明文件,在本地将服务器快速的运行起来,看到页面(README.md)。
  3. 通过简单的页面可以证明你使用的技术栈和主要的库等已经配置正确;
  4. 代码以“小步”方式提交到github上,并且每个commit都有清楚的描述;
  5. 若干篇博客用来记录你的学习收获和疑问。

第二个里程碑:数据库搭建和番茄的发布及其页面


最基本的功能是对番茄的“增删改查”,在这个里程碑中,我们先实现对番茄的发布,即增加到数据库中。制作番茄发布页面。

验收条件

  1. 任何人可以在账号密码正确的情况下访问数据库;
  2. 数据库中的相关番茄表单结构确立并能够看到;
  3. 任何人都可以看到番茄发布页面里有一个输入框和发布番茄按钮;
  4. 任何人都可以通过输入框填补番茄内容并点击发布按钮发布一个番茄;
  5. 点击发布番茄按钮后的相关错误提示信息能够得到展示;
  6. 发布番茄后,数据库里要能够看到该番茄及其内容和发布时间;
  7. 代码以“小步”方式提交到github上,并且每个commit都有清楚的描述;
  8. 若干篇博客用来记录你的学习收获和疑问。

第三个里程碑:番茄的展示与删除及其页面


这一步,在我们将番茄及其相关信息更新到数据库后,要能够将数据读取出来并在前台展示,提供删除按钮并能删除成功。番茄的展示与删除的页面和番茄发布页面同为一个页面之下,名为用户个人主页页面。

验收条件

  1. 任何人都可以看到所有已经发布了的番茄;
  2. 任何人都可以删除所有已经发布了的番茄;
  3. 删除番茄后,该番茄将从数据库中删除并不会再展示到前台;
  4. 代码以“小步”方式提交到github上,并且每个commit都有清楚的描述;
  5. 若干篇博客用来记录你的学习收获和疑问。

第四个里程碑:登录/注册功能及相关页面


之前的里程碑都在于搭建针对单独用户的核心功能,这一步来搭建用户平台。

验收条件

  1. 任何人都可以访问登录、注册页面;
  2. 任何人都可以注册一个没有被注册的账号;
  3. 任何人在某账号和密码匹配的情况下都可以登录该账号;
  4. 登录、注册过程中的相关错误信息能够得到展示;
  5. 登录成功后,可以访问自己的番茄发布与展示页面;
  6. 代码以“小步”方式提交到github上,并且每个commit都有清楚的描述;
  7. 若干篇博客用来记录你的学习收获和疑问。

第五个里程碑:番茄首页


这时,每一位用户都有自己的个人主页页面并能通过发布、删除番茄来更新自己的时间管理记录。番茄首页将着手打造番茄社交环境,用来展示所有已注册过的用户,提供社交链接。

验收条件

  1. 任何人都可以访问番茄主页;
  2. 任何人都能看到番茄主页下展示的所有已注册过番茄平台的用户;
  3. 任何人都能看到番茄主页下提示的登录、注册按钮并可以点击;
  4. 代码以“小步”方式提交到github上,并且每个commit都有清楚的描述;
  5. 若干篇博客用来记录你的学习收获和疑问。

第六个里程碑:关注他人与被他人关注


这一步:关注他人。

验收条件

  1. 任何人都可以访问某位用户的个人主页;
  2. 任何人都可以看到某位用户的个人主页的他关注的人和关注他的人;
  3. 任何人都可以看到某位用户的个人主页下有关注该用户按钮;
  4. 任何人在点击关注该用户按钮后判断是否登录;
  5. 任何人在关注、登录过程中的相关错误信息能够得以展示;
  6. 任何人在成功关注某位用户后可以在该用户个人主页的关注他的人下看到自己;
  7. 任何人在成功关注某位用户后可以在自己的个人主页的我关注的人下看到该用户;
  8. 任何人在成功关注某位用户后再次访问该用户主页时,关注按钮变成已经关注的提示。
  9. 代码以“小步”方式提交到github上,并且每个commit都有清楚的描述;
  10. 若干篇博客用来记录你的学习收获和疑问。

第七个里程碑:番茄评论


验收条件

  1. 任何人可以看到每个已经发布的番茄旁有评论框和评论按钮;
  2. 任何人在没有登录情况下可以看到评论框和按钮无法编辑和点击并有登录提示;
  3. 任何人在登录的情况下可以评论某个番茄;
  4. 评论成功后能看到该番茄下的最新评论;
  5. 每个番茄下的评论按最新时间由上到下排列;
  6. 代码以“小步”方式提交到github上,并且每个commit都有清楚的描述;
  7. 若干篇博客用来记录你的学习收获和疑问。

第八个里程碑:番茄网站上线


正式上线至某 IP 地址或某域名下。

验收条件

  1. 将数据库部署至线上;
  2. 番茄平台所有功能在线上调试成功;
  3. 任何人能够通过互联网访问番茄首页并进行深入操作;
  4. 代码以“小步”方式提交到github上,并且每个commit都有清楚的描述;
  5. 若干篇博客用来记录你的学习收获和疑问。

更多内容,尽请期待

“番茄post”的里程碑写到这里,可以看到,还有很多细节没有深入讨论。在敏捷的软件开发流程下,鉴于我们开发者也一直在梳理需求且需求会随时回炉重塑,先开发出一个可用可见的真实产品出来再看进一步发展。

软件生存期模型是跨越整个生存期的系统开发、运作和维护所实施的全部过程、活动和任务的结构框架,其中就包括增量模型这一软件开发模型,很符合这一次任务的开发流程,图例如下。

更多内容,持续更新中~。

[A09]C 语言文件的概念与简单数据流的读写函数

写完「C语言」单链表/双向链表的建立/遍历/插入/删除 后,如何将内存中的链表信息及时的保存到文件中,又能够及时的从文件中读取出来进行处理,便需要用到”文件“的相关知识点进行文件的输入、输出。

其实,就算不懂得链表,也完全可以学习”文件“相关知识点,但在此之前最好有”指针“基础。本篇文章整理自《C语言程序设计教程--人民邮电出版社》第十二章——文件,以作文件探讨。
 

一、数据流与文件概念

   

1. 数据流

数据的输入与输出都必须通过计算机的外围设备,不同的外围设备对于数据输入与输出的格式和方法有不同的处理方式,这就增加了编写文件访问程序的困难程度,而且很容易产生外围设备彼此不兼容的问题。数据流(Data Stream)用来解决这个问题。

数据流将整个文件内的数据看作一串连续的字符(字节),而没有记录的限制。数据流借助文件指针的移动来访问数据,文件指针目前所指的位置即是要处理的数据,经过访问后文件指针会自动向后移动。每个数据文件后面都有一个文件结束符号(EOF),用来告知该数据文件到此结束,若文件指针指到 EOF 便表示数据已访问完毕。

2. 文件

“文件”是指存放在外部存储介质(可以是磁盘、光盘、磁带等)上的数据集合。操作系统对外部介质上的数据是以文件形式进行管理的。当打开一个文件或者创建一个新文件时,一个数据流和一个外部文件(可能是一个物理设备)相关联。 C 语言支持的是流式文件,即前面提到的数据流,它把文件看作一个字节序列,以字节为单位进行访问,没有记录界限,即数据的输入和输出的开始和结束仅受程序控制,而不受物理符号(如回车换行符)控制。可以从不同角度对文件进行分类

  1. 根据文件依附的性质——普通文件和设备文件。
  2. 根据文件的组织形式——顺序读写文件和随机读写文件。
  3. 根据文件的存储形式——ASCII 码文件和二进制文件。

ASCII 码文件和二进制文件的主要区别:

  1. 存储形式:ASCII 文件将该数据类型转换为可在屏幕上显示的形式存储,二进制文件是按该数据类型在内存中的存储形式存储的。
  2. 存储空间:ASCII 所占空间较多,而且所占空间大小与数值大小有关。
  3. 读写时间:二进制文件读写时需要转换,造成存取速度较慢。ASCII 码文件则不需要。
  4. 作用:ASCII 码文件通常用于存放输入数据及程序的最终结果。二进制文件则不能显示出来,用于暂存程序的中间结果。

在 C 语言中,标准输入设备和标准输出设备是作为ASCII码文件处理的,它们分别称为标准输入文件和标准输出文件。

文件和内存的交互处理:


 

二、文件的打开与关闭

  • 要打开指定的文件可使用fopen()函数
FILE *fopen(char *filename,char *mode);

其中第二个参数mode用来设定要打开的文件类型和指定文件的访问模式。文件中的访问模式:

  • 判断文件是否正确打开
FILE *fp;
fp=fopen("文件目录","文件中的访问模式");
if(fp==NULL)
{
    printf("\n不能打开该文件!");
    getch();
    exit(1);
}
  • 关闭文件使用 fclose()
int fclose(FILE *fp);

返回值为0则表示关闭成功,若返回非0值则表示有错误发生。由系统打开的标准设备文件,系统会自行关闭。

  • 获取文件的属性:
    • 获取文件描述字:int fileno(FILE *fp);
    • 根据文件描述字获取对应文件大小:long filelength(int handle_no);
       

三、文件的顺序读写

顺序读写是指将文件从头到尾逐个数据读出或写入。

单字符读写函数:fgetc() 和 fputc():

int fgetc(FILE *fp);
  • 功能为:读取文件指针 fp 目前所指文件位置中的字符,读取完毕,文件指针自动往下移一个字符位置,若文件指针已经到文件结尾,返回 -1。
  • 返回值:成功则返回读取到的字符,失败返回 -1。
  • fgetc() 函数调用中,读取的文件必须是以读或读写的方式打开的。
int fputc(char ch,FILE *fp);
  • 功能为:把字符 ch 写入文件指针 fp 所指向文件的位置。
  • 返回值:成功时返回字符的 ASCII 码,失败时返回 EOF(在 stdio.h 中,符号常量EOF的值等于-1)。
  • 被写入的字符可以用写、读写、追加方式打开。

字符串读写函数:fgets()和fputs():

char *fgets(char *str,int n,FILE *fp);
  • 功能为:在文件指针 fp 所指文件位置读取 n 个字符并放入 str 字符数组。
  • 返回值:如果读不到字符串时返回 NULL。
int fputs(char *str,FILE *fp);
  • 功能为:将字符串 str 写入文件指针 fp 所指文件的位置。
  • 返回值:写入数据成功时返回非 0 值,写入失败时返回 EOF 。

格式化字符串读写函数:fscanf() 和 fprintf()

int fscanf(FILE *fp,"格式化字符串",【输入项地址表】);
  • 功能为:从文件指针 fp 所指向的文件中按照格式字符串指定的格式将文件中的数据送到输入项地址表中。
  • 返回值:读取数据成功返回所读取数据的个数,并将数据按照指定格式存入内存中的变量或数组中,文件指针自动向下移动。读取失败返回 EOF 。
int fprintf(FILE *fp,"格式化字符串",【输入项地址表】);
  • 功能为:将输出项表中的变量值按照格式字符串制定的格式输出到文件指针fp所指向的文件位置。
  • 返回值:成功返回输出字符数,失败则返回负值。

数据块读写函数:fread() 和 fwrite:

int fread(void *buffer,int size,int count,FILE *fp);
  • 功能为:从文件指针fp所指向的文件的当前位置开始,一次读入 size 个字节,重复 count 次,并将读取到的数据存到 buffer 开始的内存区中,同时将读写位置指针后移 size*count 次。
  • 返回值:该函数的返回值是实际读取的 count 值。
int fwrite(void *buffer,int size,int count,FILE *fp);
  • 功能为:从 buffer 所指向的内存区开始,一次输出 size 个字节,重复 count 次,并将输出的数据放入fp所指向的文件中,同时将读写位置指针后移 size*count 次。
  • 返回值:返回实际写入的数据项个数 count。
     

四、文件的随机读写

随机读写可移动文件内部的位置指针到需要读写的位置,再进行读写,这种读写称为随机读写。实现文件的随机读写关键是要按要求移动位置指针,这成为文件的定位。

void rewind(FILE *fp);
  • 功能为:将文件内部的位置指针移到文件的开始位置。
int fseek(FILE *fp,long offset,int whence);
  • 功能为:文件指针由 whence 地址移到 offset 的地址。
  • 返回值:对应文件的指针偏移,在函数定义中并没有真正的说明清楚返回值,对于offset当为正数的时候是向文件尾偏移的,当为负数的时候是向文件头方向偏移的,这里主要是要注意偏移的大小和文件大小边界的关系。当 offset 是向文件尾方向偏移的时候,无论偏移量是否超出文件尾,fseek 都是返回 0 ,当偏移量没有超出文件尾的时候,文件指针式指向正常的偏移地址的,当偏移量超出文件尾的时候,文件指针是指向文件尾的。并不会返回偏移出错-1值。当offset是向文件头方向偏移的时候,如果 offset 没有超出文件头,是正常偏移,文件指针指向正确的偏移地址,fseek 返回值为 0 。当 offset 超出文件头时,fseek 返回出错 -1 值,文件指针不变还是处于原来的地址。
long ftell(FILE *_File);
  • 功能为:得到流式文件的当前位置,用相对于文件开头的位移量来表示。由于文件中的位置指针经常移动,人们往往不容易知道其当前位置。用 fell 函数即可以得到当前位置。
  • 返回值:如果返回-1L,表示出错。
int putw(int _Ch,FILE *_File);
  • 功能为:将整数_Ch输出到fp指向的文件。
int __cdecl getw(FILE *_File);
  • 功能为:从磁盘文件都一个整数到内存最为返回值。
     

五、出错检查

C 语言中常用文件检测函数来检查输入/输出函数调用中的错误。

int feof(FILE *fp);
  • 功能为:判断指针 fp 是否处于文件结束的位置。
  • 返回值:如文件结束,返回值为 1,否则为 0。 
int ferror(FILE *fp);
  • 功能为:检查文件在用各种输入/输出函数进行读写时是否出错。
  • 返回值:如果 ferror 返回值为 0 表示未出错,否则表示出错。
                注意:对同一个文件每一次调用输入/输出函数,均产生一个新的ferror函数值,因此,应当在执行 fopen 函数时,ferror 函数初始值自动置0。
int clearerr(FILE *fp);
  • 功能为:本函数用于清除出错标志和文件结束标志,使它们为 0 值。假设在调用一个输入/输出函数时出现错误,ferror 函数值为一个非 0 值。在调用 clearerr(fp) 后,ferror(fp) 的值变为 0 。
  • 只要出现错误标志,就会一直保留,知道对同一文件调用 clearerr 函数或 rewind 函数,或任何其他一个输入/输出函数。
     

六、低级 I/O 函数与标准 I/O 函数

系统输入/输出函数,或称低级 I/O 函数,在内存访问数据并不提供缓冲区,因此只要一有数据需要做访问操作时,便直接向磁盘作Disk I/O。此类文件函数的优点是不必占用内存空间作为缓冲区,直接向磁盘的数据文件进行读写的操作,如果不幸死机,只会影响目前正在读写的数据。其缺点就是数据访问时会造成磁盘 I/O 次数太过频繁而影响程序运行的速度,而且此类函数是以文件描述字来代替文件指针,且不提供格式化的处理功能。

由于现行的C版本,基本使用的都是缓冲文件系统,即标准输入/输出函数,所以,关于非缓冲文件系统的系统输入/输出函数在这里就不再详细介绍。

[A1C]技术社区联动公益行业 | 极思2016西安之我的回顾

在我前几周参与的极思2016西安社区活动中,极思活动官方是这么介绍自己的:

极思取其音译“GeekSeek”, 旨在通过不同形式的对话、培训、协作等方式打破公益与技术社区的界限,使公益行业通过技术产生联动、协作,并推动设计和技术更为优质地服务于受助群体。由 ThoughtWorks 发起,并作为主办方将“极思”作为技术型企业支持公益行业信息化提升的落地举措,ThoughtWorks 的技术工作者也会在此基础上与公益伙伴积极探索更具本土特色和价值的技术实践。仍然围绕设计思维、敏捷、精益等创新理念,沿袭极思一期、二期(2014-2015)全国巡回培训方式,极思三期(2016)将携手5家合作伙伴在北京、西安、成都、上海、武汉、深圳举行6场活动。

关键便在于,极思的存在使公益行业通过技术产生联动、协作,并推动设计和技术更为优质地服务于受助群体。

本次巡回活动的内容如下,其中第三点里极思西安选择的是“服务设计工作坊”。

  • 用技术改变世界(unicef案例分享)
  • 同理心与用户研究方法
  • 服务设计工作坊 or 可视化设计工作坊(根据参与者情况会略有调整)

那么开始回顾吧。极思西安这场活动中,都发生了什么,学到了什么。

作为一枚大学生,在这里我会努力用我所知道的,去拼装我的理解。


一、主办方 ThoughtWorks 介绍


ThoughtWorks 是一家全球软件设计与定制领袖企业,也是一家融合创新、技术、设计的 IT 咨询与软件交付公司,始于 1993 年的芝加哥。2016 年,ThoughtWorks 已经在 14 个国家有了自己的分公司,在**也已成立了北京、西安、成都、武汉、上海和深圳六个分公司,聘用了 4000 多位行业精英,通过全球资源共享和人才交流服务全球高端客户。


ThoughtWorks 的使命


倡导社会责任感的 ThoughtWorks 致力于通过软件创造人类更美好的明天,同时引领最具天赋和积极性的 ThoughtWorkers 致力于“经营可持续的业务”、“推动 IT 变革,追求软件卓越”、“积极提倡社会和经济公正”这三大支撑 ThoughtWorks 商业模式的核心支柱,这三大核心是 ThoughtWorks 的基石,影响着 ThoughtWorks 所做出的每一项决策。

因此身处 ThoughtWorks,将会提高自己对社会问题的深刻认识,并能够成为富有同情心的公民。


ThoughtWorks 的方法


IDP,咨询、设计&开发和产品演进是 ThoughtWorks 的三大方法。

I:咨询:通过和客户充分写作的 INCEPTION 产出达成一致的产品策略、目标客户画像、体验地图、故事版、核心信息架构、交互原型、估算、交付计划、技术演算、技术架构和选型等交付物,为进入下一阶段项目实际设计和交付做好准备。
D:设计 & 开发:通过迭代式的敏捷交付。
P:产品演进。最终改变发展或重新定义产品。


ThoughtWorks 能做什么


这场活动上,ThoughtWorks 介绍了几个公司内部做过的一些能代表企业文化的项目,来展示 ThoughtWorks 可以做到的方向。

  • “可持续渔业数据库”:为不同利益相关方提供决策依据。
  • “建立数字化平台管理模式”:数据驱动进行有效项目管理。
  • “社会企业初创团队的敏捷试验”:初创社企产品开发中的流程改进。
  • “卓越女生计划”:提供女性在编程行业公平竞争的机会。
  • “医疗物流系统”:ESMS帮助贫困国家医疗建设。

ThoughtWorks 与社区活动


除了传统的软件交付,ThoughtWorks 也一直作为参与者或赞助商为团体争取社会和经济公正,贡献于健康生态系统的建造 —— 公开组织、赞助或参与公共事业和社会运动,ThoughtWorks 相信行动是促进社会和经济公正的关键。

我们不仅仅是一家软件公司,同时也是一个社区:我们汇集满怀激情的软件精英,通过技术和客户共同应对最艰巨的挑战。同时我们寻求IT行业的革新,并致力于对社会产生积极的影响力。

于是极思活动由 ThoughtWorks 发起便不足为奇,面向广大用户举办社区活动。


ThoughtWorks 技术雷达


ThoughtWorks 技术雷达是一份不限行业,技术中立的前瞻性技术报告。它预测技术趋势,小到一个工具和类库,大到平台和架构,而我们已经在不断见证事实的发生。

ThoughtWorks 人酷爱技术。我们对技术进行构建、研究、测试、开源、描述,并始终致力于对其进行改进 – 以求造福大众。我们的使命是支持卓越软件并和掀起IT革命。我们创建并分享 ThoughtWorks 技术雷达就是为了支持这一使命。由 ThoughtWorks 中一群资深技术领导组成的 ThoughtWorks 技术顾问委员会创建了该雷达。他们定期开会讨论 ThoughtWorks 的全球7技1术战略以及和对行业有重大影响的技术趋势。

ThoughtWorks 技术雷达的本质是图形性质,把各种技术项目归类为技术、工具、平台和语言及框架,并将这些技术分为以上四个环反应 ThoughtWorks 当前的态度。


ThoughtWorks 读书雷达


相比于分为“采用”、“试验”、“评估”、“暂缓”四个维度的技术雷达,ThoughtWorks **区社会公正事务(P3)团队为热爱创新的挑战者们推出了以技术、方法论、领域知识和个人发展为四个纬度三个等级的第一版读书雷达,这版读书雷达是通过百余家社会组织投票以及专家、机构推荐而最终推出。选取这四个纬度的原因是许多社创者在创业过程中总是受限于技术和产品化思维的壁垒,而互联网发展的今天, IT 是创新者的必备工具,精益、敏捷或者设计思维都是不可或缺的方法,领域知识的必需以及个人成长的软技能是根基。这个特别针对致力于公益领域的创新者以及社会创新的热爱者所推荐的读书图谱,利用雷达的特点和优势来展现个人读书的广度和深度,为每一个致力于公益领域创新的非技术背景的伙伴们提供从入门到高级的进阶读书计划,让社会领域创新不再陌生!


二、我与 ThoughtWorks


嗨,伙计,我还不是任何公司的员工,也不为任何公司代言,在这里,我为什么大篇幅详细介绍 ThoughtWorks ,这背后到底发生了什么?


我的格言


在一年的大学生活、软件工程专业和互联网行业的感悟中,自己渐渐悟出了这么一条道理:

在这个信息爆炸的时代,重要的不是掌握多少信息,而是认识多少承载信息的人,并努力成为其中一个。

科技日新月异,作为有志向的大学生到底该学习什么一直是一个很有挑战性的问题。相比于国内高校较为落后的学生工厂流水线式培养(至少我这么认为),是那些互联网公司对人才的极致需求刺激到了我们去勇于冲破现状。因此回归到我的格言之中,不用刻意去追求该学什么,而要多去看看那些正在自己所想要参与的行业之中搅动风云的人与事,并努力成为其中一个。

而在这个阶段影响我最深的,不是常念的 BAT,而是 ThoughtWorks。


卓越女生计划 & 思沃学院


刚才在“ThoughtWorks 能做什么”之中一笔带过的卓越女生计划,才真正改变了我的一生,短短几个月,将我本以为认知广度已深的视野彻底重构,变得更加虔诚。

P.S. 在努力的自我表达之下我是卓越女生计划的第一个男生

在这几个月,也就是总感觉刚刚过去 2015 年暑假里, 我在 ThoughtWorks 西安邮电大学联合创新实验室和学姐们一起进行不止于前端技能的软技能学习之路。

从培训要点可见

卓越女生计划便属于思沃学院,更多的介绍在我的另一篇文章之中。

《思沃学院所带给我们的》


三、极思伙伴


技术社区联动公益行业。在这场极思西安活动之中,邀请到的极思伙伴分别来自于儿童幸福家园与陕西众益社会组织服务中心。

由于这是我的第一次基于社区活动的文章总结性分享,活动之中没有及时要到分享课件甚是遗憾,值得以后注意并改进。

其中儿童幸福家园介绍了**未来人力资源的需求和大脑的发育存在敏感期,致力于在婴儿时期让孩子的身心发展达到极致。

  • 2011 年**只有 24% 高中毕业率
  • 2035 年**要达到发达国家高中毕业率 79%

四、用技术改变世界 — UNICEF的技术创新之路


战争、灾难、贫穷、残疾、饥荒、夭折、剥削、性侵、疾病、童子兵。这些自己曾经看似遥远的概念真真实实地被讲师摆在了眼前。在非洲,依然大量存在以上现象,值得 UNICEF(联合国儿童基金会)倾力付出。


童子兵


当他们放下武器时,和我们周围的孩子一样,天真无邪。

在深刻感悟这句话之前,先看一组数据。

  • 2012.1~2013.9 刚果国家新增 1000 名童子军。
  • 2007年非洲有 12 万童子兵。
  • 过去三年南苏丹新增 9,000 童子兵(UNICEF 深入摸底,真实情况会更多)

还有专门的“尼翁尼”儿童营来统一训练童子兵,将他们送上战场最前线。

喜欢《比利·林恩的中场战事》电影的朋友,当理解比利·林恩身为一个成年人在战场上的一切看似英勇的行为对他自己到底意味着什么的时候,再想想这些童子兵,也便知道“用技术改变世界”分享活动的意义。这些,都还真实存在于非洲。

时而得到解放,时而再次被强行招募,不幸的话,便死于战争之中。


UNICEF 的行动


UNICEF 中文名联合国儿童基金会,于1946年12月11日创建,最初目的是满足第二次世界大战之后欧洲与**儿童的紧急需求。1950年起,它的工作扩展到满足全球所有发展**家儿童和母亲的长期需求。围绕非洲童子军情况,UNICEF 人员曾多次实地考察统计,登记、汇总儿童信息,最终根据信息分配资源。

可以看到,在繁琐的人工登记、汇总儿童信息的过程中,产生了很多问题。资源浪费,统计信息不全面,可能因为字体、方言等原因影响记录。


ThoughtWorks 给 UNICEF 提供技术方案


在优化 UNICEF 对非洲儿童的救援流程之前,ThoughtWorks 总结了 UNICEF 之前的流程样子:线下录入儿童信息,汇总文档,录入计算机,上传到分办公室,上传到总办公室,电话联系家长,家长与儿童会面确认关系,家长找到孩子。

正如刚刚所说,最早社区员工的纸质版当面收集录入存在语言障碍、手写笔记障碍、资源浪费等问题,完全可以得到如下改善。

改善后,社区员工收集信息统一用英文到离线录入到手机(手机上网络状况不好,需要到当地办公室上传,最终汇总到全国总办公室),每当有新小孩信息出现,服务器立刻匹配父母信息,每30分钟再匹配一次,找到小孩速度大大提高。同时服务器对信息加密,不会被人贩子轻易翻译。


远远不止这些


这场分享给了我们一个更加认识 ThoughtWorks 的途径,但不只是刚才提到的给 UNICEF 提供技术方案,还有如下类似项目:

  • 非洲物流在线管理系统,将物流数据可视化,方便合理分配资源。

  • 麻疹趋势监控系统,方便监测疾病。
  • 学生信息收集、课程管理系统,方便改善教育和统计学生信息。


ThoughtWorks 愿景



五、同理心与用户研究


用户研究是用户中心的设计流程中的第一步。它是一种理解用户,将他们的目标、需求与您的商业宗旨相匹配的理想方法。用户研究重点工作在于研究用户的痛点。

对公司设计产品来说,用户研究可以节约宝贵的时间、开发成本和资源,创造更好更成功的产品。对用户来说,用户研究使得产品更加贴近他们的真实需求。通过对用户的理解,我们可以将用户需要的功能设计得有用、易用并且强大,能解决实际问题。


用户研究在商业领域的应用


  • 产品前期—市场视频、商业策略、用户偏好
  • Demo验证—打造产品细节
  • 产品上线—品牌推广、核心卖点
  • 产品迭代—可用性、新的需求探索

想象你要制作一款角色扮演类游戏,用户研究便先要提前定位游戏将会有哪些人来玩,规模有多大;再进一步向玩家提供 Demo 验证想法是否正确来降低开发成本;最终执行产品开发和上线并进行产品迭代。


用户研究在互联网领域的应用


在互联网领域内,用户研究主要应用于如下两个方面。

  • 对于新产品来说,用户研究一般用来明确用户需求点,帮助设计师选定产品的设计方向;
  • 对于已经发布的产品来说,用户研究一般用于发现产品问题,帮助设计师优化产品体验。在这方面,用户研究和交互设计紧密相连,所以你还需要了解一下交互设计的基本知识。

因此,用户研究核心要点


  • 理解需求—判断核心问题是什么
  • 选择方法—选择最合适的调研方法
  • 具体执行—项目管理、高效执行、专业严谨
  • 结果呈现—逻辑严谨、深入浅出

用户研究对 NGO 的帮助


NGO 组织(非政府组织)作为在公共管理领域作用日益重要的新兴组织,也要进行用户研究。每一个 NGO 从业人员都能从用户研究之中找到用户真正的需求,提供更适合的解决方案。

毕竟,贫穷的孩子最需要的不一定是良好的住行,更可能是父母的关怀。


第一步:同理心


先看一个短片,同理心的力量。

同理心的力量 -- 优酷

这个短片告诉我们,同理心是站在别人的立场思考。当一个人感觉悲伤时候:

同理心:(正确):我能感受到,你并不孤单。

同情心:(错误)很难受吗?来块三明治吧。

在这里你是否会心一笑?然而真正能做到并不简单。同理心的四个特点。

  • 接受观点,或者认同他人的观点
  • 不加评论,人们很难做到
  • 看出他人的情绪
  • 尝试与他一起感受

同理心是与他人一起感受,连结感受,同情心则促使失去连结。


用户研究的重点


用户研究的重点应该聚焦在“如何探索用户故事”和“如何梳理用户需求”两点上。

正如冰山一角

在一场有关“收音机”的研究上,相比普通黑色的收音机,用户都表示对黄色收音机的好感,而等到活动结束可以随意拿走一个收音机的时候,绝大多数用户却选择了质感更好的黑色收音机而没有选择像玩具一样的黄色收音机。

因此,用户说的 ≠ 用户实际做的 ≠ 用户心里想的。这也是我们每一个人的交流特点。


用户研究方法


下图是心理学常用的研究方法,定性与定量研究。

可见,定性研究(如用户访谈)关注于背后最真实的原因,而定量研究(如数据分析)则关注于统计数据。

其中桌面研究是指快速了解行业以及尽早发现项目需求及风险的低成本方法,通过阅读大量文献、文档、国内外先进案例以及最佳实践来完成。


用户访谈


用户访谈属于定性研究,除了问问题,还可以观察用户对每一个问题的反应和情绪,同时对每个答案保持好奇,深入理解“为什么”。有经验的用户研究人员对用户访谈的要求很高,包括如下要点。

  • 了解用户的基本情况
  • 了解用户的兴趣点
  • 了解用户的痛点
  • 了解用户的使用场景
  • 了解用户的期待

用户访谈过程中随着时间的流逝访谈流程也在变化。

用户访谈的要点。

  • 对访谈目的要清晰
  • 不要对用户有偏见
  • 降低姿态
  • 了解用户的真实目的
  • 在发生地访谈
  • 留心用户修改言论的时候
  • 让用户说自己的体验,讲故事
  • 需要的不是完整的解决方案

实践环节,邀请两位志愿者围绕了解用户的运动经验来充当用户访谈中的双方角色。你喜欢运动吗?喜欢便可以继续,不喜欢也可以因为用户不得不上体育课等习惯来深入交流。

在用户访谈中,建议这样做:

  • 问开放性问题
  • 不要预设立场
  • 多问上一次的经验
  • 多问一个为什么
  • 让用户多讲讲他们的故事

免干扰观察


这种观察是建立在不打扰被观察者,或是被观察者不知情的情况下发生的,好处是让观察者接触到用户最自然的表现及使用过程。


浸泡式体验


这种体验是观察者或者设计人员作为体验者,亲身去体验整个服务流程当中的特征与痛点。设计人员通过自身的专业敏感度来发现一般人已经习以为常的习惯。


如何梳理用户需求


那么,如何梳理用户需求?在听到“我想要一匹更快的马”的时候,到底用户是想要更快还是想要快马?亨利福特发明的汽车灵感便来源于此。


用户定位和产品定位


然而一辆汽车并不适合所有用户,需要进一步的对用户和产品进行重新定位。李磊想要好玩快速的车,韩梅想要安全舒适的车,小明想要耐用容量大的车。定位之后,便可以进行用户角色画像。

  • 更加专注的从用户角度思考
  • 不要预设立场
  • 做决策时更具同理心
  • 明确产品的出发点

总结


  • 同理心:站在用户的立场思考
  • 依照状况,用访谈、观察、浸入式等方法探索用户故事
  • 不要马上想解决方案,梳理需求找出可以切入的点
  • 利用用户角色画像帮助团队沟通与确定产品定位

六、ThoughtWorks 协同创新的服务设计


服务遍布在生活的每一个角落,是有效的计划和组织一项服务中所涉及的人、基础设施、通信交流以及物料等相关因素,从而提高用户体验和服务质量的设计活动。服务设计将人与其他诸如沟通、环境、行为、物料等相互融合,并将以人为本的理念贯穿于始终。协同创新多为(组织)企业内部形成的知识(**、专业技能、技术)分享机制,特点是各独立的创新主体拥有共同的目标、内在动力、直接沟通、依靠现代信息技术构建资源平台,进行多方位交流,多样化协作。协同创新的服务设计将两者有机结合起来。


麦当劳的服务体验


作为一名吃客,在麦当劳的点餐过程中,我们体验到了什么服务?前台有顾客与服务提供者的直接互动,后台支援前台服务的流程/人员/设备。可见,服务不止于人,还有物。

画出麦当劳的服务蓝图。


产品与服务的差异


产品是被制造、物质的、可触及的、可被存放的、通常没有与客户的互动、因为制作而有瑕疵。而服务是被执行、被制造、不可触及的、不可被存放的、需要与顾客互动、因为行为而产生错误。


服务改变传统产品提供方式


从打印机销售到企业影印服务,从捕鼠器到除虫服务,服务在改变传统产品提供方式的道路上一直前行。


顾客的服务接触点


服务设计作为以实践为主导的行业常常致力于为终端用户提供全局性的服务系统和流程,其关键便是“用户为先 + 追踪体验流程 + 涉及所有接触点 + 致力于打造完美的用户体验”。


服务设计流程


设计思考教会我们的是从商业、技术和渴望到设计创新。

设计思考也可应用于公益服务(NGO 组织)。


设计服务工作坊 -> 解决人口老龄化问题


工作坊正式开始,我们有趣的故事都在这里。

联合国对**人口曾作出如上预测,可见**老龄化问题持续加重,如何利用协同创新的服务设计理念改善这个问题值得我们思考。

那么,一起看一位普通老人 Robert 的纪录片,来了解他的故事,分析他的需求。

可以从饮食、服装、居住、交通、教育、娱乐、生理、心理、工作等方面分析。

将发现写在便利贴上并分类贴上。

可见 Robert 老人可列举出如下特征,便于理解。

  • 姓名:ROBERT
  • 年龄:90岁
  • 性别:男
  • 工作:已退休
  • 性格:容易伤感
  • 生活目标:维持身体健康,有人可以互相陪伴
  • 挫折:交通不能自理、两个亲密的伴侣相继过世、去超市的时候能买少量的东西
  • 喜欢的品牌:Nike、Walmart
  • 生活特点:锻炼、吃饭时看报
  • 生理:老年性黄斑病变、眼睛视力糟糕、痛风
  • 饮食:做饭自理、喝咖啡、吃药

最终画出 Robert 的用户画像,用动词描述需求。

我们 TOP.ONE小组对 Robert 进行用户画像的产出~

在分析 Robert 的需求中要时刻“脑力激荡”,大胆产生大量的点子,不用在乎点子品质好坏与逻辑思考。脑力激荡过程中贯彻“追求数量”、“拒绝批评”、“自由联想”三大方向。在 100 个点子之内,最一开始 60 个点子内有 5 个真正是新的或好的点子。接下来 20 个除了好笑之外没有什么用。但是第 80 个到第 100 个点子中有 10 个会非常惊人。还好我们没有在 60 个点子就停住。

最后,举行一场电梯演讲,快速介绍自己对 Robert 构建的项目大纲,获取大家认同。


七、极思2016西安活动结束,技术联动公益持续进行


这便是这场与众不同的极思活动,拓宽了我们的视野,也带给了我们很多有趣的知识。期待自己之后的努力,让自己未来真的能用技术参与到公益与开源之中。

[A03]原码反码补码与位运算

一、机器数和真值

  • 机器数(computer number)是数字在计算机中的二进制表示形式
  • 机器数有 2 个特点:一是符号数字化,二是其数的大小受机器字长的限制
  • 比如:十进制中的 +6,计算机字长为 8 位,转换成二进制就是 00000110,如果是 -6 ,就是 10000110
  • 这里的 00000110 和 10000110 便是机器数
  • 因为第一位是符号位(正数该位为 0,负数该位为 1,0 分 +0 和 -0),所以:
    • 8位二进制数的取值范围就是: [1111 1111, 0111 1111]
    • 机器数的形式值就不等于真正的数值。
    • 为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。
    • 比如:0000 0001的真值 = +000 0001 = +1, 1000 0001的真值 = –000 0001 = –1

二、原码,反码和补码的基础概念

对于一个数, 计算机要使用一定的编码方式进行存储。原码, 反码, 补码是机器存储一个具体数字的编码方式

[+1] = [00000001]原 = [00000001]反 = [00000001]补
[-1] = [10000001]原 = [11111110]反 = [11111111]补
  1. 原码:原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值
  2. 反码:正数的反码是其本身;负数的反码是在其原码的基础上, 符号位不变,其余各个位取反
  3. 补码:正数的补码就是其本身;负数的补码即是在反码的基础上 +1

由此可见,正数的原码反码补码都是自身,负数的反码,补码都无法直观看出其数值,需要转换成原码再计算其数值

三、为什么要使用原码,反码和补码

对于计算机,加减乘数已经是最基础的运算, 要设计的尽量简单,而让计算机辨别"符号位"显然会让计算机的基础电路设计变得十分复杂。于是人们开始探索将符号伪参与运算,并且只保留加法的方法

若用原码计算十进制减法:1-1=0,结果是不正确的:

1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2

使用反码时,结果的真值部分正确:

1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0

而反码的问题在于 0 上,反码中会有 [0000 0000]原=+0 和 [1000 0000] 原=-0两个编码表示0,于是出现了解决这一问题的补码 [1000 0000补(8 位二进制机器数中,补码还能够多表示一个最低数 -128=[1000 0000]补 ):

1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原

四、原码,补码,反码再深入

  • 再次推荐张子秋有关原码反码补码的博客,里面还讲了同余的概念与负数取模,自己也就不摘抄了。。
  • x mod y 等于 x 减去 y 乘上 x 与 y 的商的下界
  • 一个数的反码, 实际上是这个数对于一个膜的同余数,而这个膜并不是我们的二进制, 而是所能表示的最大值
  • 由于 0 的特殊情况, 没有办法表示128, 所以补码的取值范围是 [-128, 127]

五、数据溢出测试

六、位运算的运算说明

& 按位 与「AND」

功能:对应的两个二进位 均为1 时,结果为 1,否则为 0
例子:9&5 = 1001&0101 = 0001,即 9&5=1
*规律:二进制中与 1& 保持原位,与  0& 为0

| 按位 或「OR」

功能:对应的两个二进位 只要有一个为1 时,结果为 1,否则为 0
例子:9|5 = 1001|0101 = 1101,即 9|5=13

^ 按位 异或「XOR,EOR」

  • 功能:对应的两个二进位 不相同 为 1,否则为 0
  • 例子:9^5 = 1001^0101 = 1100,即 9^5=12
  • 规律:
    • 同一整数 相异或 为0,例:5^5=0
    • 不同整数 相异或 结果和顺序无关,例:5^6^7 = 5^7^6
    • 任何数 和 0 异或 结果不变,例:x^0 = x
    • 综上,x^y^x = x^x^y = 0^y = y

~ 按位 取反「NOR」

  • 功能:对整数的 每一位取反,符号也位取反「取反:0取反为1,1取反为0」
  • 例子:~9 = -10(因为负数是补码存储的)
~9=~[00001001]原=[11110110]补=[11110101]反=[10001010]原=-10

<< 左移(shl)

  • 格式:整数<<左移个数
  • 例子:x << n
  • 实质:x * 2n
  • 操作:把 x 的二进制位 向左移动 n 个单位,高位丢弃,低位补0

>> 右移(shr)

  • 格式:整数>>右移个数
  • 例子:x >> n
  • 实质:x / 2n
  • 操作:把 x 的二进制位 向右移动 n 个单位,低位丢弃,符号位不变
  • 注意:符号位也跟着移动, 右移不改变整数的正负, 最后符号位要调整为原来的数值
  • 正数 符号位为 0, 最高位补 0
  • 负数 符号位为 1, 最高位补 1

七、位运算的简单应用

##(& 按位 与「AND」)奇偶判断

  • 取模判断:a%2?printf(“奇数\n”):printf(“偶数\n”);
  • 与壹判断:a&1?printf(“奇数\n”):printf(“偶数\n”);

##(^ 按位 异或「XOR,EOR」)数值转换

  • 借助第三方变量:temp = a;a = b;b = temp;
  • 不借助额外空间,数学法:a = b - a;b = b - a;a = b + a;
  • 不借助额外空间,位运算:a = a ^ b;b = a ^ b;a = a ^ b;

(<< 左移 和 >> 右移)优化乘除法效率

  • a shl b 的值等于a乘以2的b次方
  • a shr b 比如二分查找、堆的插入操作等等

[A0D]浅谈 C 语言历史

引言

一直想做个技术分享的社区,让我们每个人都有机会把自己学到的编程知识分享出来一起探讨,于是借这次学弟学妹们的入学潮流,我的简书账号正式成立,不定期持续分享,欢迎大家的持续关注与深入交流。

编程是一件很有趣的事情,因为我们可以随心地修改程序来调侃一段人生,亦或写一串饱含诗意的代码向心动已久的女生表白。

while(i.meet(u)) {
    ourStory.begin();
}

那么就从很基础也很长寿的 C 语言历史开始讲起吧。如果你是学弟学妹,那没问题,这里正是一切的开始;如果你是学长学姐,学完 C 语言来这里听听故事,也不失有趣。


C语言的来历

先来缅怀一位前辈,Dennis Ritchie —— C 语言之父和 Unix 之父,计算机及网络技术的奠定者。Dennis Ritchie 于 1978 年出版的名著《C程序设计语言(The C Programming Language)》,推动了C语言的发展和普及,该数至今仍通过不断再版广泛传播。书中用 "hello world" 为实例开始讲解程序设计,也已经成为程序设计语言图书的传统。

Dennis Ritchie

Dennis Ritchie 于 1970 年前后和计算机科学家 Ken Thompson 在贝尔实验室开发出来的 UNIX 操作系统起初是用无数据类型的 B 语言开发,计算机内大部分操作将数据作为整数对待(例如进行+、-、*、/操作),其余操作将作为一个复引用的内存地址。

Ken Thompson (左) 和 Dennis Ritchie (右)

下图为一些早期的高级程式语言的诞生时间线,其中 ALGOL 60 是计算机发展史上首批产生的高级程式语言,标志着程序设计语言成为一门独立的科学学科,并为后来软件自动化及软件可靠性的发展奠定了基础。ALGOL 60 语言基础上设计出了 CPL,CPL 基础上设计出 BCPL,B 语言便是简化 BCPL 后取首字母 B 命名而来。

早期高级程式语言家族

由于 B 语言过于简单以及数据无类型的弊端,Dennis Ritchie 和 Ken Thompson 在 B 语言的基础上设计出了 C 语言,C 语言更加精炼、也更加接近硬件。之后的 UNIX 操作系统便用 C 语言重构,并一直用 C 语言编写至今。

一个有趣的故事是,Ken Thompson 想写个模拟在太阳系航行的电子游戏 Space Travel 玩,身边只有一台没有操作系统的空闲机器 PDP-7,而游戏必须使用操作系统的一些功能,于是 Ken Thompson 开始着手用 B 语言为 PDP-7 开发一个操作系统,后来这个操作系统便命名为 UNIX。这个过程中吸引到了同样酷爱 Space Travel 的 Dennis Ritchie,加入到了 Thompson 的开发项目中。Dennis Ritchie 的开发重心在改造 B 语言,结果诞生出了取 BCPL 语言第二个字母的新语言——C语言。

最后创造操作系统的快乐远远超出了玩 Space Travel 的初衷。

PDP-7

C语言的发展

从下图可以看出 C 语言历史上的几个重要事件,首先是 C 语言于 1972 年在贝尔实验室的诞生,1973 年 Dennis Ritchie 和 Ken Thompson 用 C 语言改写 UNIX 操作系统,再到 1978 年 Dennis Ritchie 正式发布名著《The C Programming Language》,打下 C 语言发展的基石。接下来分别于1990年、1999年、2011年由国际标准化组织(ISO)和国际电工委员会(IEC)推动的 C88、C99、C11 标准,保持了 C 语言的活力,让 C 语言不在历史的潮流中消逝。

C 语言的发展

C语言的特点

诞生时的辉煌可以成就一个语言的开始,但能在历史的潮流中不被淘汰也会要求这门语言持续发扬自身的优点,逐步克服自身的缺点。至今公开的最少
256 种编程语言中,C 语言便是在发扬自身的优点,克服自身的缺点的过程中稳排编程榜榜首前列。

2016年7月编程语言排行榜

以下便是 C 语言常见的几个优点:

  1. 简洁紧凑、灵活方便
  2. 运算符丰富
  3. 数据结构丰富
  4. 表达方式灵活实用
  5. 允许直接访问物理地址,对硬件进行操作
  6. 生成目标代码质量高,程序执行效率高
  7. 可移植性好
  8. 表达力强

而不足之处在于:

  1. 数据封装性不好 -- 数据安全性有缺陷
  2. 语法限制不严格 -- 自由的代价
  3. 缺少支持代码重构的语言结构 -- 面向过程的缺点

一个个字符,随着敲击键盘的哒哒声,经由或是懵懂或是老练的程序员指尖的跃动,最终呈现为显示器上一行行的代码。它们就这样,一行接一行随着回车与换行不停的跳动。那,是眼前这个人悦动的灵魂,它一点一点、一行行慢慢的实现着屏幕前这个程序员的梦想,也一点点,一步步推动着时代的发展,社会的变迁。

[A17]在云上搭建你的个人站点

前注:持续更新中。


SHOW.TIME. 写作背景


前段时间,腾讯云+校园由全国各大高校主动申请过的团队承办,分享课题要求基于腾讯云,“在云上搭建个人站点”和“在云上搭建微信小程序”主题二选一。于是目光转到西邮,由我来当“在云上搭建个人站点”主讲,并于近期写文整理和分享推送。

因此,通过本篇可以

  • 了解云计算
  • 了解云服务器
  • 了解 WordPress
  • 了解腾讯云
  • 学会搭建 LNMP 环境
  • 学会配置 WordPress
  • DIY 你的个人主站

FIRST.BLOOD 认知环节


认知环节

云计算
腾讯云
云 + 校园
云+校园
云端 WP

创建一台主机并登录

云服务器

登陆云主机

购买一个数据库实例并初始化

安装并配置必要的软件


DOUBLE.KILL 腾讯云 UI 界面



TRIPLE.KILL 实操环节



一、安装PHP

yum install php php-common php-cli php-pear php-pdo php-mysqlnd php-pgsql  php-sqlite php-pecl-memcache php-pecl-memcached php-gd php-mbstring php-mcrypt php-xml php-fpm


二、安装 mysql/mariadb

yum install mariadb-devel mariadb-server mysql
  1. 启动mysql/mariadb
systemctl start mariadb
  1. 登录mysql
mysql -u root -p

2.1 创建数据库

CREATE  DATABASE  wordpress;

2.2 创建数据库用户

CREATE  USER   wordpress@localhost;

2.3 设置数据库用户密码

SET  PASSWORD  FOR  wordpress@localhost=PASSWORD("wppassword");

2.4 给数据库用户相应的数据库权限

GRANT ALL PRIVILEGES ON wordpress.* TO wordpress@localhost IDENTIFIED BY 'wppassword';

2.5 更新数据库权限表

FLUSH PRIVILEGES;


三、nginx

  1. 安装 nginx
yum install nginx
  1. 启动nginx
systemctl start nginx
  1. 修改 php-fpm 默认用户
vim /etc/php-fpm.d/www.conf
  1. 把其中的 apache 修改为 nginx
chown -R nginx:nginx /var/lib/php
chown -R nginx:nginx /var/www/html 
  1. 启动php-fpm
systemctl start php-fpm

四、WordPress

wget http://download-10012769.cos.myqcloud.com/wordpress-4.5.3-zh_CN.tar.gz
tar -zxvf wordpress-4.5.3-zh_CN.tar.gz -C /var/www/html
cd /var/www/html/wordpress
cp wp-config-sample.php wp-config.php
vim wp-config.php 

四、填写刚才创建的数据库、用户、密码

rm /etc/nginx/nginx.conf
vim /etc/nginx/nginx.conf
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log;

pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    access_log    /var/log/nginx/access.log;
    sendfile        on;
    keepalive_timeout  65;

    #php max upload limit cannot be larger than this
    client_max_body_size 13m;
    index              index.php index.html index.htm;

    # Upstream to abstract backend connection(s) for PHP.
    upstream php {
      #this should match value of "listen" directive in php-fpm pool
      #server unix:/tmp/php-fpm.sock;
        server 127.0.0.1:9000;
    }

    #
    #
    include conf.d/*.conf;
}
mkdir /etc/nginx/global
vim /etc/nginx/global/restrictions.conf
# Global restrictions configuration file.
# Designed to be included in any server {} block.</p>
location = /favicon.ico {
  log_not_found off;
  access_log off;
}

location = /robots.txt {
  allow all;
  log_not_found off;
  access_log off;
}

# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~ /\. {
  deny all;
}

# Deny access to any files with a .php extension in the uploads directory
# Works in sub-directory installs and also in multisite network
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~* /(?:uploads|files)/.*\.php$ {
  deny all;
}
vim /etc/nginx/global/wordpress.conf   //commond
# WordPress single blog rules.
# Designed to be included in any server {} block.

# This order might seem weird - this is attempted to match last if rules below fail.
# http://wiki.nginx.org/HttpCoreModule
location / {
  try_files $uri $uri/ /index.php?$args;
}

# Add trailing slash to */wp-admin requests.
rewrite /wp-admin$ $scheme://$host$uri/ permanent;

# Directives to send expires headers and turn off 404 error logging.
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
       access_log off; log_not_found off; expires max;
}

# Uncomment one of the lines below for the appropriate caching plugin (if used).
#include global/wordpress-wp-super-cache.conf;
#include global/wordpress-w3-total-cache.conf;

# Pass all .php files onto a php-fpm/php-fcgi server.
location ~ [^/]\.php(/|$) {
  fastcgi_split_path_info ^(.+?\.php)(/.*)$;
  if (!-f $document_root$fastcgi_script_name) {
    return 404;
  }
  # This is a robust solution for path info security issue and works with "cgi.fix_pathinfo = 1" in /etc/php.ini (default)

  include fastcgi.conf;
  fastcgi_index index.php;
#   fastcgi_intercept_errors on;
  fastcgi_pass php;
}
vim /etc/nginx/conf.d/mywordpress.conf
server {
  server_name mywordpress;
  root /var/www/html/wordpress;

  index index.php;

  include global/restrictions.conf;
  include global/wordpress.conf;
}

测试 nginx 配置文件

nginx -t

重新平滑加载 nginx 配置文件

nginx -s reload

nginx 配置

https://segmentfault.com/a/1190000002556269



/etc/php-fpm.d/www.conf

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log;

pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    access_log    /var/log/nginx/access.log;
    sendfile        on;
    keepalive_timeout  65;

    #php max upload limit cannot be larger than this
    client_max_body_size 13m;
    index              index.php index.html index.htm;

    # Upstream to abstract backend connection(s) for PHP.
    upstream php {
      #this should match value of "listen" directive in php-fpm pool
      #server unix:/tmp/php-fpm.sock;
        server 127.0.0.1:9000;
    }

    #
    #
    include conf.d/*.conf;
}

[A0F]编辑器,编译器与集成开发环境(IDE)

引言

为了了解自己在校内建立的编程讨论群里学长学姐学弟学妹的大致比例,在群里做了一个小调查,根据结果来看,处处都恰到好处地映射了我们学校男女的比例—— 2:1 。投票参与人数比例约为 1/8 ,还是有很大的发展空间哈。

群内年级性别调查表

好了切入技术正题,本文我们来浅谈一下编辑器,编译器和集成开发环境(IDE)的区别,并介绍几款常用的编辑器和 IDE,提前掌握开发环境搭建前的知识储备。

编辑器

编辑器的概念很简单,百度百科上这么写道:

编辑器是软件程序,一般是指用来修改电脑档案的编写软件,但也有人称 PE2、HE4(汉书)……等文书软件为编辑器。常见的编辑器有文本编辑器、网页编辑器、源程序编辑器、图像编辑器,声音编辑器和视频编辑器等。

当然在这里我们主要讲的是代码编辑器,一个好的编辑器可以节省开发时间,提高工作效率,它们都能提供非常方便易用的开发环境。你可以用它们来编写代码,查看源文件和文档等,简化你的工作。

以下是一些常用的代码编辑器,每个不同的编辑器都有不尽相同的目标用户群体。

NodePad++

Notepad++ 是一款免费但优秀的代码编辑器,运行在 Windows 环境下,可以支持多种编程语言。它在 50 多种程序、脚本和标记语言上都有着语法高亮、代码折叠等功能。用户可以人为设置当前语言,它还支持实现一些编程语言的API。

NodePad ++

Vim

Vim 是从 vi 发展出来的一个文本编辑器,在程序员中被广泛使用。它支持语法高亮、显示行号,这都是对程序员重要的辅助功能。用户还可以更换界面的主题颜色,减缓长期编程的疲劳感,让代码更加清晰。它可以自动检查你的拼写错误,提高你的工作效率,对于开发者是一个非常好的选择。

Vim

GNU Emacs

Emacs 是一个轻便、可扩展、免费的编辑器,它比其它的编辑器要更强大,是一个整合环境,或可称它为集成开发环境。它可以处理文字,图像,高亮语法,将代码更直观地展现给开发者。Emacs 可以运行在大多数的操作系统上,而且它支持大多数常用的编程语言,可以自动对代码排版布局。Emacs用户可以根据自身的需要和偏好对编辑器进行定制。

Emacs

Sublime Test

Sublime Text 是具有漂亮的用户界面、强大功能和优良性能的一款代码编辑器,你可以在 Windows、OS X 和 Linux 等主流操作系统上安装并使用。

Sublime Text

Atom

Atom是免费开源的文本和代码编辑器,它是运行在 Atom Shell 上,底层依赖的架构是 Chromium(Google Chorome的开源项目)。没有人想浪费大量的时间在配置编辑器上,而在 Atom 上几乎所有的设置都可以通过设置面板来更改配置,简单易用,上手很快。

ATOM

编译器

之前的三种程序设计语言概要介绍过机器语言、编译语言和高级语言的区别,而编译器所做的就是进行这三种语言的互相转换。大多数情况下,编译是从更高级的语言(高级语言、汇编语言)编译成低级语言(汇编语言、机器语言)。

另一种情况是,从他人的可执行程序(低级语言)编译成高级语言,以推导出他人的软件产品所使用的思路、原理、结构、算法、处理过程、运行方法等设计要素,某些特定情况下可能推导出源代码。这个过程叫做反向编译。

一个现代编译器的主要工作流程

这里使用 GCC 编译器的相关概念作出探讨。

GCC 编译器

GCC 原名为 GNU C 语言编译器(GNU C Compiler),因为它原本只能处理 C 语言。后来 GCC 通过很快地扩展变得可以处理 C++ 甚至 Fortran、Pascal、Objective-C、Java、Ada、Go 以及各类处理器架构上的汇编语言等,所以改名GNU编译器套件(GNU Compiler Collection)。

由于 gcc 是命令行程序,没有特定的 UI 界面,我们在命令行可以用 GCC 进行一个简单的 C 语言编译测试,输出一个 “Hello GCC!”。

命令行的 GCC 编译过程测试

集成开发环境( IDE )

可以看到,编辑器是用来让程序员优雅的敲代码,编译器是用来将这些高级语言或汇编语言编译成计算机能直接识别并运行的机器语言。如果我们每次编辑完源程序都要在命令行依托编译器进行函数、模块的链接和编译的话岂不是很麻烦,于是集成开发环境的出现很快的完善了开发效率问题。

集成开发环境(IDE,Integrated Development Environment )是用于提供程序开发环境的应用程序,一般包括代码编辑器、编译器、调试器和图形用户界面工具。集成了代码编写功能、分析功能、编译功能、调试功能等一体化的开发软件服务套。

由于每个 IDE 的针对性不同,承载的编译器不同,不同的语言有时需要不同的IDE,这里介绍几个常用 IDE。

Dev C++

Dev-C++是一个 Windows 环境下开发 C/C++ 语言的集成开发环境(IDE),它是一款自由软件,遵守 GPL 许可协议分发源代码。它集合了 MinGW 等众多自由软件,并且可以取得最新版本的各种工具支持,而这一切工作都是来自全球的狂热者所做的工作。Dev-C++ 是 NOI、NOIP 等比赛的指定工具,缺点是调试(Debug)功能弱。由于起初开发 Dev-C++ 在开发完 4.9.9.2 版本后停止开发,所以现在正由其它公司更新开发,但都基于 4.9.9.2。Dev-C++ 的最新版是 5.11 版本。

DEV C++

Visual Stdio

Microsoft Visual Studio(简称VS)是美国微软公司的开发工具包系列产品。VS是一个基本完整的开发工具集,它包括了整个软件生命周期中所需要的大部分工具,如 UML 工具、代码管控工具、集成开发环境(IDE)等等。所写的目标代码适用于微软支持的所有平台,包括 Microsoft Windows、Windows Mobile、Windows CE、.NET Framework、.NET Compact Framework 和 Microsoft Silverlight 及 Windows Phone。

Visual Stdio

Eclipse

Eclipse是一个界面友好,供各种用户使用的 IDE,它提供了一系列的工具帮助 Web 和 Java 应用程序的开发。尽管 Eclipse 是使用 Java 语言
开发的,但它的用途并不限于 Java 语言。它还支持如 C / C++、JavaScript、Perl、PHP、Fortran、Ruby、Python,甚至 COBOL 语言。它提供很多功能来简化你的开发,内置的工具和 API 支持项目部署、运行和测试。

Eclipse

当然,如果你有你自己最喜欢的代码编辑器这里没有提到,欢迎留言。

[B09]人在西邮 | Linux 兴趣小组免试题攻关指南

1

切记,这只是“指南”,没有一劳永逸,没有舒适区。

new.xiyoulinux.org

时隔一年,2017,看到西邮 Linux 兴趣小组再出新一度的免试题,不免回想起去年大一的自己的经历,虽然当时很多关卡都是学长所指点,也依旧收获满满。这里贴上去年的免试题之我的攻略,作为给大一同学的小科普:

如果问我为什么要写攻略的话~

  • 让大家面对这种套路的免试题不再迷茫。
  • 鼓励 Linux 兴趣小组再创新第一个提出发布免试题的学长最棒

如果问我今年的攻略在哪里的话~

  • 你为什么不自己好好挑战一下呢?2017 免试题
  • 大一写攻略的接力棒,我想传递给你~

2

以下是我去年的攻略原文,曾发布在博客园。

4.28 的宣讲会圆满结束(就在写这段话之前不久),对于西邮Linux兴趣小组这一次纳新,身为局外人表示:还是有历史,还是会玩,还是厉害哈。
华丽的分割线里面是自己之前的攻关战略,最后补充了宣讲会上学长的解释,属于自己的攻关过程之外,但值得记录。
以下攻关内容叙述角度模拟一个人单独挑战时的思考,实则我是在各种指点下与学长共同完成的。。
因此,感谢帮我的学长,还有下方评论区的伙伴@奥尔德赛,对于技术,我们永远是朋友。

FREE OPEN SHARE
 

自己的攻关经历

 
4月伊始,西邮Linux小组为五月纳新进入了前期宣传阶段,免试题一放出,引来各个热爱技术的同学热情挑战。 免试题入门可从西邮Linux小组官网中戳入,或直接点西邮Linux小组2016免试题进入。
本想着从百度进入免试题入口,却意外发现2013年曾有外校学生写过13年的免试题攻略,对小组免试题考察风格有了初步的了解。详见西邮Linux小组2013免试题+继续之战

第一关

首页如图所示,看见START,就立刻戳了进去。 

进去后是一张背景图片,中间写着2006的年份(西邮Linux兴趣小组2006年建立),点击后变成2007,再点击变成2008……到2015年后点击会重新跳到2006。那线索说不定在这里,如果能点出今年——2016,或许会有所发现。 打开源代码,在有关2015的源码下发现

<input type="hidden">

隐藏域,value值为2006,因此点击2015后会重新回到2006的界面,而2006的界面源码隐藏域value的值为2007…… 看来要出现2016的字样,就需要传递2016的value值,在任意年份的页面中将源码中隐藏域value改成2016后提交看看:

<input type="hidden" name="year" value="2006"></input>


修改后点击年份,不出所料,成功过关!

P.S:点击START之前的页面源码中也有相同隐藏域且value=2006,点击START之后跳到2006的界面中,更加证明了第一关需要出现的2016和该
有关。 而在START页面将value直接修改成2016后点击START会怎么样?结果直接到了第二关!

 

第二关

一段名言、一副梵高作的《星空图》和背景的弹琴声是进入第二关首先注意到的三大线索。再没有其它什么显示的,那么应该还需要到源码里面看看。 

分析源码,发现名言、图片之外,背景音乐所用的
标签多了一个,应该不会平白出现的,如图,没怎么接触过音频文件,不知道是.3gpp格式和.eop格式哪个是多余的。 

复制该链接,全部下载出来,发现.3gpp就是背景音乐可以直接播放,而.eop没有相关软件可以打开。 百度 .eop格式 发现这需要拿键盘钢琴软件Everyone Piano打开,下载并打开之。 果然,这个源码中没用到的.eop文件用Everyone Piano打开后在键盘中敲出了线索————一个网址:

www.dreamchasinger.cn/movie/

  

第三关

跟着琴声来到第三关,一部还看不懂的微电影和一串01码,对于01码,西邮Linux兴趣小组2013年免试题第一关不就是这个01码么?老套路试试。

 老套路无果,因为这串01和13年不同的是,中间有空格,莫非是摩尔斯电码?写一个小程序把0和1变成点和横杠再用在线翻译器翻译,发现第四关的入口链接——182.254.246.154。
 如果翻译成乱码的话,是好事,只需改一下编码格式就好。这关打过去时间长了,当时好像用的是base64解码的。

第四关

怪不得纳新群之前有人说K炸,我还水了一句王炸。原来是他早已经打到这一关了,好可怕。

乱提交了一些发现并无用,源码里也毫无破绽,目瞪口呆之际盯着K玩,发现了一个神奇的现象——除了第三张方片国王是褐色胡子的中年人外,剩余三个国王都是白胡子老头!难道有猫腻,下载第三个图片之。下载出来后听说有一种叫“图种”的制作技术,可以将rar压缩文件和一张图片合并起来显示为一张图。那这张图或许就是用图种制作器做出来的——把这张图片名字3.png改为3.rar发现正是一个压缩文件~

如上图所示,压缩文件里面放着1.txt,拉出来名称改成1.exe后发现……是一个贪吃蛇游戏!过关再说。

  

一闪一闪的速成贪吃蛇游戏终于熬到了第四关,果然出现了

IMPORTANT MESSAGE:VHUUEFUDIXQHU 

WHAT??!返回王炸的网页,在输入框输下VHUUEFUDIXQHU后居然还是没反应,那你还IMPORTANT! 好吧,肯定有出路的,不过我暂时就卡在了这里……
 

博客园评论区

评论区伙伴说该输入FREEOPENSHARE,果然到了第5.1关,也是可以从网址直接跳的。

自己的第一反应还是看源码,发现这是用HTML5的Canvas画布编写,由于自己从HTML+CSS直接跳至PHP服务端开发,之前没怎么深入了解过JavaScript,有些吃力。

 但好歹现在也学C,并且JS也是面向对象的脚本语言,根据变量名还是能读出一些寓意的,如图所注释:

 

然而这时离宣讲会开始只剩一小时了,来不及思考了,要开车。
 

看完宣讲会官方攻略后的补充

官方详解如下,和自己的这篇博客相比的话各有优点哦:

其中,第五大关解题源码如下:

#include <iostream>
#include <cstring>
#include <math.h>
#include <cstdio>

using namespace std;

const int N = 25;
int dp[N][N][N][N];
int a[N][N];
int fa[2][N*N] = {};
char ans[2][100];
char str[10000];

int main()
{
    cin>>str;
    int len = strlen(str);

    int row, col;
    row = col = 0;
    int num = 0;
    //将方格数据转化为矩阵
    for(int i=0; i<len; i++)
    {
        if(str[i] >= '0' && str[i] <= '9')
        {
            num = num * 10 + str[i] - '0';
        }
        else if(i > 0 && str[i-1] >= '0' && str[i-1] <= '9')
        {
            if(str[i] == ']')
            {
                a[row][col] = num;
                num = 0;
                if(str[i+1] != ']')
                {
                    col++;
                    row = 0;
                }
            }
            else if(str[i] == ',')
            {
                a[row][col] = num;
                row++;
                num = 0;
            }
        }
    }

    int n = col;
    //动态规划
    for(int i=1; i<=row; i++)
        for(int j=1; j<=col; j++)
            for(int k=1; k<=row; k++)
                for(int l=1; l<=col; l++)
                {
                    int mx = 0;
                    if(mx < dp[i-1][j][k-1][l])
                    {
                        mx = dp[i-1][j][k-1][l];
                    }
                    if(mx < dp[i-1][j][k][l-1])
                    {
                        mx = dp[i-1][j][k][l-1];
                    }
                    if(mx < dp[i][j-1][k-1][l])
                    {
                        mx = dp[i][j-1][k-1][l];
                    }
                    if(mx < dp[i][j-1][k][l-1])
                    {
                        mx = dp[i][j-1][k][l-1];
                    }

                    if(i == k && j == l)
                        dp[i][j][k][l] = mx + a[i][j];
                    else
                        dp[i][j][k][l] = mx + a[i][j] + a[k][l];
                }

    cout<<"the ans = "<<dp[row][col][row][col]<<endl;

    //逆推得到路径
    int cnt = 0;
    int i=row, j=col, k=row, l=col;
    while(1)
    {
        if(i == 1 && j == 1 && k == 1 && l == 1)
            break;
        dp[i][j][k][l] -= a[i][j];
        if(i != k || j != l)
            dp[i][j][k][l] -= a[k][l];

        if(dp[i][j][k][l] == dp[i-1][j][k-1][l])
        {
            ans[0][cnt] = 'U';
            ans[1][cnt] = 'D';
            cnt++;
            i--;k--;
        }
        else if(dp[i][j][k][l] == dp[i-1][j][k][l-1])
        {
            ans[0][cnt] = 'U';
            ans[1][cnt] = 'R';
            cnt++;
            i--;l--;
        }
        else if(dp[i][j][k][l] == dp[i][j-1][k-1][l])
        {
            ans[0][cnt] = 'L';
            ans[1][cnt] = 'D';
            cnt++;
            j--;k--;
        }
        else
        {
            ans[0][cnt] = 'L';
            ans[1][cnt] = 'R';
            cnt++;
            j--;l--;
        }
    }

    //输出路径
    cout<<"load_one > ";
    for(int i=0; i<cnt; i++)
        cout<<ans[0][i]<<" > ";
    cout<<"end"<<endl;

    cout<<"load_two > ";
    for(int i=cnt-1; i>=0; i--)
        cout<<ans[1][i]<<" > ";
    cout<<"end"<<endl;

    return 0;
}

3

读完后,还可以看看前几个月的百度前端技术学院热身赛之我的攻略,你就知道为什么我说这是“套路”了~

有趣的百度前端热身赛@2017

也可以参考纯 URL 过关的智力游戏:Nazo_Game 找找灵感

Nazo_Game 官网

[B05]PHP 中的 cURL 爬虫实战基础

最近准备入手 PHP 爬虫,发现 PHP 的 cURL 这一知识点不可越过。本文探讨基础实战,需要提前了解命令行的使用并会进行 PHP 的环境搭建。

cURL 的概念

cURL,Client URL Library Functions,是利用 URL 语法在命令行方式下工作的开源文件传输工具,被广泛应用在 Unix、 Linux 发行版本中,并且有 Win32、Win64 下的移植版本。常用的 cURL 库 libcurl 支持 http、https、ftp、gopher、telnet、dict、file 和 ldap 协议。libcurl 同时也支持 HTTPS 认证、HTTP POST、HTTP PUT、 FTP 上传(这个也能通过PHP的FTP扩展完成)、HTTP 基于表单的上传、代理、cookies 和用户名+密码的认证。

cURL 官方文档

简而言之,cURL 便是客户端发起的,支持绝大多数互联网协议族的,能对网络文件进行下载或上传的管理程式。

命令行下的 cURL 能做什么

爬取网页源代码

打开命令行,输入如下命令,可以向百度服务器发送获取首页源代码的请求,> 命令将源代码输出保存到当前目录的 baidu.html 下。

curl https://www.baidu.com > baidu.html

获取表单 · GET 或 POST 方法

网页中的

标签常用来生成一个表单。当我们点击表单中的提交按钮时,浏览器会讲所有表单中填入的参数分析并包装,最终用指定的 HTTP 方式发送到目标网络地址。

如下所示代码将用户在输入框填写的参数信息 加入 URL 地址之后,并向目标服务器下的 judge.php 发送 GET 方法。GET 方法中,值和表单内各个字段一一对应。

<form method="GET" action="judge.php">
    <input type=text name="year">
    <input type=submit name=press value="OK">
</form>

GET 方法中的参数会出现在 URL 地址中,因此,我们同样在基于命令行 cURL 下模拟这一点。

curl www.example.com/judge.php?year=1997&press=ok

URL 语法指明,一个通用的 URL 地址格式如下,不难看出,上例代码中的 year 字段及其取值是 的实例。

 <scheme>://<user>:<password>@<host>:<port>/<path>:<params>?<query>#<frag>

与 GET 方法不同的是,HTTP 中的 POST 求求向服务器传送数据,由于常有账号密码等私密信息,这些数据通常加入 HTML Header,而在 URL 地址中不可见,并向目标服务器传送数据。

命令行中 cURL 对 POST 方法的处理方法为 -d 参数。

curl -d "year=1997&press=OK" www.example.com/judge.php

上传文件 · POST 或 PUT 方法

1995年年末,RFC 1867 定义了一种新的POST方法,用来上传文件。主要用于把本地文件上传到服务器。此时页面是这样写的:

<form method="POST" enctype='multipart/form-data' action="upload.php">
    <input type=file name=upload>
    <input type=submit name=press value="OK">
</form>

对应的 cURL 命令中用 -F 作为命令参数如下。

curl -F upload=@localfilename -F press=OK URL

HTTP协议文件上传的标准方法是使用 PUT,此时 cURL 命令使用 -T 参数:

curl -T uploadfile www.uploadhttp. com/receive.php

伪装成指定的客户端

有些网络资源首先需要判断用户使用的是什么浏览器,符合标准了才能够下载或者浏览。此时curl可以把自己“伪装”成任何其他浏览器:

curl -A "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)" URL

这个指令表示 cURL 伪装成了 IE5.0,用户平台是 Windows 2000。

curl -A "Mozilla/4.73 [en] (X11; U; Linux 2.2.15 i686)" URL

此时 cURL 变成了 Netscape,运行在 PIII 平台的 Linux 上了。

以及更多

正如 cURL 的概念一节所说,cURL 的功能除了请求网页、上传文件和伪装,还包括携带 cookie 访问目标服务器(参数 -b)、访问加密的 HTTP 页面(HTTPS)、用本地证书访问需要证书认证的 HTTP 地址(参数 -E)、授权、断点续传、设置代理与网络限速等等,所有网络上的资源都可以用 cURL 访问和下载到。

在 PHP 中使用 cURL

PHP 支持的由 Daniel Stenberg 创建的 libcurl 库允许我们与各种的服务器使用各种类型的协议进行连接和通讯。

为了使用 cURL 函数你需要安装 cURL 包。PHP 需要我们使用 cURL 7.0.2-beta 或更高版。如果 cURL 的版本低于 7.0.2-beta,PHP 将不工作。

要使用 PHP 的 CURL 支持,我们必须用带有 --with-curl[=DIR] 参数重新编译 PHP ( DIR 是包含库和头文件的目录)。

在之前讲到的命令行下 cURL 的实现,我们不难理解 PHP 中 cURL 函数:首先使用 curl_init() 函数初始化 cURL 会话,而后可以设置有关此次 cURL 过程的所有选项,通过 curl_exec() 函数执行,最后我们可以用 curl_close() 函数来结束当前会话,节省资源。以下是慕课网上有关 PHP 中 cURL 过程的图解。

慕课网:PHP中的数据传输神器cURL

安装 cURL

Mac 下自带的 PHP 环境对 cURL 提供了良好的支持。如果不是 Macintosh,或许这些能有所帮助:

通用 Linux 下的 cURL 安装

获得安装包,从网上直接下载或者其他途径,这里直接 wget

# wget http://curl.haxx.se/download/curl-7.17.1.tar.gz

解压到当前目录并进入

# tar -zxf curl-7.17.1.tar.gz & cd curl-7.17.1

配置,指定安装的目录,这里是 “/usr/local/curl”

# ./configure –prefix=/usr/local/curl

编译并安装

# make  & make install

安装完毕,将 curl 命令加入环境变量中。

# export PATH=$PATH:/usr/local/curl/bin

Ubuntu 小的 cURL 安装

Ubuntu 自带的 apt-get 包管理器可以帮我们解决一切依赖。

sudo apt-get install curl libcurl3 libcurl3-dev php5-curl

然后重启服务器,这里是 apache 服务器。

sudo /etc/init.d/apache2 restart

Windows 下的拓展

在 Windows 下安装好 PHP 后,将PHP文件夹下的三个文件php_curl.dll , libeay32.dll , ssleay32.dll 复制到system32下,再将php.ini (c:WINDOWS 目录下) 中的 ;extension=php_curl.dll 中的分号去掉后,重启服务器即可。

开始实战

这里从简单到较为复杂的小 Demo ,循序渐进。

用 cURL 做一个简单的网页爬虫

将如下 PHP 代码保存为 example1.php,并在命令行中执行。

<?php
    $curl = curl_init("https://www.baidu.com");
    curl_exec($curl);
    curl_close($curl);
?>
php -f example1.php > baidu1.html
open baidu1.html

用 cURL 抓去网页信息并替换部分内容

将如下 PHP 代码保存为 example2.php,并在命令行中执行。

<?php
    $curlobj = curl_init();
    curl_setopt($curlobj, CURLOPT_URL, "http://www.baidu.com");
    curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, true); // 只是下载页面内容,不直接
打印
    $output = curl_exec($curlobj);
    echo str_replace("百度", "谷歌", $output); // 将“百度”替换为"谷歌"
?>
php -f example2.php > baidu2.html
open baidu2.html

用 cURL 获取天气信息

将如下 PHP 代码保存为 example2.php,并在命令行中执行。

<?php
    $data = "theCityName=西安";
    $curlobj = curl_init();
    curl_setopt($curlobj, CURLOPT_URL, "http://www.webxml.com.cn/WebServices/WeatherWebService.asmx/getWeatherbyCityName");
    curl_setopt($curlobj, CURLOPT_HEADER, 0); // 不显示 Header
    curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1); // 只是下载页面内容,不直接打印
    curl_setopt($curlobj, CURLOPT_POST, 1); // 此请求为 post 请求
    curl_setopt($curlobj, CURLOPT_POSTFIELDS, $data); // 传递 post 参数
    curl_setopt($curlobj, CURLOPT_HTTPHEADER, array(
        "application/x-www-form-urlencoded;charset=utf-8",
        "Content-length: ".strlen($data)
        )); // 设置 HTTP Header
    curl_setopt($curlobj, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36'); // 伪造一个 HTTP_USER_AGENT 信息,解决为将对象引用设置到对象的实例问题
    $rtn = curl_exec($curlobj);

    if(!curl_errno($curlobj)) {
        // $info = curl_getinfo($curlobj);
        // print_r($info);
        echo $rtn;
    } else {
        echo 'Curl error: ' . curl_error($curlobj);
    }
?>
php -f example2.php > weather.html
open weather.html

本文介绍了 cURL 的基础知识和 PHP 中 cURL 的基础实战,对于更高阶的用法,尽请期待。

[B0F]在崭新的 Windows 操作系统上,前端工程师应该安装什么

Windows 真的不如 Mac 吗?仅以此篇,写给每一次安装一个崭新的 Windows 系统后举足无措的;即使有了 Macbook 也不得不用较大的硬盘空间安装 Windows 双系统的前端工程师们,当然包括我自己。本篇记录那些 Windows 下必不可少的开发者/普通用户工具。

安装 Windows 驱动

由于自己的电脑是 14 年 13 寸的 Macbook Air,通过 Boot Camp 助理制作完 Windows 安装盘并成功安装 Windows 时,需要再到 U 盘里的“BootCamp” 文件夹下双机安装“Setup”文件以自动安装 Macbook 下相关的 Windows 驱动。

其中包括使用 Mac 键盘操作 Windows 的驱动,无线网络驱动等。

安装 Windows 激活工具

从官网免费下载的 Win10 家庭版镜像是未激活的状态,需要我们通过输入产品密钥或使用密钥激活工具来手动激活正版系统。话说不激活也不影响什么?让我不激活先瞧瞧。

P.S:网上下载激活工具或直接搜索激活码均可,例如 TX9XD-98N7V-6WMQ6-BX7FG-H8Q99

安装 QQ 和 微信

国内必装社交软件之二,腾讯出品。崭新的系统即刻装 QQ 、微信可以及时使用截图等功能,接下来较为烦躁的安装各种软件的时间也可以用社交来丰富。

安装 ShadowSocks 并翻墙

在接下来的安装过程中,有些软件需要翻墙,或翻墙后下载速度能更快,因此前期先安装好翻墙工具 —— ShadowScoks,简称 SS。SS 翻墙需要代理服务器的账号、端口和密码等信息,可到各大网站购买 VPS/VPN 服务。

安装 Chrome 浏览器

无论是开发者还是普通电脑用户,Chrome 都是必备默认浏览器,Chrome 生态提供着优质的服务,Chrome 内核的发展也在引领着 Web 技术潮流。通过翻墙软件安装后登录自己的谷歌账号,所有插件、书签无缝跟新至新系统。

安装 Xshell 和 WinSCP

开发者必备远程控制服务器终端的工具有很多,Xshell 和 WinSCP 优先推荐。WinSCP 的特点之一在于图形化文件系统的展示、拖拽上传下载功能,是一个开源的图形化 SFTP 客户端;Xshell 对终端模拟的支持与用户体验更棒。两者可以相辅相成。

安装 Sublime Text、 Atom 和 WebStorm

作为跨平台的图形化文本编辑器的代表之作,Sublime Text 轻小高效,支持基于 Python 的插件,可以通过由社区维护的各类插件包实现定制化使用。多行编辑、自动补全、代码高亮、可以快速在文件间移动以及弹性快捷键等功能吸引了大量的忠实用户,实为推荐。

想必大部分前端开发者都听过、用由 Github 开发的跨平台开源文本编辑器 Atom。与支持基于 Python 的插件不同的是,Atom 支持 Node.js 所写插件,并内置由Github提供的Git版本控制系统。Atom 基于 Electron(最初以 Atom Shell 知名)和许可使用 Chromium 和 Node.js 的跨平台应用框架,并使用 CoffeeScript 和 Less 撰写。同时,Atom 插件也大部分拥有开放源代码授权,对学习如何使用 Node.js 写桌面应用(Atwood 定律的桌面应用实践)、对学习各类 Node.js/JavaScript 等技术如何实现插件功能都是很好的途径,可以说 Atom 是专为前端工程师所生。整体开发流畅度(卡不卡)不如 Sublime。

有了 Sublime Text 和 Atom,JetBrains 公司下的 WebStorm IDE 也得说说。WebStrom 是 IDE (集成开发环境)而非简单的编辑器,内置很多对前端项目良好支持功能比如版本控制、代码重构、终端支持、各类主题以及对业界最新技术的支持等,即使我们可以将 Sublime Text 或 Atom 编辑器配置成如此强大的 IDE,但 WebStorm 显然更为专业,开发前端大型项目时强烈推荐。

安装 Git 客户端

显然更热衷开源的 Web 开发者对 Git 等版本控制工具的热情更大,Windows 操作系统下默认没有像 Linux 一样对命令行的开发环境支持,我们就需要用到 Git 客户端里的 Git Bash,让 Windows 下的命令行开发不再繁琐。

通过 Git Bash,我们能使用 Git 命令来进行版本控制,在安装好 Node.js 环境后能通过 Git Bash 操作 node 命令,本地实现前端项目的构建、部署等。

安装 WireShark

真正的前端工程师是不会止于前端领域,抓包也是必备技能,免费开源的网络数据包分析软件 WireShark 就派上了用场。抓包对理解 HTTP 协议、对实战爬虫项目都有所好处。

安装 jdk 和 MinGW

如果你同时学习、使用 JAVA 语言,JDK 包必不可少。作为 Java 语言的
SDK,普通用户并不需要安装 JDK 来运行 Java 程序,而只需要安装 JRE(Java Runtime Environment)。而程序开发者必须安装 JDK 来编译、调试程序。

同样,如果你同时学习、使用 C 语言,由于 Windows 操作系统默认没有 C 语言编译环境,除了下载 Dev-C++ 这种内部集成 gcc 编辑器的 IDE 外,推荐动手安装 MinGW 作为 gcc 编译器编译环境。各大转行的前端工程师一定要多练练 C 语言,巩固编程基础。

安装 XAMPP 本地服务器软件包

XAMPP = X(任意操作系统) + Apache + MariaDB + PHP + Perl,可见是一个跨平台的服务器环境“傻瓜包”,大前端工程师除了要掌握 Node.js 技术栈,更得学学世界上最好的语言 PHP 来了解服务端编程,XAMPP 提供的本地网页服务器便能让我们暂时无视跟多的服务器、数据库配置,从零学起,快速开发。

SQL Server

Microsoft SQL Server 是由美国微软公司所推出的关系数据库解决方案,最新的版本是 SQL Server 2016,已经在 2016 年 6 月 1 日发布。 数据库的内置语言原本是采用美国标准局(ANSI)和国际标准组织(ISO)所定义的 SQL 语言,但是微软公司对它进行了部分扩充而成为作业用 SQL(Transact-SQL)。 几个初始版本适用于中小企业的数据库管理,但是近年来它的应用范围有所扩展,已经触及到大型、跨国企业的数据库管理。

StarUML

StarUML 是一个开源的 UML 工具列表软件,它遵守 GNU GPL 的一个修订版。StarUML 项目宣称的目标是代替大型的商业 UML 工具软件,如 IBM 的
Rational Rose,Borland 公司的 Together。StarUML支持UML2.0定义的大多数图,但缺少对象图(object diagram),包图(package diagram),时间图(UML timing diagram)和交互预览图(interaction overview diagram)等功能,虽然对象图和包图完全可以通过类图编辑器画出来。

Visual Studio

Microsoft Visual Studio(简称VS)是微软公司的开发工具包系列产品。VS是一个基本完整的开发工具集,它包括了整个软件生命周期中所需要的大部分工具,如UML工具、代码管控工具、集成开发环境(IDE)等等。所写的目标代码适用于微软支持的所有平台,包括Microsoft Windows、Windows Phone、Windows CE、.NET Framework、.NET Compact Framework和Microsoft Silverlight。

PC 版 Visual Studio 下载地址

安装常用普通用户软件

7-Zip 解压缩软件、搜狗输入法、WPS 、极速迅雷、百度网盘、Focusky、网易云音乐 iTunes 和 Kindle 桌面版。

看到这几个软件,普通用户都能懂了吧?基础工具,压缩软件里是否使用 7-Zip,听音乐是否需要网音乐音乐,实则跟自己的喜好所定,而我的喜好,就能从这里看出。

极速迅雷是极简版迅雷,专注下载,官网或许不再提供和继续开发,可以从其他一些地方下载到;WPS 或 Office,显然 WPS 更懂**人;搜狗输入法更能定制化,且跨三大操作系统,和网易云音乐一样对开发者更友好;百度网盘不用多说,云存储、脱离 U 盘等功能各个实用;Focusky 用来做酷炫的 3 维 PPT;从果粉转来的,iTunes 必不可少;常在 Kindle 购书的,Kindle 桌面版简直超棒......还有,优酷、土豆、爱奇艺等视频软件信息量太庞杂,简洁大方的迅雷影音是我的最爱。

娱乐

安装到最后

本来空间就很少而安慰自己是精华的 120 G SSD 空间在通过 BootCamp 安装完 Windows 双系统后被分割的都只剩了不多的空间。Windows 分区总大小为 35 G,安装完上述各大软件后只剩 10 G,未来以来,如何更好的玩下去?

你有什么 Windows 必备的软件推荐呢?

[B0C]概念图图解 Web Cookie

概念图,concept map,作为与心智图(又称思维导图)并列的两大概念绘制工具之一,自约瑟夫·D·诺瓦克(Novak)于 1960 年代发明以来,得到了教育领域和商业领域上的广泛应用。Novak 总结道:“有意义的学习涉及到新概念和命题纳入现有的认知结构的同化”。

Meaningful learning involves the assimilation of new concepts and propositions into existing cognitive structures

Jan Lanzing 的概念图主页深入阐释了使用概念图的几个目的(翻译的不好请见谅~)。

  • 书写你的想法(头脑风暴等)
  • 设计一个复杂的结构(长文本、超媒体(hypermedia)、大型 Web 站点等)
  • 方便交流与传递复杂的**
  • 用可视化方法整合新旧知识
  • 评估对概念的理解程度和诊断对概念的误解

Concept maps vs. mind maps

一个概念图例子

说到这里,便可以利用概念图的技能深究 Cookie 知识点了。

  • 使用到了 CmapTools 的全平台免费软件。

P.S: 本次 Cookie 深究背景,实验室前端知识点之概念图实战选择了 Cookie。

对 Cookie 进行概念塑性

1

按照阮一峰老师的 JS 标准参考教程所总结的:

Cookie 是服务器保存在浏览器的一小段文本信息,每个 Cookie 的大小一般不能超过4KB。浏览器每次向服务器发出请求,就会自动附上这段信息。

可见,1993 年由卢·蒙特利发明的 Cookie 的存在解决了因 HTTP 协议无状态而无法满足交互式 Web 应用持续发展的需求。有了 Cookie 之后,用户和服务器之间的状态得以保持,产品层面平滑地延伸出了登录、注册、购买物品等实用功能。

2

按照 Cookie 的两种分类依据 —— 存在时间和存储位置,前者分为“非持久
Cookie”和“持久 Cookie”,后者分为“内存 Cookie”和“硬盘 Cookie”。实则“存在时间”和“存储位置”有着相映射的效果。

Cookie 保存在硬盘上,访问位置根据操作系统乃至浏览器的不同而不同,Cookie 保存在内存中,实则是浏览器即使使用 Cookie 的结果。也因此能看出,浏览器提供着对 Cookie 的编程接口。譬如用 document.cookie 可以访问浏览器当前域名下的 cookie 值(结果是字符串),如果访问失败的话,很可能是因为服务器发来的 Cookie 设置了 HttpOnly 属性不能用编程接口读取而只能作为 HTTP 请求头中出现。

3

除了 Cookie 本身的内容,还有一些可选的属性也是可以写入的,它们都必须以分号开头。浏览器向服务器发送 Cookie 的时候,是一行将所有 Cookie 全部发送。浏览器向服务器发送 Cookie 的时候,是一行将所有 Cookie 全部发送。服务器告诉浏览器需要储存 Cookie 的时候,则是分行指定。

Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure]

常见的 Cookie 属性有。

  • Value:它是一个键值对,用于指定 Cookie 的值
  • expires:用于指定 Cookie 过期时间
  • domain:指定 Cookie 所在的域名
  • path:用来指定路径,必须是绝对路径
  • secure:用来指定 Cookie 只能在 HTTPS 下发送到服务器
  • max-age:用来指定 Cookie 有效期
  • HttpOnly:设置该 Cookie 不能被 JavaScript 读取

4

当然,Cookie 也不是万能的,维基百科中提到,Cookie 有如下缺点。

  • Cookie 会被附加在每个 HTTP 请求中,所以无形中增加了流量。
  • 由于在HTTP请求中的Cookie是明文传递的,所以安全性成问题。(除非用 HTTPS)。
  • Cookie的大小限制在4KB左右。对于复杂的存储需求来说是不够用的。
  • Cookie 容易被盗窃和脚本攻击

5

说到这里,我们已经能够画出来 Cookie 的概念图了,从 Cookie 的背景、分类及具体操作都能略谈一二,“有意义的学习涉及到新概念和命题纳入现有的认知结构的同化”,加深了我们对曾为抽象存在的 Cookie 的深刻理解。

推荐一本书

概念图是一个好的工具,能够帮助我们更好的梳理学习内容、及时记录我们的灵感并发挥我们的创造力。这里推荐一本好书:《学习、创造与使用知识 概念图促进企业和学校的学习变革》,正如书名一样,我们可以用概念图学习、创造和使用知识,也能促进企业和学校的学习变革。

《学习、创造与使用知识 概念图促进企业和学校的学习变革》这本书,适用于各位教师、教学设计者、研究者、学生,以及所有的知识产业、政府组织和商业领域的工作者,方便大家对知识的构建与整理。

amazon 入口:学习、创造与使用知识 概念图促进企业和学校的学习变革

[B0E]**首届开发者关系大会分会场 | freeCodeCamp西安线下编程活动体验#06

这个是大一服务端学弟哦 q(´・ω・`)p

那就开始吧!

在和四个实验室 Web 服务端大一学弟的为期俩周的准备下,2017 年 04.08 号这一整天,终于成功举办了这场编程马拉松活动。从最初的简单分享到发现时间不足而拓展成编程马拉松,也终于敲定了活动名称,确定了活动流程。此之谓:

小全栈编程马拉松

如果你还不了解我,不了解这场活动在大学氛围能够成功举办的背景,不妨看看这三篇文章,当然更多的故事在我的简书和微信订阅号之中(@韩亦乐)。

并且整场活动的文章内容在这里:

这场活动在西邮通院科协邀请下,由我所在的 CreatShare 互联网实验室主讲,包括全天流程及其干货内容都由 CreatShare 互联网实验室(其实就是我和四个学弟啦)策划并完善。我是这么形容这场活动对我的意义,其中可见从我的俩个大学实验室到我组织的本地 FCC 西安开源前端(全栈)社区活动,融汇了我俩年的“毕生所学”。

那么不多说,活动流程如下,用 MindeNode 绘制,贯穿 Web 前后端的基础知识点和软技能,激情的开始吧。

最帅的大一学弟没有之一 (´థ౪థ ) ☞

整场活动从前端到后端,首先便是 HTML + CSS 的必备基础内容。我们在这里引入了自己的思考,开启一场独特的“大前端”之旅。

HTML + CSS

](http://upload-images.jianshu.io/upload_images/2558748-f79355886097698c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

以下三个图是从学弟的 PPT 中取材,HTML 可以了解结构和历史,CSS 可以看看选择器和属性,并用流行的 Sublime 编辑器做个 Demo 体验(匹配一下上面第一个学弟帅哥的照片,激发一下学习欲望)。

我做了总结和扩充,从真实世界到前端,从大前端看 Web。

写一个 Demo 解释一下吧~�请忽视我的“高耦合”:

<!-- HTML 标签是由尖括号包围的关键词,比如 <html>,用来描述网页 -->
<html>
    <head>
        <title>这是我的第一个页面。</title>
    </head>
    <!-- Web 浏览器的作用是读取 HTML 文档,并以网页的形式显示出它们 -->
    <body>
        <h1>这是我的第一个大标题。</h1>
        <!-- HTML 标签通常是成对出现的,比如 <b> 和 </b> -->
        <p>这是我的第一个段落。</p>
        <br/>
        <hr/>
        <h2>我比大标题小那么一丢丢</h2>
        <p><a>这是我的第一个链接</a></p>
        <p>别跑,我的头像好帅气</p>
        <!-- 即将插入一个图像,虽然源码的耦合度不同 -->
        <p>![](http://upload-images.jianshu.io/upload_images/2558748-699f535e2b458353?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)</p>
    </body>
</html>

这场名曰“ Web 全栈”的活动,怎么能不讲讲 Web 的背景?

好巧的是,查资料的时候,看到万维网之父刚刚获得图灵奖,实至名归,激动万分。

JavaScript + ChromeDevTool

相比“PHP 是世界上最好的语言”,JavaScipt 应该算是世界上最“全能”的语言了。JS 从最初的网页前端交互到现在的 Web 前后端、移动端混合应用、物联网甚至 AR、VR ,无所不在。毕竟,Atwood 定律告诉我们:

凡是可以用 JavaScript 来写的应用,最终都会用 JavaScript 来写。

https://ppt.baomitu.com/d/e3804f96#

来场实战,想必在座的大学生大多都不怎么关注自己的“专业培养计划”,结合代码实战,来在西邮官网上实战抓取专业培养计划,利用了 JS 的 DOM 操作。

http://222.24.62.120

var v1 = document.getElementsByTagName("table")[2];
var nameArr = [];
var classCount = v1.childNodes[1].childElementCount - 1;
for (var i = 0; i < classCount; i++) {
    var name = v1.childNodes[1].childNodes[i+1].childNodes[2].innerHTML;
    var nature = v1.childNodes[1].childNodes[i+1].childNodes[6].innerHTML;
    if (nature === "选修课") {
        name += "(选)"
    }
    nameArr.push(name);
}
console.log(nameArr.join(","));

是否是选修课也进行了判断,最终获得到四年培养计划的所有课程,短短的 JS 代码避免了多少手工记录,还加深了多少 DOM 知识呢?

发完讲师的照片就跑真刺激。(谁让比他大一级,逃。。

这个是大一服务端学弟哦 q(´・ω・`)p

freeCodeCamp

啊啊啊,这个在线 JS 全栈编程平台向别人介绍的太多了。直接放图和链接吧!在早上的活动最后,向大家推荐了这个全球性开源编程社区平台。

Why...Why...Why always me to create blogs to review and share -- Virgo Me.

除了左下角的各大其他城市线下 JS 编程活动缩影外,其他三张都是我组织的 FCC 西安线下编程活动。认识到了五湖四海的大家。

8 小时的活动~!干货很多,软技能很多,怎么不来点 VIDEO不能白白浪费了免费 Wi-Fi,大大的投影和热情参与的同学们啊,俩个视频来分享。相关链接可以在 Youtube、优酷等国内外平台搜在这里就不给你们贴链接了,劳动劳动更有意义吧~。

从上面的第一个视频可以总结到,今天的程序员是未来的巫师,掌握着改造世界的方法。影片贯穿着生动的全球 IT 牛人变成回忆录:

  • 比尔·盖茨,1955年10月28日出生,13 岁接触计算机,18岁考入哈佛大学,一年后从哈佛退学,接着与好友保罗·艾伦一起创办了美国微软公司。美国富豪400强榜单常居榜首。
  • 杰克·多西,1976年11月19日出生,8 岁有自己的 Machintosh。2008 年 成为 Twitter 联合创始人兼CEO。
  • 马克·扎克伯格,1984年05月14日生于美国纽约州白原市,小学 6 年级开始学编程,2004 年推动 Facebook 正式上线。
  • 克里斯·波什,1984 年出生,美国职业篮球运动员,NBA 全明星。

绝对不会告诉你们的是,《TED 编织我的梦》这部 TED 演讲我在去年面向大一新生的 DIY 电脑俱乐部软件部第一次分享的主讲过程中就放映过,也认识到了这次的几位服务端大一学弟,实则,成功圈粉一大波迷弟。

我们,不要忘记用孩子的视角理解编程世界。

乱入我在去年 DIY 电脑俱乐部软件部主讲的分享文章,和缩影一张。

漫游C世界--DIY软件部编程之旅

秀秀秀 迷迷迷

没办法,我就是爱玩。哎,快大三了,这病,得治。

可能是我的“同性相惜(吸)”的气质太浓重了罢,短暂的午饭和午休过后,到了下午进行服务端分享的时候,早上的女生,就剩通院科协参与组织的了。

迷弟们,你们走吧,我想静静。( ತಎತ)

Full-Stack-Developer

什么是全栈工程师?我们该不该以全栈工程师为奋斗目标?我们又能从全栈工程师的方向中学习到什么?这里凝聚了我的感悟。

详细内容,记得去看看 我的第一个开源电子书:Little-FSD

[github@bmorelli25/Become-A-Full-Stack-Web-Developer](https://github.com/bmorelli25/Become-A-Full-Stack-Web-Developer)

正如精读和粗读,广度和深度也是永远矛盾的话题,先来一波知乎黑。

全栈黑~

当然,我不这么认为,我理解的“全栈工程师”的重点不在于去复古曾经最早的下搞电路设计,中写汇编代码,上知设计模式的“全能程序员”,而是新时代的,拥有极强学习能力的编程“终生学习者”。

公司的事,就是你的事,不要局限在自己的职位内。转译自 Facebook。

从软件工程思考到的全栈工程师从某种角度可以说,就是产品运营、运营经理、视觉设计、前端工程师、服务端工程师,统统吃一口。下图是我在去年为我所在的 CreatShare 互联网实验室纳新准备的组织结构图可以参考。

关于这次活动的技术点,我也快速画在了概念图中,以做头脑风暴:Web 前端,Web 后端,框架、平台、工具、基础知识点等等。。

驾驭头脑风暴

Linux + Apache

从下图链接中学弟的 PPT 中可以学习到,Linux 操作系统的基础知识和用法以及 Apache 服务器的用处、须知。这是我见过的,最详细的 PPT 没有之一。。

git@icorvoh/Little-FSD

偷一张 PPT 放到这里:

PHP + MySQL

PHP。。我的大一便以服务端做为方向,PHP 作为学习语言来学习,在一定的了解过后,前后端的通吃的时间、精神压力下,终于选择了 JavaScript 作为找工作时的重点语言。PHP + MySQL 便是最后一位大一学弟的分享。

git@icorvoh/Little-FSD

可以在 Windows 平台安装 XAMPP 的 PHP 运行环境傻瓜包,或在 MacOS、Linux 下更难更干货地安装开发环境,进行Apache、PHP 、MySQL的深入学习。这里贴一段代码,看看 PHP 怎么链接数据库,So Easy!

<?

$conn=mysql_connect('localhost','root','');  
//状态  
if(!$conn){  
echo "connection failed";  
exit;  
}  
  
//选择数据库  
$sql='use student';  
//conn通道进行  
$rs=mysql_query($sql,$conn);  
//设置字符集  
$sql='set names utf8';  
mysql_query($sql,$conn);  

?>

PHP 当然必须得有收接 HTTP 请求的能力,比如处理 GET、POST 请求:

还可以模拟客户端发送 GET、POST 请求哦,就让爬虫开始吧。

可以用 postman 这类的 HTTP API 模拟工具实战。

真正的 Web 全栈工程师,是不需要依赖浏览器的。 -- 引用自 phantomjs 官网。

架构之战

到了这里,活动也接近尾声,分享的内容慢慢,但后端也只涉及了 LAMP 架构,即 Linux + Apache + MySQL + PHP,常被用来做传统的多页面网站。然而还有 MEAN 架构、.net 等等开发架构,可以幽默的解释为什么我们要学习后端?

MEAN 架构,发扬了 Web 单页面应用的存在需求。MEAN 便是基于 JavaScript 的全栈框架 MongDB、Express.js、Angular.js、Node.js 。freeCodeCamp 在线编程平台便是用 MEAN 架构实现。技术没有优劣性,开发者可以择一而入。

LAMP V.S Node.JS

另外俩个大一服务端学弟也在这里,能看出来吗?就是站着的俩位(逃。

最后俩个大一学弟在哪里 ( _  ͡° ͜ʖ ͡° )_

我,终于,露脸了,围观请打赏~Two Three Three。

我在 DIY 电脑俱乐部软件部分享的回顾文章里就以下面这段话结尾:

分享到最后时间也晚了,教室也要关门了。这次分享结束,但人生未尝不是一次重新开始~

是啊,这次,再一次重新开始,再一次与众不同,期待未来的更加精彩吧!

git@icorvoh/Little-FSD

全栈,是一种心态!

[A18]面向未来<-一位软工男的大一故事

前注:本文写作用时 3 小时 20 min,预计阅读时间 15 分钟。


OUR.STORY.BEGIN.写在前面


当视野越来越广的时候,才真正知道什么叫做“人外有人,天外有天”。我写这篇文章并自运营分享的目的不是展示我有多么厉害,而是想将我的心路历程分享出来,做最好的自己,影响该影响的人。我永远相信,庄子旷达处世的心态背后,一定有过流离失落的感受。人无完人,事实求是并能共同成长才是最理想的成长型社交状态。


LABEL.SHOW.标签展示


10 月中旬的技术社区千人直播分享会上,我用这么一张 PPT 来介绍我自己。

西安邮电大学软件工程专业、CreatShare 互联网实验室服务端开发、ThoughtWorks 西安邮电大学联合创新实验室前端开发,还有此次我作为讲师的身份背景 —— freeCodeCamp 西安社区组织者。

正如青年文摘这几天推出的一篇文章所说,这是一个看脸、看标签的社会,从 CXO (泛指公司高管)到富二代,从明星到网红。很多时候,我们对一个人有几分敬意,都来自于他拥有多少标签。

这段话对于我的真实经历来说,两个重量级实验室成员、开发者社区的组织者等,眼花缭乱的标签,背后有太多的现实意义。

撕下所有标签,我还有价值吗?现在的我并不想直接去回答这个问题,因为在成长的过程中,用一个较好的心态大胆承担即将面对的未来所带来的责任才是我想要的成长状态。也正因如此,像软件工程常常实践先于理论一样,我们边走边瞧。

MUSIC.STRAT.《Wild Wild Web》


CHILDHOOD.REVIEW.童年小回顾


先来一张国庆期间我回家灵感突现摆出来的童年物品图。可以看出,买过很多科幻世界、奇幻世界等杂志、画过画、收藏过游戏王、收藏过三国杀、后两年的高中生活用接近全部的零花钱影院看了 50 多场电影等等。。但很多都很遗憾没有深入。正如最近的状态,Web 前端后端通学,无一精通,还写写文章忙忙自媒体运营。

于是每当我给高中好基友说“你这什么游戏品味嘛!”的时候,只要他回复一句:“你就说你打翻了几个游戏?”,我就无语凝噎~

说这些,都因其为大一的序,童年的终。


I`AM.A.FRESHMAN.大一新生


军训

军训,从初一入学、高一入学到这次的大一入学,从来都没有缺过。有过《军中绿花》的细腻相思,也有《祖国不会忘记》的热血澎湃,最不会缺少那首近乎人人都会唱的《团结就是力量》。由于自己整个高三后的暑假与电脑和梦想相伴(主要做了基于 PHP 框架 CodeIgniter 的班级通讯录网站),军训的第一天一早就直播晕倒。也第一次亲身经历了清醒后发现在被拖着走的电影画面。

坚持到最后再回顾定会有惊奇的发现,比如我们最后的战术汇报表演。

多社团纳新,高调报名,低调退出。

从军训期间校内摆摊、宿舍扫楼开始,社团在大一新生的讨论频率也就逐步火热起来。那是大一新生对社团的普遍感觉是:加入哪个社团就决定即将代表着哪个团体,而到了大都退出社团的大二,回想回想直觉可爱。

在众多的社团纳新中,或许是因为我自信的缘故,我没有体验过被刷的感觉 —— 一级社团中我选择了社团联合会,兴趣社团选择了计算机院足球队和 DIY 电脑俱乐部都加入成功。生活一下就忙碌了起来。

在我的选择中,只有兴趣社团投入的时间最多。

  • 在足球队中参加过迎新杯和校园杯,体验了很多较为正规的足球训练和足球比赛。我果断选择了门将,源于个人性格也源于体质。可能是我更喜欢高考前和同学每天晚自习上之前踢野球的感觉罢,渐渐的退出了体制化球队,忙碌于互联网中,很多朋友也就很少联系了。

  • DIY 电脑俱乐部是一个很有趣的社团,除了一般兴趣社团都会有的宣传部、办公室等部门之外,还有教学弟 C 语言的软件部和每月举办校内免费维修电脑的维修部。前段时间写的《漫游 C 世界--DIY软件部编程之旅》便讲述了我的 DIY 软件部认知之路,也包括了我上大二后给学弟学妹分享的故事。

DO IT YOURSELF.

  • 大一下半学期才加的西邮 FT 航模社,一加进去就从遥控器到各种零件,狠狠的投资了一把。下图图左便是我在航模社朋友帮助下完成的第一架飞机。其中,我参与动手最多的便是 —— 贴遥控器的彩色贴纸。但由于和我专业挂钩不算紧密,忙碌于专业的我之后也很少有时间去航模社基地,甚是遗憾。

各种竞赛,积极报名,抉择退出。

大一对竞赛还是充满兴趣的,这次回首一看,原来参加过这么多竞赛。

  • 多媒体设计大赛校赛。大一开学大致两月,就有了这个比赛,和计科同学合计三人一起在一周内完成一个网站的在线开发。还是用我高三暑假熟悉的技术栈:BootStrap 前端框架,PHP 渲染前端页面,CodeIgniter 后端框架,新浪云在线编辑。 “励青春,文章分享平台”,我们当时这么畅想。校赛一等奖抱回家。
  • 创青春校赛。“小挑”、“大挑”,在全民创新时代的大学生或多或少都了解过吧。这不,我就被说服并参与进了。创业计划书 + 答辩是重点,我作为技术开发,也就出了产品原型图,可能因为我们组都是大一太年轻,也可能因为评委老师们早已选好获奖的,答辩只是形式,我们最终也只抱了个小奖抱回家。
  • 图论杯。一个插曲,一个公司在校内开的比赛,题目都是指针,顺便推他们的培训,之所以要写出来,毕竟也免费领了个《C 与指针》抱回家。
  • ACM校赛。重量级算法比赛,全球算法比赛盛宴。我走 Web 开发,被同一级的算法高手领着飞,抱了个校赛银奖抱回家。
  • 蓝桥杯省赛。老师推荐过很多次,形象点讲是国产的 ACM 算法竞赛。300 块的报名费着实贵,10 道题答出3个,却也最后领了个省三抱回家。那位算法高手,北京决赛,国二抱回家。

“重在参与”嘛,也就无关成果。但鉴于我现在独特的发展之路来看,再参加比赛会花费更多的时间思考赛制的需要,思考比赛时间和地点的确立等等,会浪费时间在一些对我来说的琐事上,我想抽出更多的时间专注个人 ID 体系成长,不再参与也罢。

如果说简历上很耀眼的是一个人的成就的话,我有更独特的选择。


LABORATORY.LIFE.加入 CreatShare 实验室


实验室才是重点,也是我一直投入时间投入精力存在的地方。

我所在的大学的独特性在于,有很多学生实验室团队。老师作为指导教师,主要靠学长学姐一点点传递给新人。有搞 Linux 的,有搞移动开发的,还有和我气质相符搞 Web 的 CreatShare 实验室。

10 月份的纳新狠狠的把自己秀了出来,大一能上手服务端的并不是很多。也就和社团一样,无视了竞争力,争取到了实验室学习的机会。

CreatShare 互联网实验室 2012 年成立,到现在分为产品运营、运营经理、视觉设计、前端开发和服务端开发 5 个职位,大致涵盖一个 Web 产品开发的整个生命周期(大致哦)。一定要知道,这还只是一个学生实验室哦。放张我绘制的导图。

因此,CreatShare 实验室在大学便给予我很独特的互联网体验。一点一点学习技术的同时还能有一个真实环境去了解互联网公司。最终也就找到了自己适合的去处 —— 技术自运营,欢迎关注。因为我什么都想做,什么都不精通。这并不是要去抨击的性格,而是一个真真实实存在的用户需求。

在 CreatShare 实验室大一的学习过程中,我虽然没有做出多少项目,却也从技术栈、互联网文化等角度拓展了我的整个认知广度。


ThoughtWorks 西邮暑期培训


幸运的是,我有一个互联网行业的哥哥,早早的让我在大学前就奠定“大神”基础步入互联网;幸运的是西邮有一个 CreatShare 学生实验室,恰恰就是专注于 Web 开发,让我对大学充满了积极的挑战心态;最最幸运的是,遇见了 ThoughtWorks ,链接了我的软件工程专业,链接了我的 Web 开发梦,链接了我什么都想干的欲望。我认识的一些 ThoughtWorks 的 IT 咨询师们,熟练各种技术栈的同时,还不忘将人文性的关怀传递和分享,还不忘活跃于各大开发者社区。

大一结束的那个暑假,我便是免费在西邮的 ThoughtWorks 联合创新实验室进行前端学习,也培养了我的各种软技能,我的《思沃学院带给我们的就有说过》:

  • 画图分析(思维导图、UML图、原型图)
  • 团队合作(trello、BearyChat等等工具的高效沟通)
  • 敏捷开发、结对编程(TDD 的高大上概念终于有了实战)
  • React+Redux 和 Node.JS(甚至更多的技术栈)
  • 女性编程的平等机会(有很多前辈正在投入推动其中)
  • 写作能力的提升(才让我快速找到了我的自运营之路)

补一张当时我对自己所学的知识做的思维导图整理。

当然,我的 Github 仓库中和《思沃学院带给我们的就有说过》中还有更多。


WAY.TO.LEARN.我的大一学习方法


那说了这么多,我的大一学习方法到底是什么嘛?

以实验室为中轴的自学驱动,加之以学期内每双周,寒暑假每单周发送总结邮件的惯性能力,再配上换位思考的独特性格。那都不是事。

此学习方法也是像产品一样一点一点迭代出适合自己的模式,路还很长,迭代并没有结束。像最近大二开学参与的社区活动,也改进了自己的学习模式。以后希望能分享出一篇,我的大学学习流程模型。


WAIT.A.MINUTE.文章虽完,大学才开始嘛


无论身处哪一个行业,我想在努力完成行业目标的同时,当一个 Story Teller,做最好的自己,影响该影响的人。欢迎关注和交流。

It must mean something, let`s find it out.

[B06]MEAN 架构下的 FCC | FCC 西安线下编程活动体验 #05

相距 FCC 西安第一次线下编程活动,从 2016 年 09 月 16 日到 2017 年 03 月 12 日,半年的时间,在这个社区,发生了很多很多难忘的故事。身为小小组织者的我,也将很多成长中的“第一次”挥洒到了这里。FCC 西安,伴随每一位开发者茁壮成长。

不是我们跟奇数过不去,反而恰巧,在第一、三、五次,活动办得最有意思也最具干货。就不细细讲来其中的缘由。

这次,FCC 西安进高校,西安邮电大学一个新开的,很棒的大学生创业咖啡馆里,分享编程人♀生。

freeCodeCamp西安第一次线下编程活动体验
freeCodeCamp西安第三次线下编程活动体验

Coffee N Code

1

Icebreaker Games。次次活动都轮流介绍一下自己是不是不清真?能创新,就有不一样的体验。这次分为三个小组,每个人代表自己小组来说出自己的三个爱好或特长,其中一个是假的,其余小组抢答说爱好的人的哪个爱好是假的,答对加一分,答错扣一分。分数最低的小组呢,再来介绍一下自己的家乡和美食馋馋大家。命运,掌握在自己的手上。

每个人的爱好都各有所长,假的那个爱好反而更有趣和调皮。就说说我说的三个真假爱好吧,看看你能猜出来吗?

  • 喜欢读书、编程、游戏和写作。
  • 苦瓜真好吃。
  • 熟悉前端和后台。

答案,最后揭晓。

2

不知道各位 FCC 学员曾经、现在所在的大学与开源社区的合作活跃度怎么样。只要有一双善于发现的眼睛,我相信在工科学校内,都会找到一俩个和开源社区有合作的大学生团体吧?

我们的西邮(选址原因罢,这次参加活动的大部分是西邮学生),就与下图的开源社区有过长期合作,其中,FCC 中文社区,便是我带进来的。祈愿长传。

西邮和开源社区

3

FCC 的介绍每一位 FCC 学员在自己的城市线下活动中相信听过很多次了。这次,切入一个主题,浅谈 FCC 的 MEAN 架构。自己学历尚浅,参考资料外加个人感悟而诉。

MEAN = MongoDB + Express + Angular + Node.js

从上述单词缩写的示意可以看到, MEAN 架构作为全 Javascript 的 Web 开发架构,能够端到端地开发现代的、全堆栈的二十一世纪 Web 项目,有如下特点:

  • (M)ongoDB——采用 NoSQL 的文档数据库,使用 JSON 风格来存储数据,甚至也是使用 JS 来进行 sql 查询;
  • (E)xpress——基于Node的Web开发框架,提供对服务端路由的访问;
  • (A)agular——JS的前端开发框架,提供了声明式的双向数据绑定;
  • (N)ode——基于V8的运行时环境(JS语言开发),可以构建快速响应、可扩展的网络应用。

再对比 LAMP 技术堆栈,详细内容可以独立成章,这里便不细细而谈。

4

干货,绝对的干货。JavaScript 之正则表达式入门。以下内容参考自慕课网的 JS 正则表达式。

^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$

以前,总觉得正则表达式太高端,像汇编语言一样羞涩难懂。看到上面的这串正则,我知道肯定有规则可寻,但只能看懂个 a-z 什么的。好了,不鸡汤了,上更多的干货。

身为开发者,我们一直在默默使用着正则。git add .这种最让我们偷懒的 git 命令一直在使用着。如果你还没用过,FCC 可以带给你这些知识点。

JavaScript 中通过内置对象 RegExg 支持正则表达式。字符串对象 String 也有相应的正则方法。

先用常见的 string.split(',') 为例,在 FCC 上做过题的学员肯定十分熟悉这条语句,其实,string.split(',') 中的 , 会被转做正则,效果等价于 string.split(/,/g); ,意为在全局寻找 , 并将逗号前后的字符串分别顺序放入数组中。

回到 RegExg 对象中,有两种方法实例化 RegExp 对象:字面量和构造函数。

在下图示例中,第二条语句 var reg = /\bis\b/g 用字面量的方式声明了一条正则表达式规则,该规则将在全局(g, global)中匹配所有单独存在的 is 单词。第三条语句进行匹配。看看第四条语句,var reg = new RegExp('\bb\is\\b', 'g') ,实例化一个 RegExp 对象并传入相关参数触发构造函数,第一个参数便是正则表达式,第二个代表该规则将在全局(g, global)中匹配。

可以看到,字面量中,用 // 包裹正则表达式语句,RegExp 对象里,由于是 JS 语句,反斜线 ``` 本身并不代表反斜线而是转义的意思,应该将反斜线用自身转义,\``` 才代表一个反斜线,```\t``` 代表一个制表符,俗称缩进。如下转义常见的字符不止能在 JavaScript 中见到。

转义字符 含义
\t 水平制表符
\v 垂直制表符
\n 换行符
\r 回车符
\0 空字符
\f 换页符
\cX 与 X 对应的控制字符(Ctrl + X)

元字符

正则表达式由两种基本字符类型组成:原意文本字符和元字符。原意文本字符很好理解,在正则表达式中,a 就是要找到 a 字母,但若是看到 [a-z] 那肯定不是匹配 [a-z] 这五个连续的字符了,意思是把 a 字母到 z 字母中所有字母组成一类,只要能匹配到这一类的任意一个就满足匹配规则。[] 便是元字符。

在正则表达式中有特殊含义的非字母字符有,+?$^.|\(){}[]。如果就想用这些元字符本身的意思,$ 就是代表美元符,转义即可:\$

字符类

刚刚提到,“在正则表达式中出现的 [a-z] 是把 a 字母到 z 字母中所有字母组成一类,只要能匹配到这一类的任意一个就满足匹配规则。”,就用到了字符类。一般情况下,正则表达式的一个字符对应字符串的一个字符,而用 [] 来构建一个简单的类。^ 来创建一个反向类。

怎么理解呢?以下两行代码中,第一行将字符串中所有 abc 的字符替换成 X 字符。而第二行则代表将字符串中所有不是 abc 的字符替换成 X,后者便是反向类。

'a1b2c3d4'.replace(/[abc]/g, 'X');
'a1b2c3d4'.replace(/[^abc]/g, 'X');

预定义类

到了这里,[0-9] 便能轻松看懂了。但想要写一个匹配 11 位电话号码的规则,难道连写十一次吗?当然不是,\d 便等价于 [0123456789],d 即代表着 digit。

\d\d\d\d\d\d\d\d\d\d\d 总比 [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] 要好。

常见的其他预定义类还有很多: \D 等价于 [^0-9] ,刚才提到,这是反向类,用来匹配所有非数字字符。\s等价于 [\t\n\x0B\f\r]匹配空白符,\S 匹配非空白符\w 等价于 [a-zA-Z_0-9] 匹配单词字符,包括下划线、横线和数字。\W匹配非单词字符。

\d\d\d\d\d\w,匹配的是什么呢?

量词

当 \d 出现多次时,完全可以用代表数量的量词来替换,十一个\d不如一个\d{11}简单明了。

量词 含义
? 出现零次或一次(至多一次)
+ 出现一次或多次(最少一次)
* 出现零次或多次(任意次)
{n} 出现 n 次
{n,m} 出现 n 到 m 次
{n,} 至少出现 n 次
{0,n} 出现最多 n 次

这时,\d{20}\w\d?\w\w+\d*\d{3}\w{3,5}\d{3,} 便可以达到大道至简的地步,用可视化工具 Regexper 来直观表示如下。

修饰符

之前一直提到 //g 是字面量正则表达式加上 g, global 全局模式查找符合规则的文本,而全局模式是默认关闭的。g 在这里存在,便称作正则表达式修饰符。它可不是元字符。

其它修饰符有:i,ignore case,代表忽略大小写,默认是不忽略的;m,multiple lines,跳过回车符等字符,在多行文本中进行匹配。

JavaScript 中的 RegExp() 方法

test()、exec() 以及 compile()。

  • test() 方法检索字符串中的指定值。返回值是 true 或 false。
  • exec() 方法检索字符串中的指定值。返回值是被找到的值。如果没有发现匹配,则返回 null。您可以向 RegExp 对象添加第二个参数,以设定检索。例如,如果需要找到所有某个字符的所有存在,则可以使用 g 参数。
  • compile() 方法用于改变 RegExp。compile() 既可以改变检索模式,也可以添加或删除第二个参数。

下例代码可以实践这一概念。

分组

经过正则表达式匹配到的文本不一定非得替换,有时我们还需要利用。例如用正则表达式将日期 2017-03-12 变成 03/12/2017 的格式,就需要在找出年月日的同时重新排序,这时便用的到“分组”的概念。

^(\d{4})[/-](\d{2})[/-](\d{2})$

可视化结果如下,看到了group关键字。

上例正则表达式匹配时,用()包住符合匹配规则的对象,这时,第一个被包住的(\d{4})是一个group,会把“年”赋值给$1,月、日便更好理解,分别为$2$3。如何实践?

var reg = /^(\d{4})[/-](\d{2})[/-](\d{2})$/;
var string = "2017-03-12";
string.replace(reg, '替换前:$1-$2-$3, 替换后:$2/$3/$1');

以及更多

到了这里,也仅仅是开始,正则表达式是最需要自己动手去练习的知识点。还有更多的概念如正则表达式的零宽断言、负向零宽断言、注释、贪婪与懒惰等就不细细说来。

5

正则官网实战。FCC 西安社区的主页,第一次公开到大家面前,是这个样子,切合这次分享的内容。并新增环节,在官网上利用 Chrome 开发者工具直接实战,两道题目任你挑战。答案呢,直接就贴在下方了。看与不看,“借鉴”与否,是自己的选择,学到内容就好。

https://freecodecamp-xian.github.io/

6

FCC 线下编程社区不可或缺的环节,编程实战!虽然线上我们可以做,但线下一起在线上做题的体验,你有没有体验过呢?有问题,及时的互帮互助了。

End

我可能有个“假特长”,在上面的破冰活动中,“熟悉前端和后台”当然是还不可能是我的真特长了。一个直奔全栈目标、只有一年半学习时间的 Web 学徒,在“熟悉”面前,更应谦虚为妙。也只是,略懂皮毛罢了。

FCC 西安第五次的活动就到了这里,相比较成都社区举办过的 10+ 次活动和主页开发,相比最早成立的北京社区的整体技术更强性,FCC 西安,还有很多路要走。

在 FCC 这个新兴无校园大学中,怎么毕业,就要看每个学员自己的选择。

[B02]阿拉伯数字转换为罗马数字 | JavaScript 算法实现

昨日,在 FCC 平台整整用了两三小时,才刷出一道 JS 算法题,回首而看,最终的代码也就那么多行,记录过程,写文以促进之后改进,也顺便整理一下自己在 FCC 上遇到问题后的解决思路。

阿拉伯数字转换为罗马数字 -- 做题传送门,来试试~

想看答案的可以直接拉至文章后方~~


数字转换规则


罗马数字我们都不陌生,IIIVIX 等字符见文知意,可是当阿拉伯数字达到百千级别的时候,用什么字母表示?字母的排列顺序又应该是什么样子的呢?下面诺列了几个规则:

基本字符

I、V、X、L、C、D、M

分别代表

1、5、10、50、100、500、1000

计数规则:

  • 若干相同数字连写表示的数是这些罗马数字的和,如III=3;
  • 小数字在大数字前面表示的数是用大数字减去小数字,如IV=4;
  • 小数字在大数字后面表示的数是用大数字加上小数字,如VI=6;

组合规则:

  • 基本数字Ⅰ、X 、C 中的任何一个,自身连用构成数目,或者放在大数的右边连用构成数目,都不能超过三个;放在大数的左边只能用一个。
  • 不能把基本数字 V 、L 、D 中的任何一个作为小数放在大数的左边采用相减的方法构成数目;放在大数的右边采用相加的方式构成数目,只能使用一个。
  • V 和 X 左边的小数字只能用 Ⅰ。
  • L 和 C 左边的小数字只能用 X。
  • D 和 M 左 边的小数字只能用 C 。

可见该字符只适用于 4000 以下的正整数阿拉伯数字。


思路历程


按照规则来说,看来也就是要满足类似如下输入和输出:

首先想到的是找不同字符:最终也就只有 I、V、X、L、C、D、M 这七个字符分别代表几个数字,进行一定的左右顺序排列后完成转换。那么在这里首先要生成一个装有七个元素的数组,这时输入 9 的话,去拼装 I 和 X,输入 97 的话,去拼装 L 或者 C 等等。

var Roman = {
  1: 'I',
  5: 'V',
  10: 'X',
  50: 'L',
  100: 'C',
  500: 'D',
  1000: 'M'
};

就像 97 ,选择从 L (50)向右拼装呢还是选择 C (100)向左拼装,看来要去找输入数字左右两侧有对应罗马字符的数字,例如 97 的左边有代表 'L' 的 50 ,右边有代表 'C' 的 100。

开始设计算法,处处断点跟踪。

function convert(num) {
    if (isNaN(num)) return num;
    var str = "";
    var left, right; // 找到输入数字的左值和右值
    var p;
    for (p in Roman) {
      if (num > p) {
        left = p; // 左边的值一直在跟踪
      } else {
        right = p; // 知道左边的值找到后,左边的值得下一个赋给右边的值
        break;
      }
    }
    console.log("(left: " + left + ")----" + num + "----(right: " + right + ")");
    return str;
}

断点跟踪情况来看。发现确实能找到输入数字左右两边的值。


变得更复杂了,及时收手,重新思考


哇塞,找到输入数字左右两个数字后呢?在之前的转换规则里有说过,最大的罗马数字(例如‘V’),左侧的数字(例如‘I’)代表减少,右侧的数字代表(例如‘II’)增加。这时,罗马数字‘IV’、‘VII’即为阿拉伯数字 4 和 7 了。

当这时只用单个字符左右拼装 3999 的时候,一切都复杂了。

3999 --> MMMCMXCIX

要判断 9 应该转换为 VIIII 还是 IX ,必然会多出很多选择循环分支,变得更复杂了,及时收手,重新查找规律。

原来,像 97 这样的数字,不必纠结于是从 L(50) 开始拼装还是从 C(100) 开始拼装,90 转换成 XC ,7 转换成 VII 即可。看了看别的数字,都是这个规律呢,于是制定出如下对应表,直接查找到 个十百千 的任何一个。

var Roman = [["","I","II","III","IV","V","VI","VII","VIII","IX"],
             ["","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"],
             ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"],
             ["","M","MM","MMM","  "," ","  ","   ","    ","  "]];

3999 就可以理解为:3000 -> MMM, 900 -> CM, 90 -> XC, 9 -> IX 了。

3999 --> MMMCMXCIX


最终算法实现


其实你只用从这里正式看就可以了,前面的情景铺设不利于直接解答你的困惑呢。最终实现功能的函数才只有短短的 8 行。

  • ReverseArr 数组用来将输入数字转换成字符数组后倒序保存,这样 ReverseArr[0] 永远是输入数字的个位数,便于处理。
  • CorrectArr 数组用来将每个 ReverseArr 数组的数字查表转换成对应的罗马数字。
  • 最终返回 CorrectArr 数组经过 join 方法后连接起来的字符串。
var Roman = [["","I","II","III","IV","V","VI","VII","VIII","IX"],
             ["","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"],
             ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"],
             ["","M","MM","MMM","  "," ","  ","   ","    ","  "]];

// 只能转换 4000 以下的正整数阿拉伯数字
function convert(num) {
    if(isNaN(num)) return num;
    var ReverseArr = num.toString().split("").reverse();
    var CorrectArr = [];
    for (var i = 0; i < ReverseArr.length; i++) {
      CorrectArr.unshift(Roman[i][ReverseArr[i]]);
    }
    return CorrectArr.join("");
}

俩小时后的这一瞬间,感动死我了思密达:


�整理自己的思考过程


  • 查看 MDN 文档(重要),MDN 文档由网上所有人参与编辑维护,里面有几乎全部的 JS 对象及其方法的使用用例。
  • 随时 Chrome 开发者工具测试 demo 和调试,处处 console.log “人肉”看状态。
  • 搜索引擎 -- 百度 or 谷歌(辅助),算法这块,到瓶颈之处真不好意思一直不查资料想下去。
  • FCC 微信群,记得“提问的智慧”哦,人人都很忙呢。

[A16]如何写一篇优质的博客

前注:本文写作用时 6 小时,演讲分享一小时,预计阅读时间 8 分钟。


SHOW.TIME. 写作背景


最早是自己高考毕业后,哥哥让我学编程语言(PHP)并要求我坚持每天写总结邮件,随时将自己学到的知识汇总起来,也就跟着指引去博客园建立账号从而开始了我的博客之旅。

一年下来,从博客园到简书的写作之路,使我有了对博客一定的主观感悟。说起暑期建立的简书账号,自己写的几篇文章都得到了老师、学姐学长以及外界朋友较为不错的反响,于是借助 10.25 要举办的校园实验室公开课的机会,将 《如何写一篇优质的博客》 主题抛出来并传递心得,也欢迎一起探讨。


BEFORE.博客初探


--- 什么是博客 ---

在想要切合主题写一篇优质的博客前先来了解博客的故事。

博客,weblog,正式中文名叫网络日志,不同于论文也不同于日记,是继电子邮件、BBS、即时通信之后的第四种互联网沟通工具。很多人都有自己的博客,有人偶尔写一篇博客,有人每天都在写博客,也出现了专职的博客写手,靠博客营生。说它不同于论文和日记,正是在于博客的自由化和公开化 —— 我们每个人可以快速地以网络为载体,以文章为形式发表自己的心得并配上相应的论据;也能够将整个文字凝聚起来分享出去,及时有效轻松地与他人进行交流。

Weblog = Web + Log;

按功能分,有我们常见的基本博客和微型博客即微博;按用户种类能分为个人博客和企业博客;按存在方式又能分为托管博客、个人站点博客和附属博客。每个分类都能从分类标准和名称读出具体寓意。

--- 博客编年史 ---

很多时候,学科即是学科史,行业即是行业史。想知道自己在从事一个什么活动,一定要了解这个活动的历史。博客的发展有三大阶段 —— 萌芽阶段、初级阶段和成长阶段。

萌芽阶段(90 年代中期到 90 年代末期)

追溯博客的源头无疑是一件难事,但源头的故事都集中在二十世纪九十年代期间,随着网络的发展,有人开始尝试搭建自己的站点并获得了不错的推广与反响后将“博客”概念普及开来,直到 97 年 12 月 Jorn Barger 最早用 weblog 这个术语来描述那些有评论和链接,而且持续更新的个人网站,从而到了**有了博客一说。

一个简单生动的第一阶段的编年史如下:

  • 1993 年 6 月,最早博客原型——NCSA的“What`s New Page”网页,罗列了 Web 上新兴的网站索引。
  • 1994 年 Justin Hall 开办自己的个人网页,收集各种地下秘密的链接。
  • 1997 年 12 月,Jorn Barger 最早用 weblog 这个术语来描述那些有评论和链接,而且持续更新的个人网站
  • 1999 年,Peter Merholz 以缩略词“blog”来命名博客,成为今天最常用的术语。

这个阶段还没有形成一定的群体,都是 IT 技术迷、网站设计者和新闻爱好者不自觉、无理论体系的个人自发行为,一切都在悄悄演变。

初级阶段(2000~2006年左右)

2001 年 9 月 11 日惊动全球的世贸大楼遭遇恐怖袭击事件,让博客成为重要信息和灾难亲身体验的重要来源。正是这场袭击,使人们对于生命的脆弱、人与人沟通的重要、最即时最有效的信息传递方式有了全新的认识。对事件最深刻的反思不是出自哪位编者、记者之手,而是在诸多幸存者之中。从此,博客正式步入主流社会的视野。

成长阶段(2006年至今)

之前提到过,作为一种社会交流工具,博客是继电子邮件、BBS、即时通信之后的第四种互联网沟通工具。在新时代中继续发扬自己的光芒。


START.写一篇优质的博客


--- 你为什么要写博客 ---

写作的意义

聪明的人类发明了语言创造了文字,而能将这一切传递下来的便是写作。写作对于自己来说,是思维的凝聚,是人格的升华。写作能让自己在百忙之中找到忙碌的意义,也能锻炼自己的表达能力,对于生活中的辩论与演讲都有很大的帮助。同时如果去写技术类文章的话,也有助于理清解决思路和提升技术实力,最终还能帮到别人,降低社会交流成本,提高笔者与读者的双向影响力。

借用现在的我自己来说,我在大学中同时是两个学生实验室的主力成员,还要顾及编程社区的推动和发展,更不能落下课内知识。这时抽时间去写作去用文字总结自己变让一切有了意义。同时因自己是程序员的原因,技术类文章也锻炼了自己的思维方式,提升了自己的技术软硬实力,和读者互动,了解了更多的故事。

用博客落实写作

日记通常是给自己看的,曝光度有限,而在网络上发布的博客更能吸引到志同道合的人。用博客落实写作的一个最重要的原因便是自己的文章能够得到广大读者的反馈,还不会像论文一样严肃有力。最终博客能展现的除了罗列信息之外,还能加入自己的心路历程分享出去。也因此用博客落实写作便可以是笔者前期写作的源动力之一。

用博客升华自己

这不仅仅能学会如何写博客

通过多读书多提问而产出博客这整个过程,都能够抽离出解决问题、产出成功的方法论。通过写博客升华后的自己,完全可以将这种模式再加上具体情况去落实如何写 PPT、如何写文档、如何表达自己、如何辩论、如何演讲等等。。

有了这些,后回归主题吧!

--- 如何动手写博客 ---

①. 对自己定位

无论多么优秀多么高大上的博客都是活生生的人写的。纵观每一位活跃的笔者都有自己独特的写作风格。就比如我的这篇博客包括近期所写的都先从写作论点背景慢慢铺展。因此一个良好的博客手,首先要明确自己的定位,自己到底在整个博客分享过程中准备承担一个什么性格的“诗人”角色,才能写出真实可信的内容来。

②. 确定目标读者

有了笔者对自己的博客风格定位后,要能知道到底哪些用户能从这篇文章中受益。毕竟没有能符合所有食客胃口的饭菜,准确的定位每一类食客并做出相应的美食才能最大化发挥饭店的特长。写博客便是这样。

最终能够从面向复制粘贴写作到面向读者写作,去感悟最真实的需求 —— 当然需求是自己去营造的,但博客内容要能够时刻回归到需求中来。

③. 确定要写的博客主题

说到需求,其实便是博客主题的具体实例。正如这篇博客想要表达的如何写一篇优质的博客而言,要时刻回顾主题中来,让读者包括以后会重温博客的自己,能真正在这篇博客中找到主题所要表达的效果。

一篇博客主题过多时要学会拆分,避免大杂烩的感觉。这篇博客其实有两大主题 —— 博客介绍和如何写一篇优质的博客,也已经达到了一篇博客主题的饱和状态。

④. 罗列关键字并安排情景剧本

博客是笔者的总结而不是解决(流水账)过程,有笔者的心路历程更能带领读者进入主题。总结首先要能看到明晰的关键字,“一”、“二”、“三”的分类并及时的在后方跟上关键字能给读者对博客很直观的认知,随时知道自己的阅读状态。

有趣的是,生活处处是电影,诉说起来皆剧本。对于博客来说,无论是对于屏幕另一方的读者而言还是对于以后需要重温的自己而言,将整篇博客的写作过程串联起来形成故事链也就能成为剧本的一个具体形式。再拿我这一篇文章举例,刚开始说明最近的状态已经为什么要写这篇博客,接着介绍博客是什么和博客的历史,最后回归主题探如何写作,是整篇博客的故事链和情景剧本。不多说,补一张思维导图,整篇文章的精华所在。

情景剧本思维导图

⑤. 当一位艺术家 —— 用工具辅助写作

看到这篇博客开头的文字云,看到刚刚的整个博客的思维导图,你有没有心动,想着自己的博客要是能够这么漂亮并且能用图片直观的表达自己想说的简直太棒了。这时你可以大胆的将自己定位成一位艺术家,去用已有的各种现成工具去设计一篇博客的叙述流程,也让博客不再显得枯燥。

因此你可以用到文字云绘制工具、流程图绘制工具、思维导图绘制工具将自己的头脑风暴实例化并设计出来。切记要控制好图文比例,并让图、文、颜色、主题等心心相映哦。

也可以找现成别人做好的素材并整理成自己的素材库及时使用。

⑥. 让博客链接世界

博客基于网络,网络需要链接。让读者能从你的博客中链接到更多的世界,链接到更多的故事,这也是博客(网络日志)最吸引人的地方。博客网站的一大特色也便是处处超链接,处处可以跳转。还有一个链接方式就是,从笔者的故事中读到更多人的故事,最后创造读者自己的故事,链接世界的心。

⑦. 了解博客主的故事

我悟出了这么一句名言激励着自己前行,不妨分享出来:

在这个信息爆炸的时代,重要的不是掌握多少信息,而是认识多少承载信息的人,并努力成为其中一个。

我的大学生活已度过十个月之多,虽然没有花太多的时间在学术本身上,却也通过了解软件工程行业里现在正在做出杰出贡献的活生生的人,去了解释到底是谁在做着那些牛逼的事情而得到了自我成长。我的社区经历和视野广度也从此而来。

因此想要写一篇优质的博客就不得不去主动了解博客主的人生故事了。比如加拿大华裔 John Chow 通过坚持写作月入 3 万美元让我自己知道了可以通过博客获取收益,再比如我在简书关注的国内几位业界大 V 每日都在坚持写作,让我自己知道了写作也可以是程序员的必备技能,写作也如此有趣。

最终可以通过思考博客主,而找到自己写博客的源动力。

⑧. 重构 && 迭代

“重构”、“迭代”,一些软件工程方法论,常用于编程上,但这些词汇未尝不能用在博客的写作之中呢?每个人都不是万能的,写出的博客也不会是完美的。大胆的写出来并让自己成为第一个读者找出不足来“重构”博客,最终发布出去经过读者的建议来“迭代”博客,一点一点改进博客。自己写博客的能力也会越来越强。

--- 一篇博客之后 ---

好了,我的博客发布了,我还需要干什么呢?

从阅读量到点赞数到评论数

最早我和很多笔者新人一样,关注的是阅读量。看到几十的阅读量很不开心,看到几百的阅读量才愿意停下转发的步伐。却也发现再多的阅读量还不如读者的点赞和评论,这时候的读者才是用心看完了你的博客,才有了一篇博客应有的效果。

博客是社交网络

之所以说每篇博客要有一定的点赞数和评论数才算达成目标,正是因为博客在网络上的公开性,读者不只是你或你认识的人,而是来自能够链接网络的任何一位可能的读者。因此博客像社交网络一样链接起志同道合的笔者和读者,互相激励对方影响对方,从而交到更多的朋友,了解更多的故事,诉说更多的梦。

博客变现

之前说到只有流量却没有点赞、评论的话不一定能证明文章内容有多么的好,但也只有好的文章才能带来更多的阅读量。而阅读量这个虚拟化的存在,是可以探索出一条变现之路的。无论你是个人站长还是博客作者,都可以通过博客变现来回馈自己的时间和精力付出。

只是切记,要集中精力写博客,集中精力写优质的博客,让广告商、编辑主动来找你进行广告的推广或添加赞助性链接。如果笔者过多的参与到联系广告商的营销环节中的话,对文章质量很可能会放松警惕的。这是一个不好的现象。

回顾并享受这篇博客的所有过程

好咯,发布博客之后可以静静的投稿、转发朋友圈、转发各大群来和大家愉快的聊天了。

出书啦

嗯哼?这篇博客写的太好了?还有很多想写的?读者粉丝已经很多了,想整合一下所有同系列的博客出一本书?在成熟化的博客写作之后,这些都不是问题了。况且很多书籍就是这么出出来的呢!送给你一幅~出书养成之路图。

出书养成之路图


END. 立刻开始你的博客之旅吧!



Thanks


这就我写博客的源动力之一,帮助自己的同时帮助到了大家,很开心!

[A07]C 语言使用 int main 还是 void main

从大一入学刚接触C到现在已满7个月了,虽然刚开始就知道 int main才是标准的写法,但一直没有深刻理解为什么不能用 void main而必须使用 int main

刚好最近有非计算机相关专业学C的同学问我 int mainmainvoid main 有什么区别,便觉得是时候好好整理一番了,于是有了此博客。
 

先简而言之

  1. void 和 int 表明声明不同的主函数返回值,不声明则默认返回值为int整型。
  2. int main可移植性强。
  3. C语言从来没声明过void main,只声明过main()
  4. 抛弃一切用void main编写C程序的习惯!
     

稍微深入

main 函数,又称主函数,作为绝大大部分 C 程序唯一的入口(比如 windows
编程中可以编写一个其他 windows 程序都可以使用的动态链接库(dll)模块,由于 DLL 模块不是独立的程序,因此不需要 main 函数。再比如,用于专业环境的程序-----如机器人中的控制芯片--可能不需要 main 函数),是要求有返回值的,该返回值返回给操作系统来表明改程序的执行状况。

返回 0 代表程序正常执行成功,返回非 0 值代表程序异常结束,因此返回值需要是int整型,于是有了 int main()的规范。如果使用 void main,既声明主函数没有返回值的话,程序随能编译、运行成功,却不利于操作系统判断其状态,这对于由很多 C 程序构成的大型项目来说是可能会是致命的。

尤其从 c99 标准(1999年制定的官方C语言标准第二版)开始必须使用 int main,如果没加 return 0; 语句 C99 要求编译器自动添加(自己写上是个好习惯)。只声明 main 的话系统默认为 int mainvoid main 无论何时都不应该使用因为主函数必须有返回值表明程序运行状态(在很少的代码中最少不使用void main是一个良好的变成习惯)。

学校老版教材推荐编写C程序时使用的 VC6.0 是 98 年的产品,而 C99 标准见名思义在 1999 年制定,因此 VC 不会自动添加 return 0;。Windows 下建议尝试使用 DEV C++ 或 Visual Studio 的 IDE 环境(集成开发环境)写 C 代码。
 

再深入一点

在最新的 C99 标准中,只有以下两种定义方式是正确的:

int main(void){}
//整数类型主函数(无类型)
int main(int argc,char **argv)
//整数类型主函数(整数类型 统计参数个数,字符类型*数组指针至字符[])

如果没有 int main 并且不是 return 0; 的话,编译完C程序后生成了 exe 文件,在 DOS (按下 Windows 键+ r 键后输入 cmd 打开)下用执行该文件的命令时(比如是 1.exe),语句后面加上 && dir 就会发现并没有列出当前目录的列表!(&& 是按先后顺序执行两条命令的连接符,dir 命令在 DOS 下用来列出当前所在文件下的目录列表的~)

为什么没执行成功dir命令呢?正是因为写的C程序没有返回值,操作系统认为程序没有成功执行完毕,因此就不会执行 && 后面的dir命令了…

上面两种正确的定义方式一般接触 C 语言阶段用前者足以,括号里面的 void 指明主函数并不需要参数,而后者:

int main(int argc, char *argv[]);

表明 main 函数返回值为整型,带两个参数,argc为命令行参数的个数,argv为指针数组,前 argc 个指针为参数列表,最后一个指针值为NULL。具体见下方链接。

参考链接和可深入理解C的其它链接:

[A1B]freeCodeCamp西安第三次线下编程活动体验

政法大学对面,西安邮电旁。一个梦幻般的聚会吧里——之前活动通知的咖啡屋网真慢真桑心~~~——freeCodeCamp 西安第三次 Code && Caffee 成功举办。

之前我有在 《freeCodeCamp西安第一次线下编程活动体验》 介绍过我的 FCC 认知之路也分享过一些 Web 开发的学习方法,得到了不错的肯定。我也借此受邀在猿生态·十城·西安站当了一位最年轻的小讲师,分享开源魅力,很是感激。这回,便不再过多阐述前因后果,直接开启我们的 FCC 西安第三次 Coffee&Code 编程之旅吧!


Part.1 破冰 + 自我介绍和分享


有陌生人相聚的地方,就定有破冰环节的存在。破冰环节将我们的注意力吸引到现在,快速培养起互相的默契及信任。这次 FCC 西安活动有远从北郊赶到南郊来的西工大学长,有自学前端并已工作几年的兵哥哥,有考虑从南京回西安发展的朋友,还有和我一同参与进来的西邮的学生们。那么,到底发生了什么,让我们聚在一起,畅聊不只是前端的人生,有趣的社区型学习之路,才得以开始?

想必每个人都有属于自己的答案。公布一下这次畅想的活动流程作为行动指南吧。

专门,开辟了一个环节请刚才提到的兵哥哥讲几句人生~了解到原来兵哥哥中学就喜欢计算机,却因为一些原因选择了当兵,复原后,选择前端开发工作。兵哥哥的整个分享过程中,也让我们了解到了他是怎么见证 Web 1.0 、Web 2.0 的发展,以及更多他的一些 Web 干货感悟。


Part.2 FCC 介绍


第一个环节中一起探讨我们相聚的原因所在是离不开 FCC 的,每个人也都带着自己对 FCC 的理解而来。那么,大家心中的 FCC 是什么呢?技术栈?亦或是社区活动。

原来,每个人都有属于自己的 FCC。这里贴上了全球各大 FCC 编程社区相聚时的合影留念,其中不乏北京、纽约、多伦多、成都和我们这里,古都西安。

那么官方是怎么介绍自己的呢?

freeCodeCamp 是由 Quincy Larson 创办的开源社区。它致力于帮助人们利用零散时间学习编程,内容以前端和JS全栈为主。目前已经发展成为一个 40万+开发者的社区,通过游戏化的项目实战,来吸引大家学习编程,并在社区内给予实时的帮助,同时,为 NPO 组织提供技术支持。

同时,在 FCC 平台上,我们可以学到的技术栈有:

  • HTML 5
  • CSS 3
  • JavaScript
  • Databases
  • Git & Github
  • Node.JS
  • React.js
  • D3.js

当然,这只是 FCC 提高拓展我们技术栈的开始。这个过程中 FCC 用知名职业社交平台领英认证的相关证书来激励着广大 Web 学者,全部证书都拿到手的在 FCC 全球网上目前也有 115 人,传承了很多通过 FCC 平台找到工作的故事。

在领英上,freeCodeCamp 可以作为大学教育背景独立展示。

知乎上流行的 FCC 的三大学习方法很值得借鉴:一读二搜三提问。


Part.3 FCC 做题及答疑


一起线下 FCC 做题并答疑是这次活动很核心的环节,我们平时在 FCC 上遇到的问题都能当面得到一定程度的解决,相比线上咨询,更加的生动有趣。

FCC 平台的用户定位中愿景道:Learn to Code and Help Nonprofits


Part.4 一起写一个 JS 太空船游戏!


这个环节,邀请大家到加入石墨协作,一起参与了 Canvas 画布下的 JavaScript 编程,做一个太空船小游戏~

却由于时间不够、自己准备不太充实等原因大家还没有人当场做出来~

参考链接:一起动手写一个 JavaScript 太空船游戏!

这个游戏基于我们校内实验室搭建于国内服务器上的 jsbin 环境开发,展示如下。

这次没有当场做出来,我们团队主页开发见 :-)


Part.5 团队主页开发


借鉴 FCC 成都的相关经验,第一次 FCC 西安活动便拉入 17 名伙伴加入 FCC 西安的 Github 组织,我们的成果产出都可以及时的留存在这里,充实下去。在伙伴们之间的畅聊中,产生一起做项目的灵感,也更加肯定了该开源组织的重要性。

从图中可以看到,灵感才刚刚展开,先放上了两个入手仓库作为资料留存,还有这次的 JSpace-Ship 太空船以后可以线上一起线上合作开发。


Part.6 更多的组织者


这个环节实际活动中没时间讲啦,写到文章里大家看看~

从我自己的经验来看,个人精力总是有限的,再加上一个小团队如果缺少某个人便不能维持下去的状态总归不好,激励更多的人担当起组织者的身份不出意外的被提到 FCC 流程之中。这里分享了我对社区的一些理解,不足之处还望包容和指点。

1. 组织一场社区活动

在整个组织的流程中可以发现,举办活动是其中最重要的环节,但只占整个过程的一步。流程策划、内容准备、填写表单和宣传报名联手打造了这次社区活动的基石,又由写文回顾升华了整场活动的意义,不可或缺。

2. 社区的故事

大家好,我是 FCC 西安这次的一个小组织者。

于是我就有了我的故事可以诉说。

大家怎么了解到 FCC 的呢?你们想要通过 FCC 学到什么?

很多人的故事也就得到了分享和传递。

哇塞,FCC 西安那边好有趣的样子。

FCC 西安这边的社区,也就有了自己的影响力。

最后,社区的故事回馈于很多人的故事,回馈于一个人的故事,我们在这里都得到了想要的成长。

3. 文化构建

FCC 城市小组活动举办的最大特点是自发的,由内向外的,但也离不开运营团队的支持和帮助,并将之作为向开发者社区注入资源的有效环节来推动社区发展。接着,正如之前 Github 组织所说,我们在一起,也能自建出这里独特的次文化内容和知识海洋,创造资源,创造知识,一脉相传,融汇贯通。

4. 丰富活动形式

这篇文章的很多图片背景都是以绿色为调,源于我这次将在线 PPT 带入活动之中,也便于快速截图回顾 —— 这是第三次新增的活动形式的特点之一。

其实还有很多形式可以参考加入,包括上图提到的结对编程、过关分享、项目分享、编程比赛等等。一起写一个 JS 游戏,便也因此出现在第三次活动上。

5. 组织者经验

这里针对性的分享我的经验,从流程制定到排版推送,从宣传报名到成功举办并写作回顾,我都是用什么工具做的。同时因为自己常活跃于简书的缘故,最近产生并落实了建立 FCC 简书专题的灵感,期待之后大家的活跃加入,内容不限于社区经历,加入更多的在 FCC 平台上的学习之路也不失精彩。从微信订阅号里读到这篇文章的朋友点击阅读原文三步之内便能跳转从我的主页跳转到 FCC 简书专题。

还有,上图的右下角展示了我在我的本机存储的 FCC 相关资源。任何能成功举办的活动背后都真真实实的有着它的下层资源建筑。

6.这次活动身为组织者我的感悟~

  • 提前选好场地,包括场地实地考察测试
  • 提前预演活动流程,及时优化流程顺序
  • 提前合影拍照,有些朋友会有事情要回
  • 让更多的人参与进组织里来,互相提醒
  • 没有,让大家,扫我的订阅号二维码...

FCC 与 XBOX~~~


Part.7 拍照旗帜合影


想必大家也学到了足够多的知识了,时间也不早了,“聚会吧”里玩的这么嗨,,怎么不合个影留念下呢?来吧,盆友。


End.9 Enjoy Create & Share


THE ONLY FAIR IS NOT FAIR ,ENJOY CREATE & SHARE

这么一段英文名言听过很久,通过这次的 FCC 西安第三次线下编程活动经历,更加深了对这段话的理解。说了这么多了,遍布在全国的 FCC 校友们,你们怎么看呢~?期待我们接下来的相识相知相约。

[B01]撸起袖子加油干 | 制定自己的 2017 全栈 KPI

意料之外却倍感难忘的是,于 16 年最后一天,我受 FCC 中文社区运营团队之邀从西安前往苏州参加 12 位创业者的跨年分享晚会,听到FCC 中文社区创始人晋剑兄在《编程,你也可以!》中制定的 “5 年一亿个中文开发者” 小目标后激情澎湃,也是时候制定自己的小目标了,于是有了这篇文章的初衷,写出来激励自己。

在2017年跨年钟声响起,记住的第一句话就是习主席的:

“撸起袖子加油干”!

这是时代赋予我们的使命~


制定自己的 2017 年度 KPI



Step.01.重新定位自己


制定自己的年度 KPI 前,先要定位自己。

我, 2015 年来到西邮软件工程专业,短短的一年半编程学习之路结合自己在校内加入的两个互联网实验室来说,编码视野和行业视野都得到了很不错的拓展 —— 从获得校内一些小奖到现在担当的 FCC 西安开源社区组织者,都可以证明这段时间的努力没有白费。

遗憾也需要惊醒的是,还没有太多,正式上线项目的硬实力,也离找工作只有 1 年半,在 2017 年重新定位自己,便是要走的第一步。

从程序员到产品经理、运营人员等,软件工程专业毕业的人才可以输送到计算机的方方面面,自己都接触过也都感兴趣,也结合自己性格特点探索了很久相互融合的自己的路,最终决定 2017 ,我将如此定位自己:

Web 全栈开发学徒,专注个人成长与互联网发展,时刻拥有一颗工匠之心。


Step.02.保持空杯心态


恰好近期在看《软件开发者路线图:从学徒到高手》这本书,书里讲了这么一个故事:

一位年轻的哲学家经过长途跋涉去访问一位禅宗大师。大师同意与他见面,因为哲学家随身带来老师们写着高度评价的推荐函。两人坐在一棵树下交谈,话题很快转到大师可以向年轻人传授什么这个问题上来。大师感受到了年轻人的激情,他温和地微笑着,开始讲述自己的禅定术(meditation technique)。哲学家打断了他,说:“嗯,我明白你在说什么!我们在寺院中使用过与之类似的技巧,不同的是我们使用塑像来定神。”

当哲学家向大师解释完自己是如何学习并实践禅定的,大师接着往下说了。这一次他试着向年轻人解释人应怎样与大自然和宇宙保持和谐。还没等他说完两句话,年轻人又一次打断了他,并开始谈论自己如何学习禅定术,以及很多很多其他的事情。

大师再一次耐心地等待年轻的哲学家结束他动情的解说。当哲学家再一次安静下来之后,大师开始讲述如何通过各种情形看出几分诙谐。年轻人见缝插针,又开始讲述他最喜欢的笑话,还有他认为那些笑话可以怎样联系到自己所经历过的场景。

哲学家说完之后,禅宗大师邀他到室内做一次茶道。哲学家听说过这位大师的茶道技艺与众不同,于是高兴地接受了。跟这样一个人品茶论道,这永远都是特别的礼遇。一直到进入室内,大师都做得完美无瑕,直到他开始往茶杯里倒茶。这时候,哲学家注意到茶倒得比平常满。大师继续往茶杯里倒,茶很快满到杯的边沿了。年轻人不知道该说什么,开始诧异地看着大师。大师仍然继续倒,就像什么也没发生一样,茶开始溢出了,热茶溅到地毯和大师的衣服上。哲学家不敢相信他的眼睛,终于忍不住大叫:“不要倒了!你没看到杯子已满,茶水正往外溢吗?”

听到这句话,大师轻轻把茶壶放回火炉上,用他那恒久温和的微笑看着年轻的哲学家,说:“如果你带着一只已满的杯子来找我,如何能指望我再给你一些东西喝呢?”

已有的经验越多,我们就越需要付出更多的努力进入到“空杯”状态,清除**中的坏习惯,放下对技能水平的自鸣得意,敞开自己,从更有经验的同行那里学习不同的而且常常是违反直觉的新方法,切记只有空杯才能装更多的酒。

也正是这时应该这么告诉自己:2017 ,我的极客之路才刚刚开始。


Step.03.获得三个 FCC 证书


强调在各个城市自发举办线下编程活动进行学习交流的前端和 JavaScript 全栈学习平台 freeCodeCamp,吸引了来自全球的 50 万+ 开发者,一举成为了 Github 上 Star 量第一的开源项目。在**,也已经有数十个城市小组,而自己担当西安社区组织者这几个月来,学到了很多编程以外的东西。

暂时暴露出的缺点是:自己在 freeCodeCamp 上刷题学习的时间却远远不足,是时候激励自己一波了。

在 2017 年年底前,获得前端开发证书,数据可视化证书和后端开发证书。


Step.04.读 66+ 本书


回想起自己的 18 年童年,除了教科书外认真读完的书真心不多:第一本读完的《鲁宾逊漂流记》,影响我一生的《苏菲的世界》,看到我未来发展方向的《银河帝国》外,再没有太多“读书”的回忆。在大学的人际交往中,真正体会到了文化的不同,也产生了想要引经据典的冲动,更加地需要博览群书了。

专门为此买了 Kindle PW ,2017,围绕互联网,读 66+ 本书!


Step.05.写 66+ 篇文章


最起码在中学,让我写没有感悟的作文我是很不乐意的,现在,重拾“电子笔”,写博客写心得,结合多读书,升华自己的内在与人格~


Step.06.举办/参加 12+ 社区活动


相比北上广,西安互联网气氛不算很差,也有很多开源社区联动着来自不同公司的程序员乃至互联网从业人员,今年多去谷歌开发者社区向前辈学习,多参加 ThoughtWorks 的西安社区活动,最后每个月组织最少一场 freeCodeCamp 线下编程活动,保证不忘产出,12+ 目标不在话下。


Step.07.做 6+ 开源项目


校内实验室现有项目很多需要维护,产品线也期待诸如新活力,加上 freeCodeCamp 开源社区上要做的项目来看,6+ 肯定是有了,但要保证质量和看到编程成长。


Step.08.扩大 ID 体系影响力


影响力不是实体,刻意去追求定会陷入一种癫狂的状态,以此为鉴,数量只做参考,时刻提醒自己要有所产出,并尽可能加入自己的 ID 体系中,做最好的自己,影响该影响的人。

  • 简书粉丝 300+

简书作为自己最喜欢的文章写作分享平台,写作这半年来获得的反馈带来的感悟没有任何书籍可以教到,自己也将在未来以简书平台为写作核心。

  • Github 粉丝 100+

Github,全球最大同性交友平台...全球最大代码托管平台,上面有很多影响世界的开源项目,平台里都是程序员,

  • 微信订阅号粉丝 200+

专注于个人发展和互联网发展,激励自己的同时也能及时产出成果及时分享。鉴于还是 Too Young Too Simple,200 起步。

  • 在全程序员平台学习交流

国内有很多专注功能不同的程序员学习交流平台,多在诸如知乎、CSDN、博客园、简书等程序员线上聚集地和前辈学习交流收获也会更多,说不定还能因此获得实习机会呢。


Step.09.See U Later


正如和俩位其他城市组织者在苏州“吹”下

2017,获得 FCC 所有证书。

后得到朋友的回复所言:

“我就看你们这一年怎么填这个坑” 。

不多说了,新的一年,撸起袖子加油干(填坑),开始吧*年。

[A14]C 语言 32 个关键字 GET 进行曲

C 语言标准定义的 32 个关键字有什么,分别怎么用,用的时候需要注意到什么,便是这篇文章所要告诉的一切。内容较长,先上本篇文章结构思维导图。文章结尾处有 32 个关键字附录。

- 修饰类 -

- 1. extern -- 最会带帽子的关键字 -

  • 定义创建了对象并为这个对象分配了内存,声明没有分配内存
  • 相同的定义只能出现一次,相同的声明可以出现多次
int i;    // 变量的定义
extern int i;    // 变量的声明

void fun(int i, char c);    // 函数的声明
void fun(int i, char c) {}    // 函数的定义

- 2. auto -

  • 编译器在默认的缺省情况下,所有变量都是用 auto 修饰的。

- 3. register -- 最快的关键字 -

  • 这个关键字请求编译器尽可能的将变量存在 CPU 内部寄存器中而不是通过内存寻址访问以高效率。注意是尽可能,不是绝对。

3.1 寄存器

  • 数据从内存里拿出来先放到寄存器,然后 CPU 再从寄存器里读取数据来处理,处理完后同样把数据通过寄存器存放到内存里,CPU 不直接和内存打交道。

为什么寄存器比内存快?

CPU Registers 即为寄存器

3.2 使用 register 修饰符的注意点

  • register 变量必须是能被 CPU 寄存器所接受的类型
  • register 变量必须是一个单个的值,并且其长度应小于或等于整型的长度
  • register 变量可能不存放在内存中,所以不能用取址运算符“&”来获取 register 变量的地址

- 4. static -- 最名不符实的关键字 -

关键字 static 有着不寻常的历史。起初,在 C 中引入关键字 static 是为了表示退出一个块后仍然存在的局部变量。随后,static 在 C 中有了第二种含义:用来表示不能被其它文件访问的全局变量和函数。为了避免引入新的关键字,所以仍使用 static 关键字来表示这第二种含义。

4.1 修饰变量

  • 变量又分为局部和全局变量,但它们都存在内存的静态区
  • 静态全局变量,作用域仅限于变量被定义的文件中
  • 静态局部变量,在函数体里面定义且只能在这个函数里用
  • 静态变量的值不会被销毁,函数下次使用时仍然能用到这个值

4.2 修饰函数

  • 函数前加 static 使得函数成为静态函数,指对函数的作用域仅局限于本文件(所以又称内部函数)

- 5. const 关键字 -

  • const 是 constant 的缩写,并不是英文直译的用来修饰“常量”,更精确的说是修饰“只读变量”,其值在编译时不能被使用,因为编译器在编译时不知道其存储的内容。
  • const 推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。

5.1 const 修饰的只读变量

  • 定义 const 只读变量,具有不可变性。该变量具有只读属性。

5.2 节省空间,避免不必要的内存分配,同时 高效率

  • 编译器通常不为普通 const 只读变量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的值,没有了存储与读内存的操作,使得它的效率也很高。
  • const 定义的只读变量从汇编的角度来看,只是给出了对应的内存地址。

5.3 修饰一般变量

  • 只读变量在定义时,修饰符 const 可以用在类型说明符前,也可以用在类型说明符后。例如:
int const i=2;    // 正确
const int j=2;    // 正确

5.4 修饰数组

  • 定义或说明一个只读数组可采用如下格式:
int const a[5]={1, 2, 3, 4, 5};    // 正确
const int b[5]={1, 2, 3, 4, 5};    // 正确

5.5 修饰指针

  • 先忽略类型名(编译器解析的时候也是忽略类型名),我们看 const 离哪个近。“近水楼台先得月”,离谁近就修饰谁。
const int *p;    // p 可变,p 指向的对象不可变
int const *p;    // p 可变,p 指向的对象不可变
int *const p;    // p 不可变, p 指向的对象可变
const int *const p;    // 指针 p 和 p 指向的对象都不可变

5.6 修饰函数的参数

  • 当不希望这个参数值被函数体内意外改变时,const 修饰符也可以修饰函数的参数,从而防止了使用者的一些无意的或错误的修改。
void Fun(const int i);

5.7 修饰函数的返回值

  • const 修饰符也可以修饰函数的返回值,返回值不可被改变。例如:
const int Fun (void);
  • 在另一连接文件中引用 const 只读变量
extern const int i;    // 正确的声明
extern const int j=10;    // 错误!只读变量的值不能改变。

- 6. signed、unsigned 关键字 -

  • 既然计算机底层只认识 0 和 1 的二进制数字,那么正数和负数是怎么存储的呢?signed 和 unsigned 修饰的变量各有什么特点?
  • 答案很简单。在 32 位计算机的内部,一个 int 型的整数由 4 字节 32 位 0/1 数字组成,32 个数字中最高位(第一个数字)表示符号位并约定最高位如果是 1 则表示负数,如果是 0 则表示正数,这样一来,一个 32 位有符号的 int 型变量便能表示 -21474836482147483647 之间的数字,而无符号的 int 型变量便能表示 04294967295 之间的数字。
  • 其中有符号的 int 型变量由 signed 修饰,一般可以省去;无符号的 int 型变量由 unsigned 修饰,不能省去。
signed int i;
unsigned int love;
signed int u;
  • 然而用普通 01 码(原码)表示的数字中 +0 和 -0 各有一种表示方法,且原码无法,具体的计算机中负数其实是以补码的形式存储的。补码由反码 +1 而来,而反码由原码的每一位 0 变成 1,1 变成 0而来。同时反码和补码的出现使得计算机为辨别"符号位"而设计的电路不再复杂。具体的有关机器语言中原码、反码和补码的知识都在我的博客园里写过,期待之后整理到简书中来。

「C语言」原码反码补码与位运算

- 数据类型 -

- 7. 数据类型 -

  • short、int、long、char、float、double 这六个关键字代表 C 语言里的六种基本数据类型。

7.1 数据类型与“模子”

  • 在每一个拥有数据类型的变量的声明时,都会分配给该变量特定的内存大小空间。放出基本数据类型在 32 位操作系统下特定的内存空间大小:

  • 具体有关各个数据类型的特点和区别及其混合运算与类型转换等可以参考我在博客园写的这篇文章,毕竟本文的重心在“关键字”上。

「C语言」数据类型及混合运算与类型转换

7.2 变量的命名规则

  • 命名和缓存失效是计算机科学面临的最难的两件事。其中符合规范的变量命名可以直观地看出代码的逻辑性,具体命名规则也同样加入自己的博客园文章地址,期待之后整理到简书中来。

「C语言」常量和变量的表示、应用和变量命名规则

- 8. void 关键字 -

  • “色即是空,空即是色”,void 也有它的妙用 —— void 的字面意思是“空类型”,void *则为“空类型指针”,void *可以指向任何类型的数据。
  • void 真正发挥的作用在于:
    1 -> 对函数返回的限定;
    2 -> 对函数参数的限定。
  • 任何类型的指针都可以直接赋值给 void ,无需进行强制类型转换。
void *p1;
int *p2;
p1 = p2;

8.1 void 修饰函数返回值和参数

  • 如果函数没有返回值,那么应声明为 void 类型
    在给函数不加返回值说明时默认为 int 型,所以对于没有返回值的函数推荐用 void 声明。另外,加上 void 类型声明后,也可以发挥代码的“自注释”作用。所谓的代码的“自注释”即代码能自己注释自己。
  • 如果函数无参数,那么应声明其参数为 void
    在 C 语言中,可以给无参数的函数传送任意类型的参数,但是在 C++编译器中编译同样的代码则会出错。所以,无论在 C 还是 C++中,若函数不接受任何参数,一定要指明参数为 void。

8.2 void 指针

  • 千万小心又小心使用 void 指针类型。
    按照 ANSI(American National Standards Institute)标准,不能对 void 指针进行算法操作,即下列操作都是不合法的:
void * pvoid;pvoid++;    // ANSI:错误
pvoid += 1;    // ANSI:错误

但是大名鼎鼎的 GNU(GNU's Not Unix 的递归缩写)则不这么认定,它指定 void *的算法操作与 char *一致。因此下列语句在 GNU 编译器中皆正确:

pvoid++;    // GNU:正确
pvoid += 1;    // GNU:正确

因此,为了兼容两大标准, 高程序的可移植性,我们可以这样编写实现同样功能的代码:

void * pvoid;(char *)pvoid++;    // ANSI:正确;GNU:正确(char *)
pvoid += 1;    // ANSI:错误;GNU:正确
  • 如果函数的参数可以是任意类型指针,那么应声明其参数为 void *。
    典型的如内存操作函数 memcpy 和 memset 的函数原型分别为:
void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );

8.3 void 不能代表一个真实的变量

  • void 不能代表一个真实的变量。
void a;    // 错误
function(void a);    // 错误

- 9. struct 关键字 -

  • 常用在网络协议、通信协议、嵌入式系统、驱动开发等地方的 struct 关键字将一些相关联的数据打包成一个整体(结构体),方便使用。同时,可以用结构体压缩参数个数。

9.1 空结构体有多大

  • 结构体所占的内存大小是其成员所占内存之和。但空结构体呢?
struct student{

} stu;
  • 答案不是 0 而是 1。因为编译器认为任何一种数据类型都有其大小,空结构体的大小又不能大于只有 char 类型的结构体大小,所以 0 < sizeof(stu) <= 1 的情况下,空结构体的大小就定为 1 个 byte。

9.2 柔性数组

  • C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员,但结构中的柔性数组成员前面必须至少一个其他成员。
typedef struct st_type {
    int i;
    int a[];
} type_a;
  • 即使这时 sizeof(type_a) 得到的只有 sizeof(int) 的值 —— 4,但这是我们可以进行边长操作,通过以下表达式给结构体分配内存:
type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));
  • 这时候 p->item[n] 就能简单的访问可变长元素。而 sizeof(*p) 依旧是 4。

9.3 struct 和 class 的区别

  • 在 C++里 struct 关键字与 class 关键字一般可以通用,只有一个很小的区别。struct 的成员默认情况下属性是 public 的,而 class 成员却是 private 的。很多人觉得不好记,其实很容易。你平时用结构体时用 public 修饰它的成员了吗?既然 struct 关键字与 class 关键字可以通用,你也不要认为结构体内不能放函数了。

- 10. union 关键字 -

  • union 关键字的用法与 struct 的用法非常类似,用来维护足够的空间来置放多个数据成员中的“一种”,而不是为每一个数据成员配置空间。例子如下:
union StateMachine
{
    char character;
    int number;
    char *str;
    double exp;
};
  • 一个 union 只配置一个足够大的空间以来容纳最大长度的数据成员,以上例而言,最大长度是 double 型态,所以 StateMachine 的空间大小就是 double 数据类型的大小。
  • 在 C++里,union 的成员默认属性页为 public。union 主要用来压缩空间。如果一些数据不可能在同一时间同时被用到,则可以使用 union。

10.1 大小端模式对 union 类型数据的影响

union {
    int i;
    char a[2];
} *p, u;

p = &u;
p->a[0] = 0x39;
p->a[1] = 0x38;
  • 上面的例子中 p.i 的值为多少呢?这就要考虑存储模式 —— 大端模式和小端模式了。
  • 大端模式(Big_endian):字数据的高字节存储在地地址中,而字数据的低字节存放在高地址中。
  • 小端模式(Little_endian),字数据的高字节存储在高地址中,而字数据的低字节则存放在低地址中。

- 11. enum 关键字 -

  • 初学者一般用不到的 enum 数据类型其实很有用处。

11.1 枚举类型的使用方法

  • 一般的定义方式如下:
enum enum_type_name
{
    ENUM_CONST_1,
    ENUM_CONST_2,
    ...
    ENUM_CONST_n
} enum_variable_name;
  • 其中 enum_type_name 是自定义的一种数据类型名,而 emun_varaiable_name 类型是对一个变量取值范围的限定,而花括号内是它的取值范围,及 enum_type_name 类型的变量 emun_varaiable_name 只能取值为花括号内的任何一个值,如果赋给该类型变量的值不在列表中,则会报错或警告。

11.2 枚举与 #define 宏的区别

  •  #define 宏常量是在预编译阶段进行简单替换,枚举常量则是在编译的时候确定其值。
  • 一般在编译器里,可以调试枚举常量,但是不能调试宏常量。
  • 枚举可以一次定义大量相关的常量,但是 #define 宏一次只能定义一个。
  • 枚举可以一次定义大量相关的常量,而 #define 宏一次只能定义一个。

- 选择分支 -

- 12. If else 组合 -

12.1 bool 变量与“零值”进行比较

bool bTestFlag = FALSE;    // 一般要初始化为 FALSE
if(bTestFlag == 0);    // 不好。容易被误解为整型变量
if(bTestFlag == TRUE);    // 不好。TRUE的值不都为1。
if(bTestFlag);    // 推荐

12.2 float 变量与“零值”进行比较

float fTestVal = 0.0;
if(fTestVal == 0.0);    // 不好。
if((fTestVal >= -EPSINON) && (fTestVal <= EPSINON));    // 推荐。EPSINON 为定义好的精度。在该范围内则认为为零值

12.3 指针变量与“零值”进行比较

if(p == 0);    // 尽管 NULL 值为0,容易引起 p 是整型的误会。
if(p);    // 容易引起 p 是 bool 型的误会
if(NULL == p);    // 推荐。且 NULL 要写在左值避免 p = NULL; 的错误赋值。

12.4 else 到底与哪个 if 配对呢?

if(0 == x)
if(0 == y) error();
else {
//program code
}    // 这段代码容易引起误会
  • C 语言有这样的规定:else始终与同一括号内最近的未匹配的 if 语句结合。但是任何时候都不要偷懒。该写花括号都要写上。
for (initialization; condition; update) 
{
    // 推荐风格
}

for(initialization; condition; update){
    // 不推荐风格
}

12.5 if 语句后面的分号

  • 如果出现以下代码,fun() 函数无论如何都会被调用:
if(NULL != p);
    fun();
  • 建议在真正需要用空语句时写成这样:
NULL;

- 13. switch case 关键字 -

  • if、else 一般表示两个分支或是嵌套表示少量的分支,如果分支很多的话,用 switch 和 case 组合更好
  • 每个 case 语句的结尾绝对不要忘了加 break,否则将导致多个分支重叠(除非有意使多个分支重叠)。
  • 最后必须使用 default 分支。即使程序真的不需要 default 处理,也应该保留语句。这样做并非画蛇添足,可以避免让人误以为你忘了 default 处理。

13.1 case 关键字后面的值的要求

  • case 后面只能是整型或字符型的常量或常量表达式

13.2 case语句的排列顺序

  • 按字母或数字顺序排列各条 case 语句。
  • 把正常情况放在前面,而把异常情况放在后面。
  • 按执行频率排列 case 语句。

13.3 使用 case 语句的其他注意事项

  • 简化每种情况对应的操作。case 语句后面的代码越精炼,case 语句的结
    果就会越清晰。
  • 不要为了使用 case 语句而刻意制造一个变量。
  • 把 default 子句只用于检查真正的默认情况。

- 14. goto 关键字 -

  • 一般来说,编码的水平与 goto 语句使用的次数成反比。很多 C 语言编程书及其作者都主张禁用 goto 语句
struct student *p = NULL;
...
goto state;
p = (struct student *)malloc(...);    // 被 goto 跳过,没有初始化
...
state:    // 使用 p 指向的内存里的值的代码⋯

- 循环分支 -

- 15. do while for 关键字 -

  • C 语言中循环语句有三种:while 循环、do-while 循环、for 循环。
  • 死循环当然有用,操作系统的整个进程就是死循环,直到遇到关机指令。

15.1 break 与 continue 的区别

  • break 用来终止本层循环。
  • continue 用来终止本次(本轮)循环。

15.2 循环语句的注意点

  • 在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少 CPU 跨切循环层的次数。
  • 建议 for 语句的循环控制变量的取值采用“半开半闭区间”写法。
  • 不能在 for 循环体内修改循环变量,防止循环失控。
  • 循环要尽可能的短,要使代码清晰,一目了然。
  • 把循环嵌套控制在 3 层以内。

- 其他 -

- 16. sizeof -- 最冤枉的关键字 -

  • 很多人都认为 sizeof 是函数,至少我第一次学 C 语言的时候是这么认为的。然而事实呢? sizeof 是关键字,常年被人误认为函数的关键字。

  • sizeof 在计算变量所占空间大小时,括号可以省略,而计算类型(模子)大小时不能省略。

  • 一般情况下,sizeof 关键字后尽可能加上括号,继续装作函数。

sizeof(int);    // 正确
sizeof int;    // 错误
int a[10];
sizeof a;    // 正确
sizeof(a);    // 正确

- 17. typedef -- 伟大的缝纫师 -

17.1 历史的误会----也许应该是 typerename

  • type 是数据类型的意思,def(ine)是定义的意思,合起来就是定义数据类型。然而事实并不是这样,typedef 的真正意思是给一个已经存在的数据类型(注意:是类型不是变量)取一个别名,而非定义一个新的数据类型。
typedef struct student {
//code
} Stu_st, *Stu_pst;
  • 这时候,下方的定义中(1)和(2)没有区别,(3)、(4)和(5)没有区别。
struct student stu1;    // (1)
Stu_st stu1;    // (2)
struct student *stu2;    // (3)
Stu_pst stu2;    // (4)
Stu_st *stu2;    // (5)

17.2 typedef 与#define 的区别

#define INT32 int
unsigned INT32 i = 10;    // 正确
typedef int INT32;
unsigned INT32 j = 10;    // 错误

从这段代码可以看出 typedef 取的别名不支持这种类型扩展。

#define PCHAR char*
PCHAR p3,p4;    // 等价于 char *p3;char p4;
typedef char* pchar;
pchar p1,p2;    // 等价于 char *p1;char *p2;

从这段代码又可以看出 #define 仅仅是简单的替换,并无法代表一个数据类型。

- 18. volatile -- 最易变的关键字 -

  • volatile 是易变的、不稳定的意思,和 const 一样是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以 供对特殊地址的稳定访问。

18.1 编译器优化

int i=10;
int j = i;    // (1)语句
int k = i;    // (2)语句
  • 编译器在编译时会对代码进行优化。而因为在(1)、(2)两条语句中 i 没有被用作左值,这时候编译器认为 i 的值没有发生改变,所以在(1)语句时从内存中取出 i 的值赋给 j 之后,这个值并没有被丢掉,而是在(2)语句时继续用这个值给 k 赋值。编译器不会生成出汇编代码重新从内存里取 i 的值,这样提高了效率。但要注意:(1)、(2)语句之间 i 没有被用作左值才行。

18.2 volatile 关键字防止编译器优化

volatile int i=10;
int j = i;    // (3)语句
int k = i;    // (4)语句
  • 如果将之前的代码改成上面的样子的话,volatile 关键字会告诉编译器 i 是随时可能发生变化的,每次使用它的时候必须从内存中取出 i的值,因而编译器生成的汇编代码会重新从 i 的地址处读取数据放在 k 中。

- 19. return 关键字 -

  • return 用来终止一个函数并返回其后面跟着的值。
  • return 语句不可返回指向“栈内存”的“指针”,因为该内存在函数体结束时被自动销毁。
  • 关于 int main 中该不该出现 return 0; 又为什么是这样,我在我的博客园中如是写道:

「C语言」int main还是void main?

附录:C 语言标准定义的 32 个关键字

关键字 意 义
auto 声明自动变量,缺省时编译器一般默认为 auto
int 声明整型变量
double 声明双精度变量
long 声明长整型变量
char 声明字符型变量
float 声明浮点型变量
short 声明短整型变量
signed 声明有符号类型变量
unsigned 声明无符号类型变量
struct 声明结构体变量
union 声明联合数据类型
enum 声明枚举类型
static 声明静态变量
switch 用于开关语句
case 开关语句分支
default 开关语句中的“其他”分支
break 跳出当前循环
register 声明寄存器变量
const 声明只读变量
volatile 说明变量在程序执行中可被隐含地改变
typedef 用以给数据类型取别名(当然还有其他作用)
extern 声明变量是在其他文件正声明(也可以看做是引用变量)
return 子程序返回语句(可以带参数,也可不带参数)
void 声明函数无返回值或无参数,声明空类型指针
continue 结束当前循环,开始下一轮循环
do 循环语句的循环体
while 循环语句的循环条件
if 条件语句
else 条件语句否定分支(与 if 连用)
for 一种循环语句(可意会不可言传)
goto 无条件跳转语句
sizeof 计算对象所占内存空间大小

写在最后

这篇文章灵感和素材均来源自《C 语言深度解剖》这本书,感谢作者对 C 语言的独特见解,如有需要,欢迎购买实体书籍支持作者。

[B04]有趣的百度前端热身赛@2017

情人节这天,还不忘学习编程的同学都是折翼的天使,于是百度前端学院就给了我们一个通过跪键盘来发泄的机会 -- 前端热身赛。

足足火了一把前端社群。

15 号就要过去的今天,不知道你是否还在坚持热身?

Come on,也就 Step 0, 1, 2, 3, 4, done。

既然如百度前端技术学院所说,这是一个“面向大学生的前端技术学习平台”,那么身为大学生的我,就豪迈攻克之,正如以下攻略所示。若有雷同,纯属巧合~

感谢一波 @discountry 的前期解答做参考,和广大 FCC 知友及时指迷。

Step 0. Unlock

一笔画出折线,穿过图中的 9 个点,折现个数最少。只要知道这整个灰色画布都可以画,大胆的突破惯性思维,将线画长点即可只用 4 条折线过关。

否则,惯性思维下,最优解为 5 ,总是多那么一条。

Step 1.

乍眼一看,除了 “Step1 找出下一关地址” 再看不到什么,点击 “Ctrl + A” (Mac 下 Command + A) 将隐藏文字全选出来。亦或,打开浏览器“开发者工具”在源代码里搜寻踪迹。

02.01

Iy9CQzY3QTA4MzM1NkM4MzU5NEJDQzU3RUQxMzNENEE1MjU2N0U0Qg==

“==” 号应该算作提醒,前面的就是密码,直奔答案,Base 64 解码之。

base64 在线解码编码

解码后又出来一串字母,“#/” 开头,肯定是 URL 地址。别问我为什么知道这串字母需要解码,解码答案肯定是 URL 地址~我可是在去年校内实验室免试题里见过这个套路的,不会告诉你的。(逃

西邮Linux兴趣小组2016免试题

Step.2

为了更好的贯穿社会主义核心价值观(再逃... ,我们需要揭破“上帝的窗”,找到它的高度。

可以看到,在开发者工具中用以下代码实现。

$(window).height();

385,那就把锁拨到 385,然而页面不能直接拨锁,否则 999 种答案,一个个拨即可 (ಢധಢ)。

页面源码里,看到负责锁中数字的 Div 里有 style="top: -280px"字样,修改后锁轮会转,便可以试试用 px 值转动锁轮。每 60 px 转一个数字。

那么有趣的事情来了,这个 385px 并不是唯一值,把开发者工具伸展开盖住页面,答案就不是 385px 了。既然页面默认是 521 px 这种虐狗狗的值,其实不需要拨锁,把 window 的 height 调整至 521 px 即可。

Step.3

说实话,在这关之前,我只是只闻“CSS3”其名,不见其身。这次也领教了一番。

CSS3,网页样式控制新标准,早在 2001 年 5 月,W3C 就着手开始准备开发 第三版规范,其中的变形(transform)、转换(transition)和动画(animation)属性,实为亮点。

用类选择器选取三个字母(题目已经自动选择),依靠 transform 移动到相应位置。

这里用到的 transform 属性的值有:

translate(x ,y) 定义 2D 转换(位移)。
scale(x, y) 定义 2D 缩放转换。
scaleX(x) 通过设置 X 轴的值来定义缩放转换(镜像)。
rotate(angle) 定义 2D 旋转,在参数中规定角度。

需知,不能同时定义两个 transform 属性,要写在一起,并且还需要注意顺序。更多的属性值可以参考 W3School 的 CSS3 transform 属性

Step.4

没有忘记的话,去年学院就有游戏挑战压轴,作为这次热身赛的压轴,不出所料,“游戏”依旧,多彩。

依提示,在框框里调用移动小球 api ,补全函数。

左转右转一个慢动作。

在哪里转,函数参数 x, y 便派上了用场。

“82,46” 便是从地图左上角开始像素坐标,在这里,右转。

值得注意的是,不能同时在一个点上定义两个方向的转向,哪怕调整顺序也不行,需要错开几个像素。

以下代码只采集到了四个星星,仅供参考。

function moveBall(ball) {
    var right = (x, y) => ball.at(x, y, ball => ball.turnRight());
    var left = (x, y) => ball.at(x, y, ball => ball.turnLeft());
    var back = (x, y) => ball.at(x, y, ball => ball.turnBack());

    right(82, 46);
    left(82, 130);
    left(270, 130);
    right(270, 46);
    right(365, 46);
    right(365, 470);
    back(20, 470);
    left(372, 470);
    right(372, 185);
    right(575, 185);
    left(575, 475);
}

Never End

19 年前还是个胎儿的时候,怎会想到今天我居然写了个假攻略,真软文。

欢迎扫码加入“2017百度前端学院抱团群”,一起迎接技术学院课程任务 2 月 24 日的正式上线。人满的话,关注订阅号有我的微信二维码哦。

来。不。及。解。释。了。快。抱(shang)。团(che)。

简友须知:大咖专题文章不让投放二维码哦,主页有码。

[B08]小全栈任务“番茄post”【2】简化版概要设计

上一章的 小全栈任务“番茄post”【1】拆分里程碑 最后,预料到接下来采用的将是增量模型的软件开发模型。每一个增量都会经历针对该增量的分析、设计、编码、测试、交付阶段。“里程碑”便不失需求分析的意味。到了这一章,针对“番茄post”做概要设计;鉴于我们对项目的初始探索,这次概要设计将是一个简化版,没有详细的文档作为内容沉淀。

1

随着软件的规模越来越大、结构越来越复杂、开发工具落后、软件开发管理困难而复杂等历史原因,在十九世纪六十年代中期爆发了众所周知的软件危机。为了解决问题,在 1968、1969 年连续召开的两次著名的北大西洋公约组织(NATO)会议时,提出了软件工程的概念。

概要设计是软件工程中所占比例很重的环节,在这个实践过程中不仅将软件工程的知识与数据库、VB 以及数据结构等知识相结合的知识交叉地带,更是软件设计的关键,为下一阶段的详细设计做参考。

设计软件结构的具体任务是:将一个复杂系统按功能进行模块划分、建立模块的层次结构及调用关系、确定模块间的接口及人机界面等。数据结构设计包括数据特征的描述、确定数据的结构特性、以及数据库的设计。显然,概要设计建立的是目标系统的逻辑模型,与计算机无关。知识错综复杂,这里闲谈而至仅作点醒之笔。

2

鉴于我们对原型图制作的不熟程度,寻找几款市面上基于番茄工作法的软件以作番茄学习,寻找几款市面上的社区软件以作借鉴。

番茄土豆

番茄土豆见名知意,是对番茄工作法和 todo-list 的一次结合尝试,美观大方,简洁如宾。功能上除了将刚刚提到的番茄工作法和 todo-list 结合之外,也有每日 8 个番茄目标、番茄统计和番茄历史等功能。同时,番茄土豆在各大 PC 端、Web 端、移动端乃至谷歌插件,都有相应的访问入口。

番茄盒子

Windows 平台的免费项目番茄盒子也毫不逊色,除了对番茄工作内容的记录、分析之外还有上网控制,时间记录等功能,是一款功能强大的自我管理软件。所谓“上网控制”,指在用户主动设定想要克制住自己不去访问的网站后,将在该段时间无法浏览这类网站,并在开启“强力监控”的情况下,无法修改设置甚至关闭、卸载软件也无法后悔。

番茄钟 for ios

作为一个移动端的基于番茄工作法来培养用户专注力、提高工作效率的软件,番茄钟的界面够简洁,功能足够丰富。可以分享自己的番茄数据和查看排行榜,拥有了一定的社交属性,值得借鉴。

简书、知乎

不用多多介绍,简书和知乎应该是很多网客喜欢去的地方,作为社交性平台,这些社区的首页、关注页里的很多哲学思维值得迭代中的“番茄post”原型图吸收。

简书

知乎

3

回顾主题,这里我们将共同探讨并快速画出“番茄post”的原型图、组件图、数据结构图和事件列表至白板上,以确定一个明确的、共同的开发目标。

可见,对“番茄post”作出的简化版概要设计这一阶段,是里程碑的具体,也是接下来详细设计阶段的铺垫。

更多内容,持续更新中~。

[B0B]听 jjc 前端 live 30 谈 | 前端工程师的入门与进阶

身为一个 Web 开发萌新,很难忘记我发的那条朋友圈,根据我的感悟总结过的这一段话,也得到了 justjavac (jjc)的点赞,好生勉励:

在这个信息爆炸的时代,重要的不是掌握多少信息,而是认识多少承载信息的人,并努力成为其中一个。

阮一峰的经济学博士背景、池建强的“技术与人文”理念,廖雪峰的详细 Git 教程以及 Phodal 的全栈之旅和花式秀恩爱等等“程序员英雄”事迹,让我看到了一个个鲜活的生命力在互联网的行业中激情迸发,激励着自己。如果身为程序员的你还不知道他们,想必搜索引擎用的也不多吧?

https://github.com/justjavac

回归到我们的主角 jjc 和主题“前端工程师入门与进阶”,这里凝聚了我在 2017 年 4 月 22 日我的第一场知乎 Live 中的笔记。

P.S. 最近的 IOS 不再支持订阅号赞赏也阻挡不住知识付费的潮流~

语录

  • 最能提高自己的方式:别人 Review 自己的代码
  • 学新语言时和曾经学过的语言作对比:求同法和求异法
  • 想成为前端程序员,先成为程序员
  • 避免三个月的经验,重复了五年
  • 没有工资高的语言,只有工资高的开发者
  • javascript 不只是 script
  • React:抛开 React 学习 React
  • 对前端有了基本了解后,建议忘掉 dom 忘掉浏览器学习 javascript
    举例子:学 C 时先学数据类型

问答

1

  • 程序员 80% 的时间是在维护老项目
  • 老项目都是慢慢更新成新技术的

2

  • 先多练 JS,不要专注酷炫的效果。
  • 看看自己代码是否整齐
  • 写写代码逻辑很复杂但页面简单的项目
  • 区分函数式、过程式、面向对象式
  • 提升自己代码“健壮性”,任何非法输入都不会崩溃产品
  • 代码可调式性是否高
  • 分技能练习,点亮自己的技能树

3

  • 所有展示性的东西,都是前端工程师
  • React 做 MVC 架构的 V (View)

4

  • 80% 的程序员都在写业务代码
  • 成熟的开发公司外很少有不写业务代码的
  • 不提倡使用 for 等循环语句,推荐函数式编程
  • 前端和后端最大不同之公司业务很稳定,后端不易改

5

  • 能独立完成项目的人不一定不算是初学者
  • “三个月经验,重复了五年”
  • 编程入门者:不要使用框架
  • React:抛开 React 学习 React
  • 使用框架是为了解决未来可能会出现的问题,迎接变化

6

  • 提升编程思维和编程能力,可以用 js 刷刷 c 语言的题目
  • 阅读别人的代码,多问为什么

7

  • 看看 Martin Fowler 的《重构》、设计模式
  • 函数要短小,不能超过 20 行
  • 项目驱动
  • 考察思维方式
    例如:编程计算根号 7 :从二分查找到牛顿迭代法
  • 提问的智慧会了解一个事实
    大牛不是生来就是大牛,而是这些大牛在提问之前已经把问题解决了

8

  • 停留在入门,停留在写一个页面而已上面
  • 没有系统的了解 javascript
  • 为了编程而编程
  • 前端最容易犯的错:追求炫酷和最新的技术
  • 前端学习应该刻意联系 解决 Bug 的思路

如何阅读一本书

  • 高效的读书:如何阅读一本书(不要被书名迷惑)

9

  • 跟着简历上说到的技术提问:深入和全面掌握某一门知识,“系统化”学习,拓展知识

个人知识管理

  • 可以看看编程、历史、经济类的书,经济管理类的书可以拓展思路:经营、管理自己的时间、知识

如何创造财富

  • 截取自阮一峰老师翻译的《黑客与画家》

前端工程师

  • 不陌生吧

10

  • 代码 Review、Chrome 调试工具

11

  • 训练出来,多刷题,多遇到

12

  • 一种技能:解决问题的技能
  • 现在前端处于什么阶段:从 Web Page 到 Web APP,后端逻辑逐渐转移至前端 -> 胖客户端

13

  • 工具类了解原理和背景就好,比如 Webpack 为什么诞生。随着
    HTTP 2 的推广,Webpack 这类也不一定会持久下去。且用户访问量最大的 QQ 空间,所有 JS 已经缓存在各大服务器,也不便转用 Webpack
  • 之所以做前后端分离,因为不只有 Web 前端
  • 后端:提供 API
  • 前端:处理展示逻辑,无论是否在浏览器上还是在服务器上运行

14

  • 代码 Review 、技术分享和看看开源团队的代码
  • 代码 Review 最大的困难是说服和技术无关的领导进行此类活动

15

  • 大部分人进入前端其实是为了逃离后端
  • 对自己进行职业定位
  • 去招聘网站多看看自己职位的要求
  • 没用的知识就不要学习
  • 前端错误学习方式:JS 还不清楚,盲目学习前端页面、框架
  • 看明白,多动手敲
  • 没有工资高的语言,只有工资高的开发者
  • 大部分人事自学成才的
  • 初学者:尽量远离外包公司,尽量去产品型公司
    避免三个月的经验,重复了五年
  • 快速的成长:要踩足够的坑,系统化、理论化

16

  • 想得到工作,努力提高自己达到公司要求,而不是降低自己薪资标准

17

  • 新人,不要使用任何框架(除 jQuery)
  • 现在叫前端工程师,以前叫页面重构师
  • 做一些开源项目,做十个不如做精一个

18

  • 多提问:设计模式是什么,设计模式用在什么场景,设计模式解决了什么问题,设计模式怎么才能解决这个问题
  • 前端数据来源,Ajax、本地缓存、URL 等

19

  • 从发布最初版本开始看,包括其中的各种提交 diff

20

  • 需求更改:新手害怕改变,高手迎接改变,大神以不应应万变
  • 代码要多进行单元测试。

21

  • 将兴趣和工作结合,也不能将兴趣作为收入太多的来源

22

  • 移动端几乎摆脱 jQuery
  • 应该少操作 DOM,推荐使用 React

23

  • 产品、工程路线和底层、研发路线

24

  • 做精一俩个项目足以,不要贪多

25

  • 什么样的:前端工程化要了解、设计模式要了解、解决问题要了解

26

  • React:单项数据流、函数式编程

27

  • Vue,轻量级、门槛低、有成功案例,因此也很有价值

28

  • 学习理念

书签管理

29

  • 首选官网,再搜维基等文档,拓展链接
  • 拓展:从一篇博客到其友情链接等延伸提升
  • 实战提升自己:实战建立在自己有全面的知识架构,不要盲目实战
  • 想成为前端程序员,先成为程序员
  • 先学语言和库

30

  • 推荐书籍
  • 《黑客与画家》
  • 《JavaScript 高级程序设计》
  • 《JavaScript 精粹》
  • 《你不知道的 JavaScript》

我的感悟

  • 用后端的角度思考前端
  • 用设计的角度思考前端
  • 分享,是最好的学习方式,就像这场知乎 live 或这篇文章一样

  • 感受一下

[B0A]真的不该错过的大学生全天 8 小时 Web 小全栈编程马拉松活动 | 融汇俩年“毕生功力”大二大一男倾情打造

这个是大一服务端学弟哦 q(´・ω・`)p

那就开始吧!

在和四个实验室 Web 服务端大一学弟的为期俩周的准备下,2017 年 04.08 号这一整天,终于成功举办了这场编程马拉松活动。从最初的简单分享到发现时间不足而拓展成编程马拉松,也终于敲定了活动名称,确定了活动流程。此之谓:

小全栈编程马拉松

如果你还不了解我,不了解这场活动在大学氛围能够成功举办的背景,不妨看看这三篇文章,当然更多的故事在我的简书和微信订阅号之中(@韩亦乐)。

并且整场活动的文章内容在这里:

这场活动在西邮通院科协邀请下,由我所在的 CreatShare 互联网实验室主讲,包括全天流程及其干货内容都由 CreatShare 互联网实验室(其实就是我和四个学弟啦)策划并完善。我是这么形容这场活动对我的意义,其中可见从我的俩个大学实验室到我组织的本地 FCC 西安开源前端(全栈)社区活动,融汇了我俩年的“毕生所学”。

那么不多说,活动流程如下,用 MindeNode 绘制,贯穿 Web 前后端的基础知识点和软技能,激情的开始吧。

最帅的大一学弟没有之一 (´థ౪థ ) ☞

整场活动从前端到后端,首先便是 HTML + CSS 的必备基础内容。我们在这里引入了自己的思考,开启一场独特的“大前端”之旅。

HTML + CSS

](http://upload-images.jianshu.io/upload_images/2558748-f79355886097698c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

以下三个图是从学弟的 PPT 中取材,HTML 可以了解结构和历史,CSS 可以看看选择器和属性,并用流行的 Sublime 编辑器做个 Demo 体验(匹配一下上面第一个学弟帅哥的照片,激发一下学习欲望)。

我做了总结和扩充,从真实世界到前端,从大前端看 Web。

写一个 Demo 解释一下吧~�请忽视我的“高耦合”:

<!-- HTML 标签是由尖括号包围的关键词,比如 <html>,用来描述网页 -->
<html>
    <head>
        <title>这是我的第一个页面。</title>
    </head>
    <!-- Web 浏览器的作用是读取 HTML 文档,并以网页的形式显示出它们 -->
    <body>
        <h1>这是我的第一个大标题。</h1>
        <!-- HTML 标签通常是成对出现的,比如 <b> 和 </b> -->
        <p>这是我的第一个段落。</p>
        <br/>
        <hr/>
        <h2>我比大标题小那么一丢丢</h2>
        <p><a>这是我的第一个链接</a></p>
        <p>别跑,我的头像好帅气</p>
        <!-- 即将插入一个图像,虽然源码的耦合度不同 -->
        <p>![](https://avatars1.githubusercontent.com/u/19285461?v=3&s=460)</p>
    </body>
</html>

这场名曰“ Web 全栈”的活动,怎么能不讲讲 Web 的背景?

好巧的是,查资料的时候,看到万维网之父刚刚获得图灵奖,实至名归,激动万分。

JavaScript + ChromeDevTool

相比“PHP 是世界上最好的语言”,JavaScipt 应该算是世界上最“全能”的语言了。JS 从最初的网页前端交互到现在的 Web 前后端、移动端混合应用、物联网甚至 AR、VR ,无所不在。毕竟,Atwood 定律告诉我们:

凡是可以用 JavaScript 来写的应用,最终都会用 JavaScript 来写。

https://ppt.baomitu.com/d/e3804f96#

来场实战,想必在座的大学生大多都不怎么关注自己的“专业培养计划”,结合代码实战,来在西邮官网上实战抓取专业培养计划,利用了 JS 的 DOM 操作。

http://222.24.62.120

var v1 = document.getElementsByTagName("table")[2];
var nameArr = [];
var classCount = v1.childNodes[1].childElementCount - 1;
for (var i = 0; i < classCount; i++) {
    var name = v1.childNodes[1].childNodes[i+1].childNodes[2].innerHTML;
    var nature = v1.childNodes[1].childNodes[i+1].childNodes[6].innerHTML;
    if (nature === "选修课") {
        name += "(选)"
    }
    nameArr.push(name);
}
console.log(nameArr.join(","));

是否是选修课也进行了判断,最终获得到四年培养计划的所有课程,短短的 JS 代码避免了多少手工记录,还加深了多少 DOM 知识呢?

发完讲师的照片就跑真刺激。(谁让比他大一级,逃。。

这个是大一服务端学弟哦 q(´・ω・`)p

freeCodeCamp

啊啊啊,这个在线 JS 全栈编程平台向别人介绍的太多了。直接放图和链接吧!在早上的活动最后,向大家推荐了这个全球性开源编程社区平台。

Why...Why...Why always me to create blogs to review and share -- Virgo Me.

除了左下角的各大其他城市线下 JS 编程活动缩影外,其他三张都是我组织的 FCC 西安线下编程活动。认识到了五湖四海的大家。

8 小时的活动~!干货很多,软技能很多,怎么不来点 VIDEO不能白白浪费了免费 Wi-Fi,大大的投影和热情参与的同学们啊,俩个视频来分享。相关链接可以在 Youtube、优酷等国内外平台搜在这里就不给你们贴链接了,劳动劳动更有意义吧~。

从上面的第一个视频可以总结到,今天的程序员是未来的巫师,掌握着改造世界的方法。影片贯穿着生动的全球 IT 牛人变成回忆录:

  • 比尔·盖茨,1955年10月28日出生,13 岁接触计算机,18岁考入哈佛大学,一年后从哈佛退学,接着与好友保罗·艾伦一起创办了美国微软公司。美国富豪400强榜单常居榜首。
  • 杰克·多西,1976年11月19日出生,8 岁有自己的 Machintosh。2008 年 成为 Twitter 联合创始人兼CEO。
  • 马克·扎克伯格,1984年05月14日生于美国纽约州白原市,小学 6 年级开始学编程,2004 年推动 Facebook 正式上线。
  • 克里斯·波什,1984 年出生,美国职业篮球运动员,NBA 全明星。

绝对不会告诉你们的是,《TED 编织我的梦》这部 TED 演讲我在去年面向大一新生的 DIY 电脑俱乐部软件部第一次分享的主讲过程中就放映过,也认识到了这次的几位服务端大一学弟,实则,成功圈粉一大波迷弟。

我们,不要忘记用孩子的视角理解编程世界。

乱入我在去年 DIY 电脑俱乐部软件部主讲的分享文章,和缩影一张。

漫游C世界--DIY软件部编程之旅

秀秀秀 迷迷迷

没办法,我就是爱玩。哎,快大三了,这病,得治。

可能是我的“同性相惜(吸)”的气质太浓重了罢,短暂的午饭和午休过后,到了下午进行服务端分享的时候,早上的女生,就剩通院科协参与组织的了。

迷弟们,你们走吧,我想静静。( ತಎತ)

Full-Stack-Developer

什么是全栈工程师?我们该不该以全栈工程师为奋斗目标?我们又能从全栈工程师的方向中学习到什么?这里凝聚了我的感悟。

详细内容,记得去看看 我的第一个开源电子书:Little-FSD

[github@bmorelli25/Become-A-Full-Stack-Web-Developer](https://github.com/bmorelli25/Become-A-Full-Stack-Web-Developer)

正如精读和粗读,广度和深度也是永远矛盾的话题,先来一波知乎黑。

全栈黑~

当然,我不这么认为,我理解的“全栈工程师”的重点不在于去复古曾经最早的下搞电路设计,中写汇编代码,上知设计模式的“全能程序员”,而是新时代的,拥有极强学习能力的编程“终生学习者”。

公司的事,就是你的事,不要局限在自己的职位内。转译自 Facebook。

从软件工程思考到的全栈工程师从某种角度可以说,就是产品运营、运营经理、视觉设计、前端工程师、服务端工程师,统统吃一口。下图是我在去年为我所在的 CreatShare 互联网实验室纳新准备的组织结构图可以参考。

关于这次活动的技术点,我也快速画在了概念图中,以做头脑风暴:Web 前端,Web 后端,框架、平台、工具、基础知识点等等。。

驾驭头脑风暴

Linux + Apache

从下图链接中学弟的 PPT 中可以学习到,Linux 操作系统的基础知识和用法以及 Apache 服务器的用处、须知。这是我见过的,最详细的 PPT 没有之一。。

git@icorvoh/Little-FSD

偷一张 PPT 放到这里:

PHP + MySQL

PHP。。我的大一便以服务端做为方向,PHP 作为学习语言来学习,在一定的了解过后,前后端的通吃的时间、精神压力下,终于选择了 JavaScript 作为找工作时的重点语言。PHP + MySQL 便是最后一位大一学弟的分享。

git@icorvoh/Little-FSD

可以在 Windows 平台安装 XAMPP 的 PHP 运行环境傻瓜包,或在 MacOS、Linux 下更难更干货地安装开发环境,进行Apache、PHP 、MySQL的深入学习。这里贴一段代码,看看 PHP 怎么链接数据库,So Easy!

<?

$conn=mysql_connect('localhost','root','');  
//状态  
if(!$conn){  
echo "connection failed";  
exit;  
}  
  
//选择数据库  
$sql='use student';  
//conn通道进行  
$rs=mysql_query($sql,$conn);  
//设置字符集  
$sql='set names utf8';  
mysql_query($sql,$conn);  

?>

PHP 当然必须得有收接 HTTP 请求的能力,比如处理 GET、POST 请求:

还可以模拟客户端发送 GET、POST 请求哦,就让爬虫开始吧。

可以用 postman 这类的 HTTP API 模拟工具实战。

真正的 Web 全栈工程师,是不需要依赖浏览器的。 -- 引用自 phantomjs 官网。

架构之战

到了这里,活动也接近尾声,分享的内容慢慢,但后端也只涉及了 LAMP 架构,即 Linux + Apache + MySQL + PHP,常被用来做传统的多页面网站。然而还有 MEAN 架构、.net 等等开发架构,可以幽默的解释为什么我们要学习后端?

MEAN 架构,发扬了 Web 单页面应用的存在需求。MEAN 便是基于 JavaScript 的全栈框架 MongDB、Express.js、Angular.js、Node.js 。freeCodeCamp 在线编程平台便是用 MEAN 架构实现。技术没有优劣性,开发者可以择一而入。

LAMP V.S Node.JS

另外俩个大一服务端学弟也在这里,能看出来吗?就是站着的俩位(逃。

最后俩个大一学弟在哪里 ( _  ͡° ͜ʖ ͡° )_

我,终于,露脸了,围观请打赏~Two Three Three。

我在 DIY 电脑俱乐部软件部分享的回顾文章里就以下面这段话结尾:

分享到最后时间也晚了,教室也要关门了。这次分享结束,但人生未尝不是一次重新开始~

是啊,这次,再一次重新开始,再一次与众不同,期待未来的更加精彩吧!

git@icorvoh/Little-FSD

全栈,是一种心态!

[A0E]三种程序设计语言概要

引言

毕竟西邮编程气氛浓厚,加上大神学长学姐的支持和学弟学妹对编程的兴趣,上一篇简书文章《浅谈C语言历史》的分享效果还可以,自己在校内建立的编程讨论群短短几天就有了两百多的成员,并开始以内部推荐的形式邀请新成员一同加入学习编程的氛围。好的分享内容才能引发持续交流,这一期,我们来简单了解下三种程序设计语言 -- 机器语言、汇编语言和高级语言的区别与联系,做好充足的准备迎接编程成长之路。

语言只是工具,不要过早的去想着如何编写代码。
要让自己的第一个 “Hello World” 敲得振振有力。

第一台通用计算机 -- ENIAC

由于第二次世界大战的需要,历经4年的科研与实践,世界上第一台通用计算机、第二台电子计算机 ENIAC(Electronic Numerical Integrator And Calculator)于 1946 年 2 月 14 日在美国宾夕法尼亚大学宣告诞生,标志着计算机时代的到来。

世界上第一台通用计算机 ENIAC

ENIAC 是基于真空管技术研发的第一代计算机,无操作系统,采用机器指令或汇编语言编程,下图便是编程语言的层次结构,具体概念将一一道来。

编程语言的层次结构

机器语言

机器语言(机器码)是用二进制代码(只包含“0”和“1”的代码)表示的、计算机能直接识别和执行的一种机器指令的集合。最早的计算机直接靠机器语言运行,输入方法是靠打孔带(一个条带上面有实心空心的小点,对应1和0)。后来出现了磁带,但指令输入的本质没有改变。
通俗来讲,那时需要靠科研人员给计算机一段对应 0 和 1 的打孔带,计算机才能执行相应的操作并返回预期的结果。

用机器语言与计算机沟通

这些包含 “0”、“1” 的二进制机器码具有灵活、直接执行和速度快的特点,可以根据计算机设计者的实际需要直接操作计算机的硬件结构。但由于机器语言与硬件构造密切相关,每个计算机的硬件也不尽相同,因此不同型号的计算机其机器语言是不相通的,按照一种计算机的机器指令编制的程序,不能在另一种计算机上执行。

一个机器语言源码示例

二进制的机器语言也是有规则的,每一串相应的01映射着一条特定的指令。

机器语言的简要实例

计算机发展至今,除了计算机生产厂家的专业人员外,绝大多数的程序员已经不用再去学习机器语言了。

汇编语言

汇编语言(符号语言)是将二进制的机器码通过助记符的方式让人可以更方便地编写并检查的低级语言。汇编语言接近机器语言,可以看做是机器语言的另一种形式,计算机在运行时也需要将汇编语言变为机器语言的二进制形式才可运行,这两种语言都是面向机器的语言,和具体机器的指令系统密切相关。

一个汇编语言源码示例

汇编语言的特点:

  1. 面向机器的低级语言,通常是为特定的计算机或系列计算机专门设计的。
  2. 保持了机器语言的优点,具有直接和简捷的特点。
  3. 可有效地访问、控制计算机的各种硬件设备,如磁盘、存储器、CPU、I/O端口等。
  4. 目标代码简短,占用内存少,执行速度快,是高效的程序设计语言。
  5. 经常与高级语言配合使用,应用十分广泛。

汇编语言在编程发展史中承前启后,它第一次摆脱了机器语言的束缚,进入到以接近人类语言为发展目标的时代。

高级语言

高级语言是相对于汇编语言而言的,它是较接近自然语言和数学公式的编程,基本脱离了机器的硬件系统,用人们更易理解的方式编写程序,但机器是无法直接执行的,需要最终编译链接成二进制的机器代码才可被计算机直接执行。

高级语言并不特指某一种具体编程语言,而是包括很多编程语言在内。如目前流行的 JAVA 、 C 、 C++ 、 C# 、 Pascal 、 Python 、 PHP 、VC 语言等等,这些语言的语法、命令格式不尽相同。

一个简单的高级语言程序 -- C语言

因此将程序设计语言从机器语言抽象到高级语言,带来的主要好处是:

  • 高级语言接近算法语言,易学、易掌握,一般工程技术人员只要几周时间的培训就可以胜任程序员的工作;
  • 高级语言为程序员提供了结构化程序设计的环境和工具,使得设计出来的程序可读性好,可维护性强,可靠性高;
  • 高级语言远离机器语言,与具体的计算机硬件关系不大,因而所写出来的程序可移植性好,重用率高;
  • 由于把繁杂琐碎的事务交给了编译程序去做,所以自动化程度高,开发周期短,且程序员得到解脱,可以集中时间和精力去从事对于他们来说更为重要的创造性劳动,以提高程序的质量。

编译型语言和解释型语言

高级语言又分编译型语言(C、C++等)和解释型语言(JAVA、JavaScript、PHP等),虽然最终都需要编译成机器语言才能被计算机识别和执行但是——

  • 编译型语言需要将源码一并地转换成机器语言的程序之后再执行,针对不同计算机结构编译后的机器语言无法跨平台运行;
  • 解释型语言是在运行的时候将程序先编译成字节码(可以理解为一个中间语言),再在运行的时候由运载解释型语言的环境将字节码翻译成机器语言。但这个过程中可以依靠运载环境根据不同的计算机硬件结构生成相应的机器语言,从而具有跨平台的特性。

[A08]C 语言单链表/双向链表的建立/遍历/插入/删除

最近临近期末的C语言课程设计比平时练习作业一下难了不止一个档次,第一次接触到了 C 语言的框架开发,了解了 View(界面层)、Service(业务逻辑层)、Persistence(持久化层)的分离和耦合,一种面向过程的 MVC 的感觉。而这一切的基础就在于对链表的创建、删除、输出、写入文件、从文件读出......本篇文章在于巩固链表的基础知识(整理自《C语言程序设计教程--人民邮电出版社》第十章——指针与链表),只对链表的概念及增删改查作出探讨,欢迎指教。
 

一、链表结构和静态/动态链表

链表是一种常见的数据结构——与数组不同的是:

  1. 数组首先需要在定义时声明数组大小,如果像这个数组中加入的元素个数超过了数组的长度时,便不能正确保存所有内容;链表可以根据大小需要进行拓展。
  2. 其次数组是同一数据类型的元素集合,在内存中是按一定顺序连续排列存放的;链表常用malloc等函数动态随机分配空间,用指针相连。

链表结构示意图如下所示:

在链表中,每一个元素包含两个部分;数据部分和指针部分。数据部分用来存放元素所包含的数据,指针部分用来指向下一个元素。最后一个元素的指针指向NULL,表示指向的地址为空。整体用结构体来定义,指针部分定义为指向本结构体类型的指针类型。

静态链表需要数组来实现,即把线性表的元素存放在数组中。数组单元存放链表结点,结点的链域指向下一个元素的位置,即下一个元素所在数组单元的下标。这些元素可能在物理上是连续存放的,也有可能是不连续的,它们之间通过逻辑关系来连接——这就要涉及到数组长度定义的问题,实现无法预知定义多大的数组,动态链表随即出现。

动态链表指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点的数据,并建立起前后相连的关系。
 

二、单链表的建立与遍历

单链表中,每个结点只有一个指针,所有结点都是单线联系,除了末为结点指针为空外,每个结点的指针都指向下一个结点,一环一环形成一条线性链。链表的创建过程:

接下来在源码中建立并遍历输出一个单链表。

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

/*单向链表*/
struct Student/*建立学生信息结构体模型*/ 
{
    char cName[20];/*学生姓名*/
    int iNumber;/*学生学号*/
    struct student *next;/*指向本结构体类型的指针类型*/
};

int iCount;/*全局变量表示链表长度*/ 

struct Student *Create();/*创建链表函数声明*/ 
void print(struct Student *);/*遍历输出链表函数声明*/

int main()
{
    int insert_n=2;/*定义并初始化要插入的结点号*/
    int delete_n=2;/*定义并初始化要删除的结点号*/
    struct Student *pHead;/*声明一个指向学生信息结构体的指针作pHead为头结点传递*/
    pHead=Create();/*创建链表,返回链表的头指针给pHead*/
    print(pHead);/*将指针pHead传入输出函数遍历输出*/
    return 0; 
}

struct Student *Create()
{
    struct Student *pHead=NULL;/*初始化链表,头指针为空*/ 
    struct Student *pEnd,*pNew;
    iCount=0;/*初始化链表长度*/ 
    pEnd=pNew=(struct Student *)malloc(sizeof(struct Student));/*动态开辟一个学生信息结构体类型大小的空间,使得pEnd和pNew同时指向该结构体空间*/
    scanf("%s",pNew->cName);/*从输入流获取第一个学生姓名*/ 
    scanf("%d",&pNew->iNumber);/*从输入流获取第一个学生学号*/ 
    while(pNew->iNumber!=0)/*设定循环结束条件——学号不为0时*/ 
    {
        iCount++;/*链表长度+1,即学生信息个数+1*/ 
        if(iCount==1)/*如果链表长度刚刚加为1,执行*/ 
        {
            pNew->next=pHead;/*使指针指向为空*/
            pEnd=pNew;/*跟踪新加入的结点*/
            pHead=pNew;/*头结点指向首结点*/
        }
        else/*如果链表已经建立,长度大于等于2时,执行*/ 
        {
            pNew->next=NULL;/*新结点的指针为空*/
            pEnd->next=pNew;/*原来的结点指向新结点*/
            pEnd=pNew;/*pEnd指向新结点*/
        }
        pNew=(struct Student *)malloc(sizeof(struct Student));/*再次分配结点的内存空间*/
        scanf("%s",pNew->cName);/*从输入流获取第一个学生姓名*/ 
        scanf("%d",&pNew->iNumber);/*从输入流获取第一个学生学号*/ 
    }
    free(pNew);/*释放结点空间*/
    return pHead;/*返回创建出的头指针*/ 
}

void print(struct Student *pHead)
{
    struct Student *pTemp;/*定义指向一个学生信息结构体类型的临时指针*/ 
    int iIndex=1;/*定义并出事哈变量iIndex,用来标识第几个学生(信息)*/ 
    printf("总共%d个学生(信息):\n",iCount);
    pTemp=pHead;/*指针得到首结点的地址*/ 
    while(pTemp!=NULL)/*当临时指针不指向NULL时*/ 
    {
        printf("第%d个学生信息:\n",iIndex); 
        printf("姓名:%s",pTemp->cName); /*输出姓名*/
        printf("学号:%d",pTemp->iNumber);/*输出学号*/
        pTemp=pTemp->next;/*移动临时指针到下一个结点*/ 
        iIndex++;/*进行自加运算*/ 
    }
}

三、单链表的插入与删除

在本实例中,插入时根据传递来的学号,插入到其后。删除时根据其所在链表的位置,删除并释放该空间。主函数增加如下:

int main()
{
    int insert_n=2;/*定义并初始化要插入的结点号*/
    int delete_n=2;/*定义并初始化要删除的结点号*/
    struct Student *pHead;/*声明一个指向学生信息结构体的指针作pHead为头结点传递*/
    pHead=Create();/*创建链表,返回链表的头指针给pHead*/
    pHead=Insert(pHead,insert_n);/*将指针pHead和要插入的结点数传递给插入函数*/
    print(pHead);/*将指针pHead传入输出函数遍历输出*/
    Delete(pHead,delete_n);/*将指针pHead和要删除的结点数传递给删除函数*/
    print(pHead);/*将指针pHead传入输出函数遍历输出*/
    return 0; 
}

插入函数:

struct Student *Insert(struct Student *pHead,int number)
{
    struct Student *p=pHead,*pNew;/*定义pNew指向新分配的空间*/ 
    while(p&&p->iNumber!=number)
        p=p->next;/*使临时结点跟踪到要插入的位置(该实例必须存在学号为number的信息,插入其后,否则出错)*/ 
    printf("姓名和学号:\n");
    /*分配内存空间,返回该内存空间的地址*/ 
    pNew=(struct Student *)malloc(sizeof(struct Student));
    scanf("%s",pNew->cName);
    scanf("%d",&pNew->iNumber);
    pNew->next=p->next;/*新结点指针指向原来的结点*/
    p->next=pNew;/*头指针指向新结点*/
    iCount++;/*增加链表结点数量*/ 
    return pHead;/*返回头指针*/ 
}

删除函数:

void Delete(struct Student *pHead,int number)
{
    int i;
    struct Student *pTemp;/*临时指针*/ 
    struct Student *pPre;/*表示要删除结点前的结点*/ 
    pTemp=pHead;/*得到链表的头结点*/ 
    pPre=pTemp;
    for(i=0;i<number;i++)
    {/*通过for循环使得Temp指向要删除的结点*/ 
        pPre=pTemp;
        pTemp=pTemp->next; 
    }
    pPre->next=pTemp->next;/*连接删除结点两边的结点*/ 
    free(pTemp);/*释放要删除结点的内存空间*/ 
    iCount--;/*减少链表中的结点个数*/ 
}

四、双向链表的概念

双向链表基于单链表。单链表是单向的,有一个头结点,一个尾结点,要访问任何结点,都必须知道头结点,不能逆着进行。而双链表添加了一个指针域,通过两个指针域,分别指向结点的前结点和后结点。这样的话,可以通过双链表的任何结点,访问到它的前结点和后结点。

在双向链表中,结点除含有数据域外,还有两个链域,一个存储直接后继结点的地址,一般称为右链域;一个存储直接前驱结点地址,一般称之为左链域。

双向链表结构示意图:

五、双向链表的建立与遍历

双向链表的源码实战和单链表类似,只是多了第二个指针域的控制,这里直接贴上没有注释的源代码。

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define N 10

typedef struct Node
{
    char name[20];
    struct Node *llink,*rlink;
}STUD;

STUD *creat(int);void print(STUD *);

int main()
{
    int number;
    char studname[20];
    STUD *head,*searchpoint;
    number=N;
    head=creat(number);
    print(head);
    printf("请输入你要查找的人的姓名:");
    scanf("%s",studname);
    searchpoint=search(head,studname);
    printf("你所要查找的人的姓名是:%s",*&searchpoint->name); 
    return 0;
}

STUD *creat(int n)
{
    STUD *p,*h,*s;
    int i;
    if((h=(STUD *)malloc(sizeof(STUD)))==NULL)
    {
        printf("不能分配内存空间");
        exit(0);        
    }
    h->name[0]='\0';
    h->llink=NULL;
    h->rlink=NULL;
    p=h;
    for(i=0;i<n;i++)
    {
        if((s=(STUD *)malloc(sizeof(STUD)))==NULL)
        {
        printf("不能分配内存空间");
        exit(0);        
        }
        p->rlink=s;
        printf("请输入第%d个人的姓名",i+1);
        scanf("%s",s->name);
        s->llink=p;
        s->rlink=NULL;
        p=s;
    }
    h->llink=s;
    p->rlink=h;
    return(h);
}

void print(STUD *h)
{
    int n;
    STUD *p;
    p=h->rlink;
    printf("数据信息为:\n");
    while(p!=h)
    {
        printf("%s ",&*(p->name));
        p=p->rlink;
    }
    printf("\n");
}

六、双向链表的元素查找

查找函数 STUD *search(STUD *,char *);

STUD *search(STUD *h,char *x)
{
    STUD *p;
    char *y;
    p=h->rlink;
    while(p!=h)
    {
        y=p->name;
        if(strcmp(y,x)==0)
            return(p);
        else
            p=p->rlink;
    }
    printf("没有查到该数据!");
}

七、循环链表的概念

类似于单链表,循环链表也是一种链式的存储结构,由单链表演化而来。单链表的最后一个结点的指针指向NULL,而循环链表的最后一个结点的指针指向链表头结点。这样头尾相连,形成了一个环形的数据链。循环链表的建立不需要专门的头结点。判断循环链表是否为尾结点时,只需判断该节点的指针域是否指向链表头节点。

八、合并两个链表的实例

建立两个带头节点的学生链表,每个节点包含学号、姓名和成绩,链表都按学号升序排列,将它们合并为一个链表仍按学号升序排列。算法分析:

合并链表用merge()函数实现。函数中定义3个工作指针a、b、c,其中a、b分别指向La链表、Lb链表的当前结点,C指向合并后的链表尾结点。合并后链表的头结点共用La链表的头结点。

  1. 合并前,先让a和b分别指向两个链表的第一个结点,c指向La链表的头结点。
  2. 合并时应该分3种情况讨论,即La和Lb都没有处理完;La没处理完,但Lb处理完毕;Lb没处理完,但La处理完毕。
  3. 合并过程中应始终将La和Lb链表中较小的一个链接在Lc中,方能保持有序。
void merge(struct stud *La,struct stud *Lb)
{
    struct stud *a,*b,*c;
    c=La;
    a=La->next;/* 合并前 */
    b=Lb->next;
    while(a!=NULL && b!=NULL)/* La和Lb都没处理完 */
    {
        if(a->num <= b->num)
        {
            c->next=a;
            c=a;
            a=a->next;
        }
        else
        {
            c->next=b;
            c=b;
            b=b->next;
        }
    }
    if(a!=NULL)
        c->next=a;/* 若La没有处理完 */
    else
        c->next=b;/* 若Lb没有处理完 */
    free(Lb); /* 释放Lb的头结点 */
}

九、实战

亲自将《C语言程序设计教程--人民邮电出版社》第十章——综合实例影片信息管理系统补成一个完整的程序。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 没有
// 每重新进一次main(),都产生一层函数嵌套,很多次后会发生什么 

typedef struct Movie
{
    int id;/*影片编号*/
    char name[20];/*影片名称*/
    char director[10];/*导演*/
    char actor[20];/*主演*/
    char date[10];/*上映日期*/
    float score;/*影片评分*/
    struct Movie *next;/*指向下一个节点的指针*/
}Film;

int iCount;
Film *pMain=NULL;

void menu();/*菜单*/ 
Film *Create();/*创建链表函数声明*/
void printAll(Film *head);/*显示所有影片的信息*/
Film *findFilm(Film *,int);/*查询影片信息*/
void printFilm(Film *Film);/*输出单个影片信息*/
void modifyFilm(Film *,int);/*修改影片信息*/
void deleteFilm(Film *,int);/*删除影片信息*/

/* 统计链表长度,这里由iCount代替 */ 
//int length(Film *);/*显示影片总数*/ 

int main()
{
    menu();
    return 0;
}

void menu()
{
    int choice;
    int id;
    printf("\n\n");
    printf("\t------------------------------------\n");
    printf("\t|     欢迎使用影片信息管理系统     |\n");
    printf("\t------------------------------------\n");
    printf("\t|          1-录入影片信息          |\n");
    printf("\t|          2-查询影片信息          |\n");
    printf("\t|          3-修改影片信息          |\n");
    printf("\t|          4-删除影片信息          |\n");
    printf("\t|          5-显示所有影片          |\n");
    printf("\t|          6-  影片总数            |\n");
    printf("\t|          7-  退出程序            |\n");
    printf("\t请选择功能 1-7 :");
    scanf("%d",&choice);
    getchar();
    system("cls");
    switch(choice)
    {
        case 1:
            pMain=Create(); 
            if(pMain==NULL)
                printf("\t录入出错了 =、=\n");
            else
            {
                system("cls");
                printf("\t成功录入%d个影片信息\n",iCount);
            } 
            menu();
            break;
        case 2:
            if(pMain==NULL)
            {
                printf("\t没有任何影片可供查询\n");
            }
            else
            {
                printf("\t输入查询的id:");
                scanf("%d",&id);
                printFilm(findFilm(pMain,id));
            }
            menu();
            break;
        case 3:
            if(pMain==NULL)
            {
                printf("\t没有任何影片可供修改\n");
            }
            else
            {
                printf("\t输入修改的id:");
                scanf("%d",&id);
                modifyFilm(pMain,id);
                system("cls");
                printf("\t修改成功\n");
            }
            menu();
            break;
        case 4:
            if(pMain==NULL)
            {
                printf("\t没有任何影片可供删除\n");
            }
            else
            {
                printf("\t输入删除的id:");
                scanf("%d",&id);
                deleteFilm(pMain,id); 
                system("cls");
                printf("\t删除成功\n");
            }
            menu();
            break;
        case 5:
            if(pMain==NULL)
            {
                printf("\t没有任何影片可供显示\n");
                menu();
            }
            else
                printAll(pMain);
            menu();
            break;
        case 6:
            printf("\t影片总数为:%d",iCount);
            menu();
            break;
        case 7:
            exit(0);
            break;
        default:
            menu();
            break;
    }
}

Film *Create()
{
    int flag;
    Film *pHead=NULL;
    Film *pNew,*pEnd;
    Film *qq;
    pEnd=pNew=(Film *)malloc(sizeof(Film));
    iCount=0;
    printf("\n\n\t该录入将重新赋值。\n");
    printf("\t请输入影片编号:");
    scanf("%d",&pNew->id);
    printf("\t请输入影片名称:");
    scanf("%s",pNew->name);
    printf("\t请输入导演:");
    scanf("%s",pNew->director);
    printf("\t请输入主演:");
    scanf("%s",pNew->actor);
    printf("\t请输入上映日期:");
    scanf("%s",pNew->date);
    printf("\t请输入影片评分:");
    scanf("%f",&pNew->score);
    printf("\n");
    printf("\t是否继续输入(1继续,其它则退出并返回主菜单):");
    scanf("%d",&flag);
    while(flag==1)
    {
        iCount++;
        if(iCount==1)
        {
            pNew->next=pHead;
            pEnd=pNew;
            pHead=pNew;
        }
        else
        {
            pNew->next=NULL;
            pEnd->next=pNew;
            pEnd=pNew;
        }
        pNew=(Film *)malloc(sizeof(Film));
        printf("\t请输入影片编号:");
        scanf("%d",&pNew->id);
        printf("\t请输入影片名称:");
        scanf("%s",pNew->name);
        printf("\t请输入导演:");
        scanf("%s",pNew->director);
        printf("\t请输入主演:");
        scanf("%s",pNew->actor);
        printf("\t请输入上映日期:");
        scanf("%s",pNew->date);
        printf("\t请输入影片评分:");
        scanf("%f",&pNew->score);
        printf("\n");
        printf("\t是否继续输入(1继续,其它则退出并返回主菜单):");
        scanf("%d",&flag);
    }
    iCount++;
    pNew->next=NULL;
    pEnd->next=pNew;
    pEnd=pNew;
    pNew=(Film *)malloc(sizeof(Film));
    free(pNew);
    return(pHead);
}

void printAll(Film *head)
{
    Film *p=head;
    if(p)/*链表不为空时才输出表头*/ 
    {
        printf("    编号    名称    导演    主演    上映时间    评分    \n");
        printf("--------------------------------------------------------\n");
    }
    while(p)/*遍历链表,输出每个结点的信息*/
    {
        printf("\t%d\t%s\t%s\t%s\t%s\t\t%f\n",p->id,p->name,p->director,p->actor,p->date,p->score);
        p=p->next;
    }
}

Film *findFilm(Film *head,int id)
{
    Film *p=head;
    while(p&&p->id!=id)/*如果p不为空并且p不是要找的结点*/ 
        p=p->next;/*令p指向下一个结点*/ 
    return p;
}

void printFilm(Film *film)
{
    if(!film)/*如果指针为空,即不存在该结点*/ 
        printf("\t%s\n","没有查询到该影片的信息,请检查输入");
    else/*若指针不为空则输出影片信息*/ 
    {
        printf("    编号    名称    导演    主演    上映时间    评分    \n");
        printf("--------------------------------------------------------\n");
        printf("\t%d\t%s\t%s\t%s\t%s\t\t%f\n",film->id,film->name,film->director,film->actor,film->date,film->score);
    }
}

void modifyFilm(Film *head,int id)
{
    Film *p=findFilm(head,id);/*首先查找该id的影片,将结果保存在p中*/ 
    if(p)/*如果查找到影片,则可以修改*/ 
    {
        printf("\t======================================================\n");
        printf("\t               ***** 修改影片信息 *****               \n");
        printf("\t======================================================\n");
        printf("该影片的信息如下:\n");
        printFilm(p);
        printf("\t请输入影片编号:");
        scanf("%d",&p->id);
        printf("\t请输入影片名称:");
        scanf("%s",p->name);
        printf("\t请输入导演:");
        scanf("%s",p->director);
        printf("\t请输入主演:");
        scanf("%s",p->actor);
        printf("\t请输入上映日期:");
        scanf("%s",p->date);
        printf("\t请输入影片评分:");
        scanf("%f",&p->score);
    }
    else
        printf("\t未查询到该影片的信息,请检查输入.\n");
}

void deleteFilm(Film *head,int id)
{
    Film *q,*p=head;
    if(head->id==id)/*如果要删除的是头结点*/ 
    {
        head=(head->next);
        free(p);
    }
    else/*若要删除的不是头结点*/ 
    {
        while(p)/*遍历链表寻找要删除的结点*/ 
        {
            if(p->id==id)
            {
                q->next=p->next;
                free(p);/*释放内存空间*/ 
                break;
            }
            q=p;/*q为p的前驱结点*/ 
            p=p->next;
        }
    }
}

/* 统计链表长度,这里由iCount代替 */ 
//int length(Film *head)/*统计链表长度*/ 
//{
//    Film *p=head;
//    int count=0;
//    while(p)/*遍历链表*/ 
//    {
//        p=p->next;
//        ++count;
//    }
//    return count;
//}

拓展思维、(•̀ᴗ•́)و ̑̑

既然双向链表可以多出一个指针域用来指向前一个结点,用llink和rlink区分这两个指针域;那么有没有可能再多几个指针域来放ulink和dlink呢(指向上面的结点和指向下面的结点)?这样就构成了形象的二维链表而不是一维链表了。当然,在物理内存上这些链表依然是线性关系。理论可以实现,那么三维链表呢?画面太美,有待自己下学期大二学数据结构的时候再拓展。

[A19]充分了解 Git 并入手单人开发

前注1:本文写作用时 5 小时 55 min,预计阅读时间 15 分钟。
前注2:本文基于学习型写作。查阅+写作+总结+迭代同步进行。


ARTICLE.INTRODUCTION.序


Git 作为以命令行为主的免费开源分布式版本控制系统,说简单也简单,说难也绝非易事。本文以快速上手 Git 单人开发为最终目标,贯穿讲解 Git 背景等相关知识,内容较长,却也循序渐进,以期达到融汇贯通的效果,不足之处还望指点。在看本文之前,你最好能够提前了解 Linux 基本命令的使用。


ABOUT.VCS.了解版本控制系统(VCS)


本地版本控制系统(LVCS)

为了解决复制整个项目目录的方式来保存不同的版本问题,人们很久以前就开发了许多种本地版本控制系统,大多都是采用某种简单的数据库来记录文件的历次更新差异。

其中最流行的 RCS 的工作原理是在硬盘上保存补丁集(补丁是指文件修订前后的变化);通过应用所有的补丁,可以重新计算出各个版本的文件内容。

甚至在流行的 Mac OS X 系统上安装了开发者工具包之后,也可以使用 rcs 命令。

集中化版本控制系统(CVCS)

接下来的问题是,如何让在不同系统上的开发者协同工作?于是,集中化的版本控制系统(Centralized Version Control Systems,简称 CVCS)应运而生。这类系统都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。 

这种做法带来了许多好处:每个人都可以在一定程度上看到项目中的其他人正在做些什么,而管理员也可以轻松掌控每个开发者的权限。但考虑到**服务器的单点故障、中心数据库所在的磁盘发生损坏等问题,整个项目的历史记录被保存在单一位置,就有丢失所有历史更新记录的风险。

分布式版本控制系统(DVCS)

于是分布式版本控制系统(Distributed Version Control System,简称 DVCS)面世了。 在这类系统中,像 Git、Mercurial、Bazaar 以及 Darcs 等,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。 这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。 因为每一次的克隆操作,实际上都是一次对代码仓库的完整备份。

更进一步,许多这类系统都可以指定和若干不同的远端代码仓库进行交互。籍此,你就可以在同一个项目中,分别和不同工作小组的人相互协作。 你可以根据需要设定不同的协作流程,比如层次模型式的工作流,而这在以前的集中式系统中是无法实现的。


GET.START.GIT 简史


Git 的由来

同生活中的许多伟大事物一样,Git 诞生于一个极富纷争大举创新的年代。

Linux 内核作为参与人数众广的开源项目,绝大多数维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002年间)。 到 2002 年,整个项目组开始启用一个专有的分布式版本控制系统 BitKeeper 来管理和维护代码,却于 2005 年被开发 BitKeeper 的商业公司结束合作关系,他们收回了 Linux 内核社区免费使用 BitKeeper 的权力。 这就迫使 Linux 开源社区(特别是 Linux 的缔造者 Linux Torvalds)基于使用 BitKcheper 时的经验教训,开发出自己的版本系统 -- Git。 他们对新的系统制订了若干目标来能高效管理类似 Linux 内核一样的超大规模项目(速度和数据量):

  • 速度高
  • 设计简约
  • 对非线性开发模式的强力支持(允许成千上万个并行开发的分支)
  • 完全分布式

自诞生于 2005 年以来,Git 日臻成熟完善,在高度易用的同时,仍然保留着初期设定的目标。 它的速度飞快,极其适合管理大项目,有着令人难以置信的非线性分支管理系统(Git 分支)。

谁在使用 Git

以下是官网上列出的使用 Git 的著名公司、项目,但远不止这些。


DEEP.IN.深入Git


因此,Git 是分布式版本控制系统中很流行的一种, 和其它大部分系统以文件变更列表的方式存储信息对比:后者将它们保存的信息看作是一组基本文件和每个文件随时间逐步累积的差异,而 Git 更像是把数据看作是对小型文件系统的一组快照。

Git 对待数据更像是一个快照流。 

Git 的三个特点

  • 近乎所有操作都是本地执行
    如果你习惯于所有操作都有网络延时开销的集中式版本控制系统,Git 在这方面会让你感到速度之神赐给了 Git 超凡的能量。 因为你在本地磁盘上就有项目的完整历史,所以大部分操作看起来瞬间完成。
    • Git 不需外连到服务器去获取历史,只需要从本地数据库中读取。
    • 直接能从本地计算当前版本与一个月前的版本之间引入的修改。
  • Git 保证完整性
    Git 中所有数据在存储前都计算校验和(Git 使用哈希值),然后以校验和来引用。 若你在传送过程中丢失信息或损坏文件,Git 就能发现。
    • 哈希值看起来是这样: 24b9da6552252987aa493b52f8696cd6d3b00373
    • 实际上,Git 数据库中保存的信息都是以文件内容的哈希值来索引,而不是文件名。
  • Git 一般只添加数据
    你执行的 Git 操作,几乎只往 Git 数据库中增加数据。未提交更新时有可能丢失或弄乱修改的内容,但是一旦你提交快照到 Git 中,就难以再丢失数据,特别是如果你定期的推送数据库到其它仓库的话。

Git 的三种状态

Git 系统上的文件有三种状态已修改(modified)和已暂存(staged)、已提交(committed)。

  • 已修改表示修改了文件,但还没保存到数据库中。
  • 已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。
  • 已提交表示数据已经安全的保存在本地数据库中。

这里便是 git add, git commit, git push 的原理所在。

由此引入 Git 项目的三个工作区域的概念:

  • Git 仓库目录是 Git 用来保存项目的元数据和对象数据库的地方。 这是 Git 中最重要的部分,从其它计算机克隆仓库时,拷贝的就是这里的数据。
  • 工作目录是对项目的某个版本独立提取出来的内容。 这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘上供你使用或修改。
  • 暂存区域是一个文件,保存了下次将提交的文件列表信息,一般在 Git 仓库目录中。 有时候也被称作“索引”,不过一般说法还是叫暂存区域。

Git 的工作流程

  • 在工作目录中修改文件。
  • (git add)暂存文件,将文件的快照放入暂存区域。
  • (git commit)提交更新,找到暂存区域的文件,将快照永久性存储到 Git 仓库目录。

可以用如下命令随时查看 Git 系统中文件的状态:

git status


USE.WAY.Git 使用方式


Git 有多种使用方式。 你可以使用原生的命令行模式,也可以使用 GUI 模式,这些 GUI 软件也能提供多种功能。以下分别介绍这两种模式,首推命令行模式。

使用 Git 的命令行工具【推荐】

只有在命令行模式下你才能执行 Git 的所有命令,而大多数的 GUI 软件只实现了 Git 所有功能的一个子集以降低操作难度。此外,由于每个人的想法与侧重点不同,不同的人常常会安装不同的 GUI 软件,但所有人一定会有命令行工具。

  • 在 Linux 上安装 Git
    如果你想在 Linux 上用二进制安装程序来安装 Git,可以使用发行版包含的基础软件包管理工具来安装。 以下二选一,视具体发行版本而定。
sudo yum install git
sudo apt-get install git

安装 Git 的 GUI 工具

这里只做 Github Desktop 的介绍和推荐,有关 Github 的相关知识点之后提及。

可以看出,Git 的图形化操作比命令行操作用起来要方便也更加直观。多平台的 Github Desktop 将 Git 的图形化操作发挥到了极致。

但重回之前所说,只有在命令行模式下你才能执行 Git 的所有命令,而大多数的 GUI 软件只实现了 Git 所有功能的一个子集以降低操作难度。Git 的 GUI 对使用分布式版本控制的开发者来说还无法普及。


PLATFORM.TOOL.基于 Git 的 Github 代码托管平台


GitHub 是一个面向开源及私有软件项目的托管平台,因为只支持 Git 作为唯一的版本库格式进行托管,故名 GitHub。GitHub 于 2008 年 4 月 10 日正式上线,除了 Git 代码仓库托管及基本的 Web 管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段分享(Gist)等功能。目前,其注册用户已经超过350万,托管版本数量也是非常之多,其中不乏知名开源项目 Ruby on Rails、jQuery 等。

放入自己的开源项目,实战的同时还能帮助需要的人,多么有意义。


SINGLE.DEVELOPMENT.实战 Git 单人开发


于是到了实战环节,基于命令行模式,开始我们的 Git 单人开发。

01.配置 Git 基本信息

Git 自带一个 git config 的工具来帮助设置控制 Git 外观和行为的配置变量。 这些变量存储在三个不同的位置:

  • /etc/gitconfig 文件: 包含系统上每一个用户及他们仓库的通用配置。 如果使用带有 --system 选项的 git config 时,它会从此文件读写配置变量。
  • ~/.gitconfig 或 ~/.config/git/config 文件:只针对当前用户。 可以传递 --global 选项让 Git 读写此文件。
  • 当前使用仓库的 Git 目录中的 config 文件(就是 .git/config):针对该仓库。

每一个级别覆盖上一级别的配置,所以 .git/config 的配置变量会覆盖 /etc/gitconfig 中的配置变量。

在 Windows 系统中,Git 会查找 $HOME 目录下(一般情况下是 C:\Users$USER )的 .gitconfig 文件。 Git 同样也会寻找 /etc/gitconfig 文件,但只限于 MSys 的根目录下,即安装 Git 时所选的目标位置。

如上图,安装好 Git 之后就应该去配置自己的用户名和邮箱号,因为每一个 Git 的提交都会使用这些信息,并且它会写入到你的每一次提交中,不可更改。很多 GUI 工具都会在第一次运行时帮助你配置这些信息。

git config --global user.name "icorvoh"
git config --global user.email "[email protected]"
git list

02.添加 Git 忽略文件

有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件,再比如Node 模块也是这样,只需把项目所需依赖名添加至 package.json 中,克隆到本地后本地安装依赖即可。

这就需要用到 Git 的 .gitignore 文件。Git 对于 .ignore 配置文件是按行从上到下进行规则匹配的,意味着如果前面的规则匹配的范围更大,则后面的规则将不会生效。下面列举几个常用的配置语法。

  • 以斜杠“/”开头表示目录;
  • 以星号“*”通配多个字符;
  • 以问号“?”通配单个字符
  • 以方括号“[]”包含单个字符的匹配列表;
  • 以叹号“!”表示不忽略(跟踪)匹配到的文件或目录;

.gitignore 文件一般不存在,需要在仓库根目录下手动创建。

03.创建本地仓库

选择工作目录创建仓库,这里命名为“gittest”。

mkdir gittest

进入 gittest 文件夹

cd gittest

04.初始化版本库

新建的文件夹并不是 git 仓库,需要在根目录里面进行初始化。

git init

初始化正常情况下应该得到如下命令行反馈:

Initialized empty Git repository in <Git 仓库文件所对应的绝对路径>

初始化成功会发现新的 Git 仓库中多出了一个 .git 隐藏文件夹。用编辑器打开可以看到,.git 隐藏文件夹是 git init 后在当前目录生成的一个管理 git 仓库的文件夹,这里存储着 git 你现在检出(checkout)的文件,当你在项目不同分支切换时,工作目录里的文件经常会被替换和删除。所有历史信息都保存在当前目录中。

  • hooks:这个目录存放一些 shell 脚本,可以设置特定的git命令后触发相应的脚本;在搭建 gitweb 系统或其他 Git 托管系统会经常用到 hook script。
  • info:包含仓库的一些信息
  • logs:保存所有更新的引用记录
  • objects:该目录存放所有的Git对象,对象的SHA1哈希值的前两位是文件夹名称,后38位作为对象文件名。
  • refs:具体的引用,Reference Specification,这个目录一般包括三个子文件夹,heads、remotes和tags,比如,heads中的master文件标识了项目中的master分支指向的当前commit,其他类似。
  • COMMIT_EDITMSG:保存最新的commit message,Git系统不会用到这个文件,只是给用户一个参考
  • config:这个是GIt仓库的配置文件
  • description:仓库的描述信息,主要给gitweb等git托管系统使用
  • index:这个文件就是我们前面提到的暂存区(stage),是一个二进制文件
  • HEAD:这个文件包含了一个分支(branch)的引用,通过这个文件Git可以得到下一次commit的parent
  • ORIG_HEAD:HEAD指针的前一个状态

05.添加与提交

之前的两步已经建立好了一个空的 Git 仓库,开始添加新文件。

touch README.md
git add README.md
git commit -m "init"

06.创建和删除分支

几乎每一种版本控制系统都以某种形式支持分支。使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作。和许多其他版本控制系统不同,Git 鼓励在工作流程中频繁使用分支与合并,哪怕一天之内进行许多次都没有关系。在创建仓库的时候,master 是“默认的”。在其他分支上进行开发,完成后再将它们合并到主分支上。

创建一个叫做“feature_x”的分支,并切换过去:

git checkout -b feature_X

切换回主分支:

git checkout master

再把新建的分支删掉:

git branch -d feature_x

分支的版本回退:

git reset HEAD~3

除非你将分支推送到远端仓库,不然该分支就是不为他人所见的:

git push origin master

07.更新与合并

要更新你的本地仓库至最新的改动,执行如下命令以在工作目录中获取(fetch)并合并(merge)远端的改动。

git pull

要合并其他分支到你的当前分支,可以执行如下命令。

git merge <branch>

两种情况下,git 都会尝试去自动合并改动。不幸的是,这可能导致产生需要自己手动合并的冲突(conflicts)。改完冲突后,执行以下命令标记合并成功:

git add <filename>

在合并改动之前,可以使用如下命令查看:

git diff <source_branch> <target_branch>

08.日志操作

大雁塔酒店。

git log

09.撤销与修改

用来撤销最后一次 git add files,你也可以用 git reset 撤销所有暂存区域文件。

git reset -- files

把文件从暂存区域复制到工作目录,用来丢弃本地修改。

git checkout -- files

通常,一个合并会产生一个合并提交(commit),把两个父分支里的每一行都合并起来。

git reset --hard HEAD

修改 git commit 时填错的错误信息

git commit --amend

但是,如果当前分支和另一个分支没有内容上的差异(即冲突),git就会执行一个"快速向前(fast-forward)"操作,git不会创建新的提交,只是将当前分支指向合并进来的分支。

10.生成 SSH 密钥

为了使本地仓库和远端安全链接,于是到了这一步。

SSH key提供了一种与 GitHub 通信的方式,通过这种方式,能够在不输入密码的情况下,将GitHub作为自己的remote端服务器,进行版本控制。分为如下三步。

  • 查看 SSH 密钥是否存在,如果有则备份删除。
cd ~/.ssh
  • 生存密钥,过程中可直接按回车。
ssh-keygen -t rsa -C "[email protected]"

最后得到两个文件:id_rsa 和 id_rsa.pub 并获取其中密钥

cat ~/.ssh/id_rsa.pub

  • 在代码托管平台(这里是 Github )中添加公钥。

11.创建远端仓库

这里用到的是对 Git 版本控制系统运用最好的全球最大代码托管平台兼同性交友平台 -- Github。创建好自己的 Github 账号并邮箱验证后便可以创建 Git 远端新仓库。这里创建一个和本地同名的仓库“gittest”。

12.绑定本地到远端仓库

由于之前的操作都只是本地的,没有对远端仓库进行任何绑定,需要如下命令。

git remote add origin https://github.com/icorvoh/gittest.git

这里链接到了我的 github 地址的 gittest 仓库。这时我的仓库是这样子的,什么都没有。

13.推送改动

在进行 git commit -m "" 后所有改动已经在本地仓库的 HEAD 中了。执行如下命令以将这些改动提交到远端仓库:

git push origin master

再次刷新 github 远端仓库,发现改动推送成功。

14.克隆远端仓库

从执行如下命令以创建一个本地仓库的克隆版本。

git clone /path/to/repository

如果是远端服务器上的仓库,你的命令会是这个样子。

git clone username@host:/path/to/repository


git 常用命令清单


git init # 初始化本地git仓库(创建新仓库)
git config --global user.name "xxx" # 配置用户名
git config --global user.email "[email protected]" # 配置邮件
git config --global color.ui true # 
git status等命令自动着色
git config --global color.status autogit config --global color.diff autogit config --global color.branch autogit config --global color.interactive autogit config --global --unset http.proxy # remove proxy configuration on gitgit clone git+ssh://[email protected]/VT.git # clone远程仓库
git status # 查看当前版本状态(是否修改)
git add xyz # 添加xyz文件至indexgit add . # 增加当前子目录下所有更改过的文件至index
git commit -m 'xxx' # 提交
git commit --amend -m 'xxx' # 合并上一次提交(用于反复修改)
git commit -am 'xxx' # 将add和commit合为一步
git rm xxx # 删除index中的文件
git rm -r * # 递归删除
git log # 显示提交日志
git log -1 # 显示1行日志 -n为n行
git log -5
git log --stat # 显示提交日志及相关变动文件
git log -p -m
git show dfb02e6e4f2f7b573337763e5c0013802e392818 # 显示某个提交的详细内容
git show dfb02 # 可只用commitid的前几位
git show HEAD # 显示HEAD提交日志
git show HEAD^ # 显示HEAD的父(上一个版本)的提交日志 ^^为上两个版本 ^5为上5个版本
git tag # 显示已存在的tag
git tag -a v2.0 -m 'xxx' # 增加v2.0的tag
git show v2.0 # 显示v2.0的日志及详细内容
git log v2.0 # 显示v2.0的日志
git diff # 显示所有未添加至index的变更
git diff --cached # 显示所有已添加index但还未commit的变更
git diff HEAD^ # 比较与上一个版本的差异
git diff HEAD -- ./lib # 比较与HEAD版本lib目录的差异
git diff origin/master..master # 比较远程分支master上有本地分支master上没有的
git diff origin/master..master --stat # 只显示差异的文件,不显示具体内容
git remote add origin git+ssh://[email protected]/VT.git # 增加远程定义(用于push/pull/fetch)
git branch # 显示本地分支
git branch --contains 50089 # 显示包含提交50089的分支
git branch -a # 显示所有分支
git branch -r # 显示所有原创分支
git branch --merged # 显示所有已合并到当前分支的分支
git branch --no-merged # 显示所有未合并到当前分支的分支
git branch -m master master_copy # 本地分支改名
git checkout -b master_copy # 从当前分支创建新分支master_copy并检出
git checkout -b master master_copy # 上面的完整版
git checkout features/performance # 检出已存在的features/performance分支git checkout --track hotfixes/BJVEP933 # 检出远程分支hotfixes/BJVEP933并创建本地跟踪分支
git checkout v2.0 # 检出版本v2.0
git checkout -b devel origin/develop # 从远程分支develop创建新本地分支devel并检出
git checkout -- README # 检出head版本的README文件(可用于修改错误回退)
git merge origin/master # 合并远程master分支至当前分支
git cherry-pick ff44785404a8e # 合并提交ff44785404a8e的修改
git push origin master # 将当前分支push到远程master分支
git push origin :hotfixes/BJVEP933 # 删除远程仓库的hotfixes/BJVEP933分支
git push --tags # 把所有tag推送到远程仓库
git fetch # 获取所有远程分支(不更新本地分支,另需merge)
git fetch --prune # 获取所有原创分支并清除服务器上已删掉的分支
git pull origin master # 获取远程分支master并merge到当前分支
git mv README README2 # 重命名文件README为README2
git reset --hard HEAD # 将当前版本重置为HEAD(通常用于merge失败回退)
git rebase
git branch -d hotfixes/BJVEP933 # 删除分支hotfixes/BJVEP933(本分支修改已合并到其他分支)
git branch -D hotfixes/BJVEP933 # 强制删除分支hotfixes/BJVEP933git ls-files # 列出
git index包含的文件
git show-branch # 图示当前分支历史
git show-branch --all # 图示所有分支历史
git whatchanged # 显示提交历史对应的文件修改
git revert dfb02e6e4f2f7b573337763e5c0013802e392818 # 撤销提交dfb02e6e4f2f7b573337763e5c0013802e392818
git ls-tree HEAD # 内部命令:显示某个git对象
git rev-parse v2.0 # 内部命令:显示某个ref对于的SHA1 HASHgit reflog # 显示所有提交,包括孤立节点
git show HEAD@{5}
git show master@{yesterday} # 显示master分支昨天的状态
git log --pretty=format:'%h %s' --graph # 图示提交日志
git show HEAD~3
git show -s --pretty=raw 2be7fcb476git stash # 暂存当前修改,将所有至为HEAD状态
git stash list # 查看所有暂存
git stash show -p stash@{0} # 参考第一次暂存
git stash apply stash@{0} # 应用第一次暂存
git grep "delete from" # 文件中搜索文本“delete from”git grep -e '#define' --and -e SORT_DIRENTgit gcgit fsck
  • Hello,我是韩亦乐,现任本科软工男一枚。软件工程专业的一路学习中,我有很多感悟,也享受持续分享的过程。如果想了解更多或能及时收到我的最新文章,欢迎订阅我的个人微信号:韩亦乐。简书的个人主页中,也有我的订阅号二维码和 Github 项目地址。
  • 本文内部编号“A0D”,同时采用【知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议】进行许可。

Some little ideas

About your instructiions,I have readed.
some suggestions:
1,Software Development Environment not only is IDE, it has something else.
2,you can instruct some foreigin website more than home.
3,why the framework is only frontend?

[B10]十大经典排序算法 C 语言实现[上]冒泡选择插入希尔归并

最早拥有排序概念的机器出现在 1901 至 1904 年间由 Hollerith 发明出使用基数排序法的分类机,此机器系统包括打孔,制表等功能,1908 年分类机第一次应用于人口普查,并且在两年内完成了所有的普查数据和归档。
Hollerith 在 1896 年创立的分类机公司的前身,为电脑制表记录公司(CTR)。他在电脑制表记录公司(CTR)曾担任顾问工程师,直到1921年退休,而电脑制表记录公司(CTR)在1924年正式改名为IBM。
---- 摘自《维基百科 - 插入排序》

期中已到,期末将至。《算法设计与分析》的“预习”阶段藉此开始~。在众多的算法**中,如果你没有扎实的数据结构的功底,不知道栈与队列,哈希表与二叉树,不妨可以从排序算法开始练手。纵观各类排序算法,常见的、经典的排序算法将由此篇引出。

排序算法的输出必须遵守的下列两个原则:

  • 输出结果为递增序列(递增是针对所需的排序顺序而言)
  • 输出结果是原输入的一种排列、或是重组

十大经典排序算法

十大经典的排序算法及其时间复杂度和稳定性如上表所示。判断一个排序算法是否稳定是看在相等的两个数据排序算法执行完成后是否会前后关系颠倒,如若颠倒,则称该排序算法为不稳定,例如选择排序和快速排序。

排序前:(4, 1) (3, 1) (3, 7)(5, 6)

排序后:(3, 1) (3, 7) (4, 1) (5, 6) (稳定,维持次序)
排序后:(3, 7) (3, 1) (4, 1) (5, 6) (不稳定,次序被改变)

00.交换两个整数的值

接下来十个经典排序算法的详细探讨缺少不了交换两个整数值的掌握,这里回顾一下其中三种方交换法:用临时变量交换两个整数的值(SwapTwo_1)、不用第三方变量交换两个整数的值(SwapTwo_2)、使用位运算交换两个整数的值(SwapTwo_3)。其中用临时变量交换两个整数的值效率最高,后俩者只适用于内置整型数据类型的交换,并不高效。

void SwapTwo_1 (int *a, int* b) {
    int temp;
    temp = *a;
    *a = *b;
    *b = temp;
}
void SwapTwo_2 (int *a, int *b) {
    *a = *a + *b;
    *b = *a - *b;
    *a = *a - *b;
}
void SwapTwo_3 (int *a, int *b) {
	*a ^= *b;
	*b ^= *a;
	*a ^= *b;
}

01. 冒泡排序(BubbleSort)

先不说公司面试笔试,大学实验室的纳新题里最常有的就是冒泡排序。冒泡排序重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。由于它的简洁,冒泡排序通常被用来对于程序设计入门的学生介绍算法的概念。

冒泡排序 - @Visualgo

上图可见,冒泡排序算法的运作如下:

  • 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
  • 针对所有的元素重复以上的步骤,除了最后一个。
  • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

通俗来讲,整个冒泡排序就是通过两次循环,外层循环将此轮最大(小)值固定到此轮尾部,内层循环“冒泡”比较相邻的两个元素并决定是否交换位置。

从上图也可理解冒泡排序如何将每一轮最大(小)值固定到此轮尾部:尾部总为有序状态,前面无序状态区根据大小规则冒泡向后方传递最值。

/*
 * 冒泡排序。每次外循环将最值固定到数组最后
 * @param: {int []} arr
 * @param: {int} len
 * @return null;
 */
void BubbleSort (int arr[], int len) {
	int i, j, temp;
	for (int i = 0; i < len - 1; i++) {
		// 每趟 i 循环将最大(小)值固定到最后一位
		for (int j = 0; j < len - 1 - i; j++) {
			// 每趟 j 循环循环没有被固定到后方的数字
			if (arr[j] > arr[j + 1]) {
				// arr[j] < arr[j + 1] 代表从小到大排序
				temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}

更多十大经典排序算法请戳我的 Github 仓库 @LeetCode-C

02. 选择排序(SelectionSort)

选择排序首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

选择排序的主要优点与数据移动有关。如果某个元素位于正确的最终位置上,则它不会被移动。选择排序每次交换一对元素,它们当中至少有一个将被移到其最终位置上,因此对n个元素的表进行排序总共进行至多n-1次交换。在所有的完全依靠交换去移动元素的排序方法中,选择排序属于非常好的一种。

上图左下角和右上角可以分别看做排序序列起始位置(已排序区)和排序序列末尾(未排序区),左下角一直稳定更新,但选择排序不稳定,即排序后曾经相同的两个元素的前后位置关系可能会发生颠倒。

/*
 * 选择排序。每次外循环选择最值固定到数组开始
 * @param: {int []} arr[]
 * @param: {int} len
 * @return null;
 */
void SelectionSort (int arr[], int len) {
    int i, j, temp, min;
    for (i = 0; i < len - 1; i++) {
    	min = i;
    	for (j = i + 1; j < len - 1; j++) {
    		if (arr[min] > arr[j]) {
    			// 只需找到最小的值的位置后一次性替换
    			min = j;
    		}
    		temp = arr[min];
    		arr[min] = arr[i];
    		arr[i] = temp;
    	}
    }
}

更多十大经典排序算法请戳我的 Github 仓库 @LeetCode-C

03. 插入排序(InsertionSort)

插入排序的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用 in-place
排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

一般来说,插入排序都采用 in-place 在数组上实现。具体算法描述如下:

  • 从第一个元素开始,该元素可以认为已经被排序
  • 取出下一个元素,在已经排序的元素序列中从后向前扫描
  • 如果该元素(已排序)大于新元素,将该元素移到下一位置
  • 重复步骤 3,直到找到已排序的元素小于或者等于新元素的位置
  • 将新元素插入到该位置后
  • 重复步骤 2~5

如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目。该算法可以认为是插入排序的一个变种,称为二分查找插入排序。这里先不做涉及。

/*
 * 插入排序。前面有序的数字循环向后留给满足条件的第一个无序数字
 * @param: {int []} arr
 * @param: {int} len
 * @return null;
 */
void InsertionSort (int arr[], int len) 
{
    int i, j, temp;
    for (i = 1; i < len; i++) {
        // 与已排序的数逐一比较,大于 temp 时,该数向后移
        temp = arr[i];
        // 如果将赋值放到下面的for循环内, 会导致在第10行出现 j 未声明的错误
        j = i - 1;
        for (; j >= 0 && arr[j] > temp; j--) {
            // j 循环到-1时,由于短路求值,不会运算 arr[-1]
            arr[j + 1] = arr[j];
        }
        arr[j + 1] = temp; 
        // 被排序数放到正确的位置
    }
}

更多十大经典排序算法请戳我的 Github 仓库 @LeetCode-C

04. 希尔排序(ShellSort)

希尔排序按其设计者希尔(Donald Shell)的名字命名,该算法由1959年公布。希尔排序也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。希尔排序是基于插入排序的以下两点性质而提出改进方法的:

  • 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
  • 插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位

希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。

以23, 10, 4, 1的步长序列进行希尔排序。

步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。

已知的最好步长序列是由 Sedgewick 提出的(1, 5, 19, 41, 109,...),这项研究也表明“比较在希尔排序中是最主要的操作,而不是交换。”用这样步长序列的希尔排序比插入排序要快,甚至在小数组中比快速排序和堆排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢。

/*
 * 希尔排序。
 * @param: {int []} arr
 * @param: {int} len
 * @return null;
 */
void ShellSort(int arr[], int len) {
    int gap, i, j;
    int temp;
    for (gap = len >> 1; gap > 0; gap >>= 1) {
        // gap 为间隔,每次间隔折半
        for (i = gap; i < len; i++) {
            // 循环该轮数组后半段
            temp = arr[i];
            for (j = i - gap; j >= 0 && arr[j] > temp; j -= gap) {
                // 根据当前 grap 间隔和条件进行插入排序前的后移
                arr[j + gap] = arr[j];
            }
            // 插入到当前位置
            arr[j + gap] = temp;
        }
    }
}

更多十大经典排序算法请戳我的 Github 仓库 @LeetCode-C

05. 归并排序(MergeSort)

归并排序是创建在归并操作上的一种有效的排序算法,效率为 O(n log n)。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。

归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。归并排序算法依赖归并操作。

归并排序用迭代法和递归法都可以实现,迭代法的算法步骤为:

  • 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
  • 设定两个指针,最初位置分别为两个已经排序序列的起始位置
  • 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
  • 重复步骤3直到某一指针到达序列尾
  • 将另一序列剩下的所有元素直接复制到合并序列尾

递归法的算法步骤为:

  • 将序列每相邻两个数字进行归并操作,形成 floor(n/2) 个序列,排序后每个序列包含两个元素
  • 将上述序列再次归并,形成 floor(n/4) 个序列,每个序列包含四个元素
  • 重复步骤 2,直到所有元素排序完毕
/*
 * 归并排序。迭代版
 * @param: {int []} arr
 * @param: {int} len
 * @return null;
 */
void MergeSort_1 (int arr[], int len) {
	int* a = arr;
	int* b = (int*) malloc(len * sizeof(int));
	int seg, start;
	for (seg = 1; seg < len; seg += seg) {
		for (start = 0; start < len; start += seg + seg) {
			int low = start, mid = Min (start + seg, len), high = Min(start + seg + seg, len);
			int k = low;
			int start1 = low, end1 = mid;
			int start2 = mid, end2 = high;
			while (start1 < end1 && start2 < end2)
				b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
			while (start1 < end1)
				b[k++] = a[start1++];
			while (start2 < end2)
				b[k++] = a[start2++];
		}
		int* temp = a;
		a = b;
		b = temp;
	}
	if (a != arr) {
		int i;
		for (i = 0; i < len; i++)
			b[i] = a[i];
		b = a;
	}
	free(b);
}

int Min(int x, int y) {
	return x < y ? x : y;
}
/*
 * 归并排序。递归版
 * @param: {int []} arr
 * @param: {const int} len
 * @return null;
 */
void MergeSort_2 (int arr[], const int len) {
	int reg[len];
	merge_sort_recursive(arr, reg, 0, len - 1);
}

void merge_sort_recursive (int arr[], int reg[], int start, int end) {
	if (start >= end)
		return;
	int len = end - start, mid = (len >> 1) + start;
	int start1 = start, end1 = mid;
	int start2 = mid + 1, end2 = end;
	merge_sort_recursive(arr, reg, start1, end1);
	merge_sort_recursive(arr, reg, start2, end2);
	int k = start;
	while (start1 <= end1 && start2 <= end2)
		reg[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
	while (start1 <= end1)
		reg[k++] = arr[start1++];
	while (start2 <= end2)
		reg[k++] = arr[start2++];
	for (k = start; k <= end; k++)
		arr[k] = reg[k];
}

总结【上】

这篇文章“十大经典排序算法及其 C 语言实现【上】”引出了十大经典算法的前五个并用 C 语言实践:冒泡排序、选择排序、插入排序、希尔排序和归并排序,并作出了充足的图文解释。即将推出的“十大经典排序算法及其 C 语言实现【下】”将对剩下五个经典算法快速排序、堆排序、计数排序、桶排序、基数排序作出完善,尽请期待~。

维基百科 - 排序算法

[A1A]一起动手写一个 JavaScript 太空船游戏!

周六一早,正在被窝窝着睡,突然觉得少了点什么,才意识到自己在校内实验室报名的全天 Learn Smart 编程活动早已开始 —— 这么有趣的活动怎么可以因此不去了呢,火速前往。

图片取材自 Bit Blaster XL

今天这场 Learn Smart 活动,便要做一个基于 Canvas 的太空船游戏。


一、需求确认 (´◑ω◐`)


方便起见,这里给该游戏起名为 JSpace-Ship,今天要完成的任务是:

  • 白块代表飞船
  • 红块代表碎片
  • 碎片自动下落
  • 飞船躲避碎片

太空垃圾真是多 (ಢധಢ)


二、功能探索 ( _ ͡° ͜ʖ ͡° )_


功能探索即是先一起玩玩这个游戏,感悟游戏背后的功能。

在 JSpace-Ship 的体验中,发现其实背后的逻辑很简单,无非是:

  • 上上下下左左右右躲避碎片 Gay 木偶喔 :-)

哈哈,幽默一下,就到了干货的环节了,做好准备!


三、分解任务 ☍ (¦3ꇤ[▓▓]


任何问题都是可以穷尽的,小游戏编程亦是如此。如果有了对实现 JSpace-Ship 游戏功能这个大任务的详细分解步骤作为接下来编程的参考指南,抽象逻辑便也能具体化。

任务分解如下 (๑´∀`๑)

  1. 填写游戏介绍
  2. 产生一个画布
  3. 产生飞船并静止
  4. 随机产生一个碎片
  5. 让一个碎片自动下落
  6. 随机产生多个碎片
  7. 让多个碎片自动下落
  8. 让飞船上下左右移动
  9. 飞船靠近上下边界静止
  10. 飞船靠近左边界跳转右边界,反之跳转左边界
  11. 飞船碰撞碎片后游戏结束
  12. 游戏结束时产生 Game Over 字样

制作原型图 (๑´ڡ`๑)

刚才已经能看到黑色背景,白色飞船,红色碎片的界面图了,画出来即可。

绘制事件列表 (ノTwT)ノ ┫

界面上的每一个操作,都是事件,都能产生用户故事与需求。

画出组件图 ー=≡Σ( ε¦) 0

和下面的数据结构放一起了。

规定数据结构 (´థ౪థ )

JSON 格式好简洁好棒的。


四、概念学习 ☉☯☉


到了代码实战环节,怎能无法对 Web 概念有所了解并阐述。

什么是 Canvas (๑•́ ₃ •̀๑)エー

因为这次是团队合作解决的,基于石墨在线协作编辑,我们对 Canvas 的共同认知如下:

是 HTML5 中出现的新标签,像所有的 Dom 对象一样它有自己本身的属性、方法和事件,其中就有绘图的方法,JS 能够调用它来进行绘图。在Canvas 中,一旦图形被绘制完成,它就不会继续得到浏览器的关注。如果其位置发生变化,那么整个场景也需要重新绘制,包括任何或许已被图形覆盖的对象。

  • 依赖分辨率
  • 不支持事件处理器
  • 弱的文本渲染能力
  • 能够以 .png 或 .jpg 格式保存结果图像
  • 最适合图像密集型的游戏,其中的许多对象会被频繁重绘

简而言之,HTML5 的新特性 Canvas 画布逐像素绘制图片,绘制完成后不再得到浏览器关注,改动时重新绘制。

为什么不用 SVG (⊃_⊂)

SVG ,可缩放矢量图形,支持 DOM 操作也不仅仅存在于 Web 开发中。

  • 不依赖分辨率
  • 支持事件处理器
  • 最适合带有大型渲染区域的应用程序(比如谷歌地图)
  • 复杂度高会减慢渲染速度(任何过度使用 DOM 的应用都不快)
  • 不适合游戏应用

可见,如果使用 SVG 的话,就要生成足够多的对象来持续操作,也会因为这些操作而影响性能。

上图直观说明了 Canvas 能作为图片存储,是像素化的。而 SVG 矢量图形如下,如论缩放多大依旧清晰,却无法图片存储。

Flash 不高兴了 (/´ △ `\ )

HTML5 的时代啦,那 FLASH 就继续不高兴吧~

HTML5 真的能取代 FLASH 吗


五、DEMO预研 q(´・ω・`)p


依据分解过的任务,依据事件列表,正式开始DEMO预研。在我们小组的石墨合作编辑中,快速产出快速分享敏捷开发~

全程在线开发基于校内实验室的 JS Bin。国内还没有太普及哦~


六、功能实现 ૢ(⌯・ω・`⌯)


当每一个功能都有了独立可执行的 Demo 后,再完成一步稍稍逼死强迫症(涉及各种风格不统一)的代码合并就可以正式上线我们的 JSpace-Ship 了。

合并完成,本次功能实现完成,左手右手慢动作。


七、反馈 (✿´ ꒳ ` )


什么?!有人说我是标题党,这篇文章甚至这个游戏和太空船有什么关系?我只想 Say ~一天时间当然不够加入太空元素,但下去自己不会去改装嘛~~~

反馈表对于这场活动的举办成功与否能起到一定的参考价值。填写之。

Oh,对了,本次改装链接来源于学姐,哈哈。同时对于自己处女座和强迫症的性格来说,今天从团队开发里学到的最深刻的便是——注重功能,不要过于追求完美。|д・)

Blog-Archive

博客中枢,分目录,放暂存灵感,博客归档

归档

从 2015 年为第一年开始,采用三位十六进制数字进行编号。每俩年编号第一位自增。

Level A (2015-2016)

Level B (2017-2018)

读书篇

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.