-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
3999 lines (3655 loc) · 451 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[JavaScript之(ES6箭头函数和异步回调地狱)]]></title>
<url>/2017/07/03/JavaScript%E4%B9%8B-ES6%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0%E5%92%8C%E5%BC%82%E6%AD%A5%E5%9B%9E%E8%B0%83%E5%9C%B0%E7%8B%B1/</url>
<content type="html"></content>
</entry>
<entry>
<title><![CDATA[微信小程序开发扫盲(五)]]></title>
<url>/2017/07/03/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%BC%80%E5%8F%91%E6%89%AB%E7%9B%B2-%E4%BA%94/</url>
<content type="html"></content>
</entry>
<entry>
<title><![CDATA[微信小程序开发扫盲(四)]]></title>
<url>/2017/07/03/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%BC%80%E5%8F%91%E6%89%AB%E7%9B%B2-%E5%9B%9B/</url>
<content type="html"></content>
</entry>
<entry>
<title><![CDATA[微信小程序开发扫盲(三)]]></title>
<url>/2017/07/03/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%BC%80%E5%8F%91%E6%89%AB%E7%9B%B2-%E4%B8%89/</url>
<content type="html"></content>
</entry>
<entry>
<title><![CDATA[微信小程序开发扫盲(二)]]></title>
<url>/2017/07/03/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%BC%80%E5%8F%91%E6%89%AB%E7%9B%B2-%E4%BA%8C/</url>
<content type="html"></content>
</entry>
<entry>
<title><![CDATA[微信小程序开发扫盲(一)]]></title>
<url>/2017/07/03/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%BC%80%E5%8F%91%E6%89%AB%E7%9B%B2-%E4%B8%80/</url>
<content type="html"><![CDATA[<blockquote>
<p>我不止一次地说过新时代分离开发模式下只有服务端接口和客户端容器概念, 微信小程序就是一个借助浏览器内核伪装成App的客户端容器, 本系列博文站在一个前端工程师的角度分析小程序开发流程。</p>
</blockquote>
<a id="more"></a>
<ul>
<li><p>微信开发语言是wxml, wxss, javascript。wxml是一种微信用于替代html的类xml标记语言, wxss语法和css几乎没有区别, javascript方面微信自己封装了一个wx框架。</p>
</li>
<li><p>微信开发IDE必须使用微信官方提供的<code>微信Web开发者工具</code>, 目前还可以选择使用其他构建工具和代码编辑工具。</p>
</li>
<li><p>微信开发者ID也叫AppID, 早期只提供给内测人员使用, 现在所有个人开发者注册登录<code>微信公众平台 | 小程序</code>就能获取AppID。</p>
</li>
<li><p><code>微信Web开发者工具</code>无法再断网情况下使用。</p>
</li>
<li><p>微信小程序的入口文件为app.json。pages目录下为不同页面的内容。</p>
</li>
</ul>
]]></content>
</entry>
<entry>
<title><![CDATA[NodeJS学习之模块和交互式环境下的使用]]></title>
<url>/2017/06/26/NodeJS%E5%AD%A6%E4%B9%A0%E4%B9%8B%E6%A8%A1%E5%9D%97%E5%92%8C%E4%BA%A4%E4%BA%92%E5%BC%8F%E7%8E%AF%E5%A2%83%E4%B8%8B%E7%9A%84%E4%BD%BF%E7%94%A8/</url>
<content type="html"><![CDATA[<blockquote>
<p>同于namespace命名空间,JS为了避免团队代码中的变量和函数相互污染,引入了Common.js规范,这个规范类似于PHP中的PSR约定,同时它也主要针对模块和组件开发。</p>
<p>主要包括模块的定义,标识和引用三个部分。</p>
</blockquote>
<a id="more"></a>
<ul>
<li>nodejs中文件和模块和对应的,模块主要有<code>核心模块</code>,<code>文件模块</code>和<code>第三发模块</code>,它们分别的引用模块方式为:</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">核心模块: http fs path</div><div class="line"></div><div class="line">文件模块: <span class="keyword">var</span> util=<span class="built_in">require</span>(<span class="string">'./util.js'</span>)</div><div class="line"></div><div class="line">第三方模块: <span class="keyword">var</span> promise=<span class="built_in">require</span>(<span class="string">'bluebird'</span>)</div></pre></td></tr></table></figure>
<ul>
<li><p>核心模块在node环境启动时被加载,第三方模块包括npm下载和团队自定义的模块。</p>
</li>
<li><p>模块流程: 创建模块,导出模块,加载模块,使用模块, 示例创建一个school模块。</p>
</li>
<li><p>关于exports和module.exports。 </p>
</li>
<li><p>URI和URL的区别(统一资源标识符和统一资源定位符),URL属于URI,我们常说的网址就是URL,但是URI是一个略微抽象的概念,URL的命名规则包括协议,英文,小写,文中编码等等。node也有一个用于网址解析的url模块。</p>
</li>
<li><p>在node命令环境中输入url就能看到这个模块暴露的方法,使用<code>url.pasre('http://www.imooc.com/course/list')</code>就能被模块解析成一个对象返回到终端。其组成部分包括:</p>
</li>
</ul>
<figure class="highlight routeros"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">protocol 底层使用的协议</div><div class="line">slashes 是否有双斜线</div><div class="line">auth 是否有认证</div><div class="line">host 域名或ip地址<span class="built_in"></span></div><div class="line">port 端口</div><div class="line">hostname 主机名</div><div class="line">hash 哈希值</div><div class="line">search 查询参数</div><div class="line">query 发送的数据</div><div class="line">pathname 资源路径名</div><div class="line">path 资源路径</div><div class="line">href 完整超链接</div></pre></td></tr></table></figure>
<ul>
<li><p>url.parse和url.format是可逆的操作。</p>
</li>
<li><p>输入querystring查看这个模块提供的方法。其中有<code>querystring.stringify({name: 'scote', sex: '男'})</code>可以把对象序列化后变成URL参数路径。更多参数查看文档。</p>
</li>
<li><p><code>querystring.stringify</code>和<code>querystring.parse</code>是互逆的,后者是反序列化操作, 类似于<code>json_encode</code>和<code>json_decode</code>。就是字符串和对象之间的互相转换。更多参数请查阅API文档。</p>
</li>
<li><p>汉字转义使用<code>querystring.escape()</code>, 反转义使用<code>querystring.unescape()</code>。</p>
</li>
<li><p>输入网址按下回车后发生了什么?</p>
</li>
</ul>
<figure class="highlight lsl"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"><span class="number">1.</span> 搜索浏览器自身的DNS缓存</div><div class="line"><span class="number">2.</span> 搜索操作系统自身的DNS缓存</div><div class="line"><span class="number">3.</span> 读取本地hosts文件</div><div class="line"><span class="number">4.</span> 向本地DNS服务商发起一个系统调用</div><div class="line"><span class="number">5.</span> 该服务商查看自身的DNS缓存记录和数据库</div><div class="line">true- 该服务商向根DNS服务器发起迭代DNS解析请求</div><div class="line">true- 该服务商拿到ip地址后返回系统内核并把记录缓存</div><div class="line">true- 操作系统内核把结果返回给浏览器</div><div class="line"><span class="number">5.</span> 得到ip后开始三次握手四次挥手,建立TCP/IP连接</div><div class="line">true- <span class="number">217.123</span><span class="number">.43</span><span class="number">.62</span>的哥们,你在线吗?(<span class="number">0</span><span class="number">-1</span>)</div><div class="line">true- 我在。(<span class="number">1</span><span class="number">-2</span>)</div><div class="line">true- 我要给你发送数据了,准备好了吗?(<span class="number">2</span><span class="number">-3</span>)</div><div class="line">true- 准备好了。(<span class="number">3</span><span class="number">-4</span>)</div><div class="line"><span class="number">6.</span> 连接建立成功后客户端发送HTTP方法。</div><div class="line"><span class="number">7.</span> 服务器端接收到请求,后端处理后把数据返回给浏览器。</div><div class="line"><span class="number">8.</span> 服务器上的静态资源也经过上面的步骤返回到浏览器</div><div class="line"><span class="number">9.</span> 浏览器把拿到的资源组合渲染给用户看</div></pre></td></tr></table></figure>
<ul>
<li><p>请求和响应都会发送http header和http body(正文信息)。</p>
</li>
<li></li>
</ul>
]]></content>
</entry>
<entry>
<title><![CDATA[Apache的ab压力测试工具]]></title>
<url>/2017/06/26/Apache%E7%9A%84ab%E5%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/</url>
<content type="html"><![CDATA[<blockquote>
<p>Apache自带ApacheBench压力测试工具,主要针对服务端数据接口做性能测试,当然你也可以对本地web服务器做测试。</p>
<p>下面简单使用<code>ab -n1000 -c10 http://devapi.umeishu.com/rent/areas</code>查看返回信息,简单解释用法。ab测试的更多参数自行搜索和查看文档。</p>
</blockquote>
<a id="more"></a>
<ul>
<li>-n参数表明一共发送多少个请求,-c参数表明并发请求量为10个。</li>
</ul>
<p><img src="http://ool6x4l46.bkt.clouddn.com/hexo/preview.jpg" alt="preview"></p>
<ul>
<li>首先看第一张图,执行命令开始的前部分。没啥可说的,图上就是ab工具的版本,测试的接口地址,持续完成了多少个请求。</li>
</ul>
<ul>
<li>下面这张图就是ab压力测试主要的返回数据了。<br><img src="http://ool6x4l46.bkt.clouddn.com/hexo/main.jpg" alt="main"></li>
</ul>
<figure class="highlight routeros"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line">Server Software: 服务端跑的Http服务器软件<span class="built_in"></span></div><div class="line">Server Hostname: 主机名<span class="built_in"></span></div><div class="line">Server Port: 端口</div><div class="line"></div><div class="line">Document Path: 网址路径</div><div class="line">Document Length: 响应正文的长度(大小)</div><div class="line"></div><div class="line">Concurrency Level: 刚才设置的并发数</div><div class="line">Time taken <span class="keyword">for</span> tests: 所有请求处理完成所需时间</div><div class="line">Complete requests: 刚才设置的请求总数</div><div class="line">Failed requests: 失败的总请求数(异常或无响应)</div><div class="line">Total transferred: 所有数据的大小(长度)</div><div class="line">HTML transferred: HTML传输量(字节)</div><div class="line">Requests per second: 服务器吞吐率</div><div class="line">Time per request: 平均请求的等待时间</div><div class="line">Time per request: 每个链接请求运行的平均值</div><div class="line">Transfer rate: 请求在单位时间内的流量</div><div class="line"><span class="built_in"></span></div><div class="line">Connection Times (ms)</div><div class="line">ms: 百分之xxx的用户访问所需毫秒数</div></pre></td></tr></table></figure>
]]></content>
</entry>
<entry>
<title><![CDATA[PHP接口测试]]></title>
<url>/2017/06/25/PHP%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95/</url>
<content type="html"><![CDATA[<blockquote>
<p>什么是接口, 接口类型和差异, 什么接口测试, 接口测试流程, 接口测试工具?</p>
<p>人工测试接口太费成本, 这时候我们引用phpunit写自动化测试代码。</p>
</blockquote>
<a id="more"></a>
<ul>
<li><p>测试接口就是测试HTTP请求,每个不同地址的HTTP请求就是一个接口。</p>
</li>
<li><p>接口包括内部接口和外部接口,内部接口中包括上层服务, 下层服务和同级服务。</p>
</li>
<li><p>接口以HTTP方法进行分类,HTTP方法(接口类型)主要有GET, POST, PUT, DELETE。注意PUT的修改是针对整个表字段,PATCH可以只修改部分字段。</p>
</li>
<li><p>我们对每个数据库实体的操作一般都有增删改查四个操作, 查询一般有查询多条和单条数据。也就是说一个实体资源一般有5个API(数据接口)。</p>
</li>
<li><p>接口测试流程和黑盒测试一样, 严格来说都要经过需求讨论, <code>需求评审</code>, <code>场景设计</code>, <code>用例设计</code>, <code>数据准备</code>, <code>数据准备</code>和<code>执行操作</code>。</p>
</li>
<li><p>重点是<code>设计测试用例</code>, 就是说你要确定某个资源要测试哪些操作, 放置后续执行漏测试一些接口, 测试用例也能让团队其他人员知道你所在的测试进度。</p>
</li>
<li><p>测试用例一般要考虑: 功能能否实现, 功能是否对应接口文档, 逻辑业务是否正常如权限认证。</p>
</li>
<li><p>接口API异常测试有参数异常<code>(关键字参数,参数为空,参数过多或缺少,错误参数)</code>和数据异常<code>(关键字数据,数据为空,长度类型校验,错误数据)</code>处理; 接口API安全问题<code>(cookie,header,认证token或手机唯一识别码等)</code>。</p>
</li>
<li><p>f</p>
</li>
<li><p>f</p>
</li>
<li><p>f</p>
</li>
<li><p>f</p>
</li>
<li><p>f</p>
</li>
<li><p>f</p>
</li>
<li><p>f</p>
</li>
</ul>
]]></content>
</entry>
<entry>
<title><![CDATA[ThinkPHP学习之配置和环境]]></title>
<url>/2017/06/24/ThinkPHP%E5%AD%A6%E4%B9%A0%E4%B9%8B%E9%85%8D%E7%BD%AE%E5%92%8C%E7%8E%AF%E5%A2%83/</url>
<content type="html"><![CDATA[<blockquote>
<p>TP5框架的有六大配置: 惯例配置, 应用配置, 扩展配置, 场景配置, 模块配置, 动态配置。v5.0.9默认在application/目录下新建了应用配置文件config.php。我不推荐把所有配置项填写在这个文件中, 我们的项目中有数据库配置, Session配置, 缓存配置, Cookie配置, 邮件配置等等, 全部放在一个文件中会显得冗长不便于扩展。</p>
<p>一般PHP框架的学习流程是先路由然后MVC到模板, TP框架学习的第一步却是配置。</p>
</blockquote>
<a id="more"></a>
<ul>
<li><p>cofig()助手函数是对<code>think/Config</code>类的封装,Config有<code>range()</code>, <code>parse()</code>, <code>load()</code>, <code>has()</code>, <code>get()</code>, <code>set()</code>, <code>reset()</code>等静态方法。</p>
</li>
<li><p><code>thinkphp/convention.php</code>就是<strong>惯例配置</strong>的内容, 考虑扩展和迭代开发的话这个文件不应该被修改。删除config.php, 在不同模块中使用助手函数config()输出默认惯例配置的内容。</p>
</li>
<li><p>在项目根目录新建conf/config.php, 这里填写的就是<strong>应用配置</strong>。你可以添加惯例配置中没有的键值对,也可以填写同名配置项, TP5底层使用了<code>array_merge()</code>更新配置项。</p>
</li>
<li><p><strong>扩展配置</strong>如email, 必须新建<code>conf/extra/</code>目录并新建扩展配置文件email.php, 返回一个email的相关信息。查看config()可以看到多出一个email数组配置项, 这个配置项的key就是刚才新建的文件名email.php。数据库的配置文件名必须为<code>database.php</code>, 所在路径是<code>conf/</code>或者<code>conf/extra/</code>。当然你也可以以数组形式写在<code>conf/config.php</code>中。扩展配置会merge替换应用配置。</p>
</li>
<li><p><strong>场景配置</strong>能让你在公司和家里使用不同的配置项。比如你公司家里各有台式机, 这时候你应该在conf/中新建office.php和home.php并分别在里面配置相关环境项, 然后在config/中填写<code>app_status</code>项的value为对应的环境如home。</p>
</li>
<li><p><strong>模块配置</strong>顾名思义就是让不同的模块有不同的配置项, 如果你要给admin和index模块分别写特定的配置, 那么首先新建<code>conf/admin/config.php</code>和<code>conf/index/config.php</code>, 在分别的模块配置中还是可以新建extra目录等等, 这时候分别填写不同的配置项试试吧。</p>
</li>
<li><p><strong>动态配置</strong>就是使用助手函数config()动态设置配置项。如果你想让某个配置项只在某个控制器中可以访问, 那么你需要在该控制器的构造方法中使用助手函数<code>conifg('key', 'value')</code>设置配置项, 当然你也可以只在某个方法中动态设置这个配置项。</p>
</li>
<li><p>前面关于输出配置项都是使用config()这个助手函数, 你也可以使用Config类提供的静态方法get()获取。直接路径法请使用<code>\think\Config::get()</code>, 但是更推荐先使用<code>use \think\Config;</code>使用根命名空间, 再使用Config类的静态方法获取或者设置相关参数如<code>dump(\think\Config::get('app_debug'))</code>获取bool值。</p>
</li>
<li><p>TP5的默认助手函数都在<code>thinkphp/helper.php</code>中, 所有助手函数都事先判断了是否存在该函数。也就是说, 如果你面对一个自定义了config()并大量使用该函数的项目, 那么你应该Config类的静态方法去重构。</p>
</li>
<li><p>Config类的set()静态方法或者助手函数config()第三个参数都可以传递配置作用域, 获取配置value也需要添加第二个作用域参数。</p>
</li>
<li><p>环境的配置首先可以使用PHP的<code>$_ENV</code>获取系统的环境变量(经过我的测试这样无法获取.env中定义的环境变量, 但使用TP5的<code>\think\ENV::get()</code>可以获取), 也可以在项目根目录添加默认会被加载的.env文件并以ini配置文件的方式写上环境变量值。这里输出会进行大小写转换, 前缀添加(thinkphp/base.php)和组名转换。使用<code>$_ENV['key']</code>获取不存在的环境变量会报错, 使用<code>\think\ENV::get('key')</code>获取不存在的环境变量会返回NULL。获取分组下的值可以使用<code>group_key</code>和<code>group.key</code>两种写法。</p>
</li>
<li><p>将TP5的配置和ENV环境变量类组合在一起, 可以在配置文件中使用<code>'app_status' => \think\Env::get('app_status', 'dev')</code>这种写法, 如果未定义环境变量就是用dev。</p>
</li>
<li></li>
</ul>
]]></content>
</entry>
<entry>
<title><![CDATA[C/C++学习之求数组长度方案]]></title>
<url>/2017/06/19/C-C-%E5%AD%A6%E4%B9%A0%E4%B9%8B%E6%B1%82%E6%95%B0%E7%BB%84%E9%95%BF%E5%BA%A6%E6%96%B9%E6%A1%88/</url>
<content type="html"><![CDATA[<blockquote>
<p>c++中没有求数组长度的默认函数,只能自己写。但经常有初学者把sizeof(), size(), length(), strlen() 混淆。本篇博文具体解释一下如何求数组长度和这四个函数,以及可能遇到的问题。</p>
</blockquote>
<a id="more"></a>
<ul>
<li>C++求数组长度为:</li>
</ul>
<figure class="highlight lisp"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">int arr_length = sizeof(<span class="name">arr</span>) / sizeof(<span class="name">arr</span>[<span class="number">0</span>])<span class="comment">;</span></div></pre></td></tr></table></figure>
<ul>
<li>为了方便使用,在C语言中常定义宏来求数组长度</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">\<span class="meta">#<span class="meta-keyword">define</span> ARR_LEN(arr, length){</span></div><div class="line">truelength = <span class="keyword">sizeof</span>(arr) / <span class="keyword">sizeof</span>(arr[<span class="number">0</span>]);</div><div class="line">}</div></pre></td></tr></table></figure>
<ul>
<li>使用时,直接调用宏函数即可,如</li>
</ul>
<figure class="highlight lsl"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">int arr[]={<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>};</div><div class="line"></div><div class="line">int len;</div><div class="line"></div><div class="line">ARR_LEN(arr, len); <span class="comment">//此时len赋值为5</span></div></pre></td></tr></table></figure>
<ul>
<li>在C++中,也可以定义模板函数</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>></span></div><div class="line"></div><div class="line"><span class="title">int</span> <span class="title">getArrayLen</span>(<span class="title">T</span> &<span class="title">arr</span>){</div><div class="line">true<span class="keyword">return</span> <span class="keyword">sizeof</span>(arr) / <span class="keyword">sizeof</span>(arr[<span class="number">0</span>]);</div><div class="line">}</div></pre></td></tr></table></figure>
<ul>
<li>使用时,调用模板函数,如</li>
</ul>
<figure class="highlight go"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">string</span> arr[]={<span class="string">"abc"</span>, <span class="string">"ab"</span>, <span class="string">"abcde"</span>, <span class="string">"1234567"</span>, <span class="string">"890"</span>};</div><div class="line"></div><div class="line"><span class="keyword">int</span> <span class="built_in">len</span>=getArrayLen(arr); <span class="comment">//此时len赋值为5</span></div></pre></td></tr></table></figure>
<ul>
<li><p>当数组传入函数时,传入的是指针,指针仅指向数组头arr[0],不带有任何长度信息; 所以在传入数组时,要把数组长度同时传入函数。</p>
</li>
<li><p>可以考虑一下,下面这个函数调用时,会输出什么?</p>
</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">length_array</span><span class="params">(<span class="keyword">int</span> arr[])</span></span>{</div><div class="line">true<span class="keyword">int</span> len=getArrayLen(arr);</div><div class="line"></div><div class="line">true<span class="built_in">cout</span> << <span class="string">"len="</span> << len << <span class="string">", sizeof(arr)= "</span> << <span class="keyword">sizeof</span>(arr) << <span class="built_in">endl</span>;</div><div class="line">}</div></pre></td></tr></table></figure>
<blockquote>
<p>Output: len=1, sizeof(arr)=4;</p>
<p>这是因为arr是指针,而指针所占空间是4个字节。</p>
<p>所以sizeof(arr)/sizeof(arr[0])=1。</p>
</blockquote>
<ul>
<li><p>请牢记:如果把数组作为参数传入函数,那么这个数组会退化为一个指针 int *arr。</p>
</li>
<li><p>下面说一下size(), length(), strlen()</p>
</li>
<li><p>先说 size() 和 length(),这两个方法都要先 include <string>,两者使用起来无任何差别。即str.size() == str.length() 为真。</string></p>
</li>
<li><p>引用cplusplus.com中的话:</p>
</li>
</ul>
<blockquote>
<p>Both string::size and string::length are synonyms and return the same value, which is the length of the string, in terms of bytes.</p>
</blockquote>
<ul>
<li><p>而 strlen() 是<cstring>中的,是C语言的遗留物。</cstring></p>
</li>
<li><p>引用cplusplus.com中的话:</p>
</li>
</ul>
<blockquote>
<p>cstring::strlen returns the length of the C string str. In C++, char_traits::length implements the same behavior.</p>
</blockquote>
<ul>
<li>即 strlen(str) == str.length() == str.size() 为真。</li>
</ul>
<ul>
<li>参考文献及资料</li>
</ul>
<blockquote>
<p><a href="http://www.cplusplus.com" target="_blank" rel="external">C++官方英文文档</a></p>
<p><a href="http://blog.csdn.net/bopzhou/article/details/6063163" target="_blank" rel="external">CSDN博客: C/C++中如何获取数组的长度?</a></p>
</blockquote>
]]></content>
</entry>
<entry>
<title><![CDATA[C/C++学习之内存管理总结]]></title>
<url>/2017/06/18/C-C-%E5%AD%A6%E4%B9%A0%E4%B9%8B%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E6%80%BB%E7%BB%93/</url>
<content type="html"><![CDATA[<blockquote>
<p>程序员们经常编写内存管理程序,往往提心吊胆。如果不想触雷,唯一的解决办法就是发现所有潜伏的地雷并且排除它们,躲是躲不了的。本文的内容比一般教科书的要深入得多,读者需细心阅读,做到真正地通晓内存管理。</p>
</blockquote>
<a id="more"></a>
<ul>
<li>1、内存的三种分配方式</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">(<span class="number">1</span>)从静态存储区域分配。</div><div class="line"> 内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。</div><div class="line">true例如全局变量,<span class="keyword">static</span>变量。</div><div class="line"></div><div class="line">(<span class="number">2</span>)在栈上创建。</div><div class="line">true在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。</div><div class="line">true栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。</div><div class="line"></div><div class="line">(<span class="number">3</span>)从堆上分配,亦称动态内存分配。</div><div class="line">true程序在运行的时候用<span class="built_in">malloc</span>或<span class="keyword">new</span>申请任意多少的内存,程序员自己负责在何时用<span class="built_in">free</span>或<span class="keyword">delete</span>释放内存。</div><div class="line">true动态内存的生存期由我们决定,使用非常灵活,但问题也最多。</div></pre></td></tr></table></figure>
<ul>
<li>2、常见的内存错误及其对策</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div></pre></td><td class="code"><pre><div class="line">发生内存错误是件非常麻烦的事情。</div><div class="line"></div><div class="line">编译器不能自动发现这些错误,通常是在程序运行时才能捕捉到。</div><div class="line"></div><div class="line">而这些错误大多没有明显的症状,时隐时现,增加了改错的难度。</div><div class="line"></div><div class="line">有时用户怒气冲冲地把你找来,程序却没有发生任何问题,你一走,错误又发作了。 </div><div class="line"></div><div class="line">常见的内存错误及其对策如下:</div><div class="line"></div><div class="line"> <span class="number">1</span>) 内存分配未成功,却使用了它。</div><div class="line"> 编程新手常犯这种错误,因为他们没有意识到内存分配会不成功。</div><div class="line"> 常用解决办法是,在使用内存之前检查指针是否为<span class="literal">NULL</span>。</div><div class="line"> 如果指针p是函数的参数,那么在函数的入口处用assert(p!=<span class="literal">NULL</span>)进行检查。</div><div class="line"> 如果是用<span class="built_in">malloc</span>或<span class="keyword">new</span>来申请内存,应该用<span class="keyword">if</span>(p==<span class="literal">NULL</span>) 或<span class="keyword">if</span>(p!=<span class="literal">NULL</span>)进行防错处理。</div><div class="line"></div><div class="line"> <span class="number">2</span>) 内存分配虽然成功,但是尚未初始化就引用它。</div><div class="line"> 犯这种错误主要有两个起因:一是没有初始化的观念;二是误以为内存的缺省初值全为零,导致引用初值错误(例如数组)。</div><div class="line"> 内存的缺省初值究竟是什么并没有统一的标准,尽管有些时候为零值,我们宁可信其无不可信其有。</div><div class="line"> 所以无论用何种方式创建数组,都别忘了赋初值,即便是赋零值也不可省略,不要嫌麻烦。</div><div class="line"></div><div class="line"> <span class="number">3</span>) 内存分配成功并且已经初始化,但操作越过了内存的边界。</div><div class="line"> 例如在使用数组时经常发生下标“多<span class="number">1</span>”或者“少<span class="number">1</span>”的操作。</div><div class="line"> 特别是在<span class="keyword">for</span>循环语句中,循环次数很容易搞错,导致数组操作越界。</div><div class="line"> 数组越界有时输出<span class="number">0</span>,有时</div><div class="line"></div><div class="line"> <span class="number">4</span>) 忘记了释放内存,造成内存泄露。</div><div class="line"> 含有这种错误的函数每被调用一次就丢失一块内存。</div><div class="line"> 刚开始时系统的内存充足,你看不到错误。</div><div class="line"> 终有一次程序突然死掉,系统出现提示:内存耗尽。</div><div class="line"> 动态内存的申请与释放必须配对,程序中<span class="built_in">malloc</span>与<span class="built_in">free</span>的使用次数一定要相同,否则肯定有错误(<span class="keyword">new</span>/<span class="keyword">delete</span>同理)。</div><div class="line"></div><div class="line"> <span class="number">5</span>) 释放了内存却继续使用它。这时候有三种情况:</div><div class="line"> a) 程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面。</div><div class="line"> b)函数的<span class="keyword">return</span>语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数体结束时被自动销毁。</div><div class="line"> c)使用<span class="built_in">free</span>或<span class="keyword">delete</span>释放了内存后,没有将指针设置为<span class="literal">NULL</span>。导致产生“野指针”。</div><div class="line"></div><div class="line">下面是老司机宝典:</div><div class="line"></div><div class="line">【规则<span class="number">1</span>】用<span class="built_in">malloc</span>或<span class="keyword">new</span>申请内存之后,应该立即检查指针值是否为<span class="literal">NULL</span>。防止使用指针值为<span class="literal">NULL</span>的内存。</div><div class="line"></div><div class="line">【规则<span class="number">2</span>】不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。</div><div class="line"></div><div class="line">【规则<span class="number">3</span>】避免数组或指针的下标越界,特别要当心发生“多<span class="number">1</span>”或者“少<span class="number">1</span>”操作。</div><div class="line"></div><div class="line">【规则<span class="number">4</span>】动态内存的申请与释放必须配对,防止内存泄漏。</div><div class="line"></div><div class="line">【规则<span class="number">5</span>】用<span class="built_in">free</span>或<span class="keyword">delete</span>释放了内存之后,立即将指针设置为<span class="literal">NULL</span>,防止产生“野指针”。</div></pre></td></tr></table></figure>
<ul>
<li>3、指针与数组的对比</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div></pre></td><td class="code"><pre><div class="line">C/C++程序中,指针和数组在不少地方可以相互替换着用,让人产生一种错觉,以为两者是等价的。</div><div class="line"></div><div class="line">数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。</div><div class="line"></div><div class="line">数组名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。</div><div class="line"></div><div class="line">指针可以随时指向任意类型的内存块,它的特征是“可变”,所以我们常用指针来操作动态内存。指针远比数组灵活,但也更危险。</div><div class="line"></div><div class="line">下面以字符串为例比较指针与数组的特性。</div><div class="line"></div><div class="line"><span class="number">3.1</span> 修改内容</div><div class="line"></div><div class="line">下面的程序(修改数组和指针的内容)中,字符数组a的容量是<span class="number">6</span>个字符,其内容为hello。</div><div class="line"></div><div class="line">a的内容可以改变,如a[<span class="number">0</span>]= ‘X’。</div><div class="line"></div><div class="line">指针p指向常量字符串“world”(位于静态存储区,内容为world),常量字符串的内容是不可以被修改的。</div><div class="line"></div><div class="line">从语法上看,编译器并不觉得语句 p[<span class="number">0</span>]= ‘X’有什么不妥,但是该语句企图修改常量字符串的内容而导致运行错误。</div><div class="line"></div><div class="line"><span class="keyword">char</span> a[] = “hello”;</div><div class="line">a[<span class="number">0</span>] = ‘X’;</div><div class="line"><span class="built_in">cout</span> << a << <span class="built_in">endl</span>;</div><div class="line"><span class="keyword">char</span> *p = “world”; <span class="comment">// 注意p指向常量字符串</span></div><div class="line">p[<span class="number">0</span>] = ‘X’; <span class="comment">// 编译器不能发现该错误</span></div><div class="line"><span class="built_in">cout</span> << p << <span class="built_in">endl</span>;</div><div class="line"></div><div class="line"><span class="number">3.2</span> 内容复制与比较</div><div class="line"></div><div class="line">不能对数组名进行直接复制与比较。</div><div class="line"></div><div class="line">下面的程序中,若想把数组a的内容复制给数组b,不能用语句 b = a ,否则将产生编译错误。</div><div class="line"></div><div class="line">应该用标准库函数<span class="built_in">strcpy</span>进行复制。</div><div class="line"></div><div class="line">同理,比较b和a的内容是否相同,不能用<span class="keyword">if</span>(b==a) 来判断,应该用标准库函数<span class="built_in">strcmp</span>进行比较。</div><div class="line"></div><div class="line">语句p = a 并不能把a的内容复制指针p,而是把a的地址赋给了p。</div><div class="line"></div><div class="line">要想复制a的内容,可以先用库函数<span class="built_in">malloc</span>为p申请一块容量为<span class="built_in">strlen</span>(a) <span class="number">1</span>个字符的内存,再用<span class="built_in">strcpy</span>进行字符串复制。</div><div class="line"></div><div class="line">同理,语句<span class="keyword">if</span>(p==a) 比较的不是内容而是地址,应该用库函数<span class="built_in">strcmp</span>来比较。</div><div class="line"></div><div class="line"><span class="comment">// 数组…</span></div><div class="line"><span class="keyword">char</span> a[] = <span class="string">"hello"</span>;</div><div class="line"><span class="keyword">char</span> b[<span class="number">10</span>];</div><div class="line"><span class="built_in">strcpy</span>(b, a); <span class="comment">// 不能用 b = a;</span></div><div class="line"><span class="keyword">if</span>(<span class="built_in">strcmp</span>(b, a) == <span class="number">0</span>) <span class="comment">// 不能用 if (b == a)</span></div><div class="line">…</div><div class="line"><span class="comment">// 指针…</span></div><div class="line"><span class="keyword">int</span> len = <span class="built_in">strlen</span>(a);</div><div class="line"><span class="keyword">char</span> *p = (<span class="keyword">char</span> *)<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="keyword">char</span>)*(len <span class="number">1</span>));</div><div class="line"><span class="built_in">strcpy</span>(p,a); <span class="comment">// 不要用 p = a;</span></div><div class="line"><span class="keyword">if</span>(<span class="built_in">strcmp</span>(p, a) == <span class="number">0</span>) <span class="comment">// 不要用 if (p == a)</span></div><div class="line">…</div><div class="line"></div><div class="line"><span class="number">3.3</span> 计算内存容量</div><div class="line"></div><div class="line">用运算符<span class="keyword">sizeof</span>可以计算出数组的容量(字节数)。</div><div class="line"></div><div class="line">示例(a)部分中,<span class="keyword">sizeof</span>(a)的值是<span class="number">12</span>(注意别忘了’’)。</div><div class="line"></div><div class="line">指针p指向a,但是 <span class="keyword">sizeof</span>(p)的值却是<span class="number">4</span>。这是因为<span class="keyword">sizeof</span>(p)得到的是一个指针变量的字节数,相当于<span class="keyword">sizeof</span>(<span class="keyword">char</span>*),而不是p所指的内存容量。 </div><div class="line"></div><div class="line">C/C++语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。</div><div class="line"></div><div class="line">注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。</div><div class="line"></div><div class="line">示例(b)部分中,不论数组a的容量是多少,<span class="keyword">sizeof</span>(a)始终等于<span class="keyword">sizeof</span>(<span class="keyword">char</span> *)。</div><div class="line"></div><div class="line"><span class="keyword">char</span> a[] = <span class="string">"hello world"</span>;</div><div class="line"><span class="keyword">char</span> *p = a;</div><div class="line"><span class="built_in">cout</span><< <span class="keyword">sizeof</span>(a) << <span class="built_in">endl</span>; <span class="comment">// 12字节</span></div><div class="line"><span class="built_in">cout</span><< <span class="keyword">sizeof</span>(p) << <span class="built_in">endl</span>; <span class="comment">// 4字节</span></div><div class="line"></div><div class="line">上面是(a)部分:计算数组和指针的内存容量</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">Func</span><span class="params">(<span class="keyword">char</span> a[<span class="number">100</span>])</span></span></div><div class="line">{</div><div class="line"> <span class="built_in">cout</span><< <span class="keyword">sizeof</span>(a) << <span class="built_in">endl</span>; <span class="comment">// 4字节而不是100字节</span></div><div class="line">}</div><div class="line">上面是(b)部分:数组退化为指针</div></pre></td></tr></table></figure>
<ul>
<li>4、指针参数是如何传递内存的?</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div></pre></td><td class="code"><pre><div class="line">如果函数的参数是一个指针,不要指望用该指针去申请动态内存。</div><div class="line"></div><div class="line">下面的示例中,Test函数的语句GetMemory(str, <span class="number">200</span>)并没有使str获得期望的内存,str依旧是<span class="literal">NULL</span>,为什么?</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">GetMemory</span><span class="params">(<span class="keyword">char</span> *p, <span class="keyword">int</span> num)</span></span></div><div class="line">{</div><div class="line"> p = (<span class="keyword">char</span> *)<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="keyword">char</span>) * num);</div><div class="line">}</div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test</span><span class="params">(<span class="keyword">void</span>)</span></span></div><div class="line">{</div><div class="line"> <span class="keyword">char</span> *str = <span class="literal">NULL</span>;</div><div class="line"> GetMemory(str, <span class="number">100</span>); <span class="comment">// str 仍然为 NULL</span></div><div class="line"> <span class="built_in">strcpy</span>(str, <span class="string">"hello"</span>); <span class="comment">// 运行错误</span></div><div class="line">}</div><div class="line"></div><div class="line">上面试图用指针参数申请动态内存,毛病出在函数GetMemory中。</div><div class="line"></div><div class="line">编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是 _p,编译器使 _p = p。</div><div class="line"></div><div class="line">如果函数体内的程序修改了_p的内容,就导致参数p的内容作相应的修改。这就是指针可以用作输出参数的原因。</div><div class="line"></div><div class="line">在本例中,_p申请了新的内存,只是把 _p所指的内存地址改变了,但是p丝毫未变。</div><div class="line"></div><div class="line">所以函数GetMemory并不能输出任何东西。</div><div class="line"></div><div class="line">事实上,每执行一次GetMemory就会泄露一块内存,因为没有用<span class="built_in">free</span>释放内存。</div><div class="line"></div><div class="line">如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”,见下面的示例代码。</div><div class="line"></div><div class="line"><span class="keyword">void</span> GetMemory2(<span class="keyword">char</span> **p, <span class="keyword">int</span> num)</div><div class="line">{</div><div class="line"> *p = (<span class="keyword">char</span> *)<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="keyword">char</span>) * num);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test2</span><span class="params">(<span class="keyword">void</span>)</span></span></div><div class="line">{</div><div class="line"> <span class="keyword">char</span> *str = <span class="literal">NULL</span>;</div><div class="line"> GetMemory2(&str, <span class="number">100</span>); <span class="comment">// 注意参数是 &str,而不是str</span></div><div class="line"> <span class="built_in">strcpy</span>(str, <span class="string">"hello"</span>);</div><div class="line"> <span class="built_in">cout</span><< str << <span class="built_in">endl</span>;</div><div class="line"> <span class="built_in">free</span>(str);</div><div class="line">}</div><div class="line"></div><div class="line">上面用指向指针的指针申请动态内存,由于“指向指针的指针”这个概念不容易理解,我们可以用函数返回值来传递动态内存。这种方法更加简单,见下面的代码:</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">char</span> *<span class="title">GetMemory3</span><span class="params">(<span class="keyword">int</span> num)</span></span></div><div class="line">{</div><div class="line"> <span class="keyword">char</span> *p = (<span class="keyword">char</span> *)<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="keyword">char</span>) * num);</div><div class="line"> <span class="keyword">return</span> p;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test3</span><span class="params">(<span class="keyword">void</span>)</span></span></div><div class="line">{</div><div class="line"> <span class="keyword">char</span> *str = <span class="literal">NULL</span>;</div><div class="line"> str = GetMemory3(<span class="number">100</span>);</div><div class="line"> <span class="built_in">strcpy</span>(str, <span class="string">"hello"</span>);</div><div class="line"> <span class="built_in">cout</span><< str << <span class="built_in">endl</span>;</div><div class="line"> <span class="built_in">free</span>(str);</div><div class="line">}</div><div class="line"></div><div class="line">上面用函数返回值来传递动态内存,用函数返回值来传递动态内存这种方法虽然好用,但是常常有人把<span class="keyword">return</span>语句用错了。</div><div class="line"></div><div class="line">这里强调不要用<span class="keyword">return</span>语句返回指向“栈内存”的指针,因为该内存在函数结束时自动消亡,见下面的代码:</div><div class="line"></div><div class="line"><span class="keyword">char</span> *GetString(<span class="keyword">void</span>)</div><div class="line">{</div><div class="line"> <span class="keyword">char</span> p[] = <span class="string">"hello world"</span>;</div><div class="line"> <span class="keyword">return</span> p; <span class="comment">// 编译器将提出警告</span></div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test4</span><span class="params">(<span class="keyword">void</span>)</span></span></div><div class="line">{</div><div class="line"> <span class="keyword">char</span> *str = <span class="literal">NULL</span>;</div><div class="line"> str = GetString(); <span class="comment">// str 的内容是垃圾</span></div><div class="line"> <span class="built_in">cout</span><< str << <span class="built_in">endl</span>;</div><div class="line">}</div><div class="line"></div><div class="line">上面代码用<span class="keyword">return</span>语句返回指向“栈内存”的指针,用调试器逐步跟踪Test4,发现执行str = GetString语句后str不再是<span class="literal">NULL</span>指针,但是str的内容不是“hello world”而是垃圾。</div><div class="line"></div><div class="line">如果把上面那种改写成下面这种,会怎么样?</div><div class="line"></div><div class="line"><span class="keyword">char</span> *GetString2(<span class="keyword">void</span>)</div><div class="line">{</div><div class="line"> <span class="keyword">char</span> *p = <span class="string">"hello world"</span>;</div><div class="line"> <span class="keyword">return</span> p;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test5</span><span class="params">(<span class="keyword">void</span>)</span></span></div><div class="line">{</div><div class="line"> <span class="keyword">char</span> *str = <span class="literal">NULL</span>;</div><div class="line"> str = GetString2();</div><div class="line"> <span class="built_in">cout</span><< str << <span class="built_in">endl</span>;</div><div class="line">}</div><div class="line"></div><div class="line">上面这种改写是使用<span class="keyword">return</span>语句返回常量字符串,函数Test5运行虽然不会出错,但是函数GetString2的设计概念却是错误的。</div><div class="line"></div><div class="line">因为GetString2内的“hello world”是常量字符串,位于静态存储区,它在程序生命期内恒定不变。</div><div class="line"></div><div class="line">无论什么时候调用GetString2,它返回的始终是同一个“只读”的内存块。</div></pre></td></tr></table></figure>
<ul>
<li>5、杜绝“野指针”</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div></pre></td><td class="code"><pre><div class="line">“野指针”不是<span class="literal">NULL</span>指针,是指向“垃圾”内存的指针。</div><div class="line"></div><div class="line">人们一般不会错用<span class="literal">NULL</span>指针,因为用<span class="keyword">if</span>语句很容易判断。但是“野指针”是很危险的,<span class="keyword">if</span>语句对它不起作用。</div><div class="line"></div><div class="line">“野指针”的成因主要有两种:</div><div class="line">true<span class="number">1</span>)指针变量没有被初始化。</div><div class="line">true任何指针变量刚被创建时不会自动成为<span class="literal">NULL</span>指针,它的缺省值是随机的,它会乱指一气。</div><div class="line">true所以,指针变量在创建的同时应当被初始化,要么将指针设置为<span class="literal">NULL</span>,要么让它指向合法的内存。例如</div><div class="line">truetrue<span class="keyword">char</span> *p = <span class="literal">NULL</span>;</div><div class="line">truetrue<span class="keyword">char</span> *str = (<span class="keyword">char</span> *) <span class="built_in">malloc</span>(<span class="number">100</span>);</div><div class="line">true<span class="number">2</span>)指针p被<span class="built_in">free</span>或者<span class="keyword">delete</span>之后,没有置为<span class="literal">NULL</span>,让人误以为p是个合法的指针。</div><div class="line">true<span class="number">3</span>)指针操作超越了变量的作用范围。这种情况让人防不胜防,示例:</div><div class="line">true</div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span></span></div><div class="line">{</div><div class="line"> <span class="keyword">public</span>:</div><div class="line"> <span class="function"><span class="keyword">void</span> <span class="title">Func</span><span class="params">(<span class="keyword">void</span>)</span></span></div><div class="line"> {</div><div class="line"> <span class="built_in">cout</span> << “Func of <span class="class"><span class="keyword">class</span> <span class="title">A</span>” << endl;</span></div><div class="line"> }</div><div class="line">};</div><div class="line"></div><div class="line">void Test(void)</div><div class="line">{</div><div class="line"> A *p;</div><div class="line"> {</div><div class="line"> A a;</div><div class="line"> p = &a; // 注意 a 的生命期</div><div class="line"> }</div><div class="line"> p->Func(); // p是“野指针”</div><div class="line">}</div><div class="line"></div><div class="line">函数Test在执行语句p-><span class="title">Func</span>()时,对象<span class="title">a</span>已经消失,而<span class="title">p</span>是指向<span class="title">a</span>的,所以<span class="title">p</span>就成了“野指针”。</div><div class="line"></div><div class="line">但奇怪的是我运行这个程序时居然没有出错,这可能与编译器有关。</div></pre></td></tr></table></figure>
<ul>
<li>6、有了malloc/free为什么还要new/delete?</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div></pre></td><td class="code"><pre><div class="line"><span class="built_in">malloc</span>与<span class="built_in">free</span>是C /C语言的标准库函数,<span class="keyword">new</span>/<span class="keyword">delete</span>是C++的运算符(不是库函数)。</div><div class="line"></div><div class="line">它们都可用于申请动态内存和释放内存。</div><div class="line"></div><div class="line">对于非内部数据类型的对象而言,光用maloc/<span class="built_in">free</span>无法满足动态对象的要求。</div><div class="line"></div><div class="line">对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。</div><div class="line"></div><div class="line">由于<span class="built_in">malloc</span>/<span class="built_in">free</span>是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于<span class="built_in">malloc</span>/<span class="built_in">free</span>。</div><div class="line"></div><div class="line">因此C++语言需要一个能完成动态内存分配和初始化工作的运算符<span class="keyword">new</span>,以及一个能完成清理与释放内存工作的运算符<span class="keyword">delete</span>。</div><div class="line"></div><div class="line">我们先看一看<span class="built_in">malloc</span>/<span class="built_in">free</span>和<span class="keyword">new</span>/<span class="keyword">delete</span>如何实现对象的动态内存管理,见示例<span class="number">6</span>。</div><div class="line"></div><div class="line">class Obj</div><div class="line">{</div><div class="line"> <span class="keyword">public</span> :</div><div class="line"> Obj(<span class="keyword">void</span>)</div><div class="line"> {</div><div class="line"> <span class="built_in">cout</span> << “Initialization” << <span class="built_in">endl</span>;</div><div class="line"> }</div><div class="line"> </div><div class="line"> ~Obj(<span class="keyword">void</span>)</div><div class="line"> {</div><div class="line"> <span class="built_in">cout</span> << “Destroy” << <span class="built_in">endl</span>;</div><div class="line"> }</div><div class="line"> </div><div class="line"> <span class="function"><span class="keyword">void</span> <span class="title">Initialize</span><span class="params">(<span class="keyword">void</span>)</span></span></div><div class="line"> {</div><div class="line"> <span class="built_in">cout</span> << “Initialization” << <span class="built_in">endl</span>;</div><div class="line"> }</div><div class="line"> <span class="function"><span class="keyword">void</span> <span class="title">Destroy</span><span class="params">(<span class="keyword">void</span>)</span></span></div><div class="line"> {</div><div class="line"> <span class="built_in">cout</span> << “Destroy” << <span class="built_in">endl</span>;</div><div class="line"> }</div><div class="line">};</div><div class="line"></div><div class="line"><span class="comment">// C语言风格的内存管理</span></div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">UseMallocFree</span><span class="params">(<span class="keyword">void</span>)</span></span></div><div class="line">{</div><div class="line"> Obj *a = (obj *)<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(obj)); <span class="comment">// 申请动态内存</span></div><div class="line"> a->Initialize(); <span class="comment">// 初始化</span></div><div class="line"> ...</div><div class="line"> a->Destroy(); <span class="comment">// 清除工作</span></div><div class="line"> <span class="built_in">free</span>(a); <span class="comment">// 释放内存</span></div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">// C++风格的内存管理</span></div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">UseNewDelete</span><span class="params">(<span class="keyword">void</span>)</span></span></div><div class="line">{</div><div class="line"> Obj *a = <span class="keyword">new</span> Obj; <span class="comment">// 申请动态内存并且初始化</span></div><div class="line"> ...</div><div class="line"> <span class="keyword">delete</span> a; <span class="comment">// 清除并且释放内存</span></div><div class="line">}</div><div class="line"></div><div class="line">用<span class="built_in">malloc</span>/<span class="built_in">free</span>和<span class="keyword">new</span>/<span class="keyword">delete</span>如何实现对象的动态内存管理(上面刚写完)</div><div class="line"></div><div class="line">类Obj的函数Initialize模拟了构造函数的功能,函数Destroy模拟了析构函数的功能。</div><div class="line"></div><div class="line">函数UseMallocFree中,由于<span class="built_in">malloc</span>/<span class="built_in">free</span>不能执行构造函数与析构函数,必须调用成员函数Initialize和Destroy来完成初始化与清除工作。C++风格的函数UseNewDelete则简单得多。</div><div class="line"></div><div class="line">所以我们不要企图用<span class="built_in">malloc</span>/<span class="built_in">free</span>来完成动态对象的内存管理,应该用<span class="keyword">new</span>/<span class="keyword">delete</span>。</div><div class="line"></div><div class="line">由于内部数据类型(基本数据类型)的“对象”没有构造与析构的过程,对它们而言<span class="built_in">malloc</span>/<span class="built_in">free</span>和<span class="keyword">new</span>/<span class="keyword">delete</span>是等价的。</div><div class="line"></div><div class="line">既然<span class="keyword">new</span>/<span class="keyword">delete</span>的功能完全覆盖了<span class="built_in">malloc</span>/<span class="built_in">free</span>,为什么C++不把<span class="built_in">malloc</span>/<span class="built_in">free</span>淘汰出局呢?</div><div class="line"></div><div class="line">这是因为C++程序经常要调用C函数,而C程序只能用<span class="built_in">malloc</span>/<span class="built_in">free</span>管理动态内存。</div><div class="line"></div><div class="line">如果用<span class="built_in">free</span>释放“<span class="keyword">new</span>创建的动态对象”,那么该对象因无法执行析构函数而可能导致程序出错。</div><div class="line"></div><div class="line">如果用<span class="keyword">delete</span>释放“<span class="built_in">malloc</span>申请的动态内存 ”,理论上讲程序不会出错,但是该程序的可读性很差。</div><div class="line"></div><div class="line">所以<span class="keyword">new</span>/<span class="keyword">delete</span>必须配对使用,<span class="built_in">malloc</span>/<span class="built_in">free</span>也一样。</div></pre></td></tr></table></figure>
<ul>
<li>7、内存耗尽怎么办?</li>
</ul>
<figure class="highlight awk"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div></pre></td><td class="code"><pre><div class="line">如果在申请动态内存时找不到足够大的内存块,malloc和new将返回NULL指针,宣告内存申请失败。通常有三种方式处理“内存耗尽”问题。</div><div class="line"></div><div class="line"><span class="number">1</span>)判断指针是否为NULL,如果是则马上用return语句终止本函数。例如:</div><div class="line"></div><div class="line">void Func(void)</div><div class="line">{</div><div class="line"> A *a = new A;</div><div class="line"> <span class="keyword">if</span>(a == NULL)</div><div class="line"> {</div><div class="line"> return;</div><div class="line"> }</div><div class="line"> …</div><div class="line">}</div><div class="line"></div><div class="line"><span class="number">2</span>)判断指针是否为NULL,如果是则马上用<span class="keyword">exit</span>(<span class="number">1</span>)终止整个程序的运行。例如:</div><div class="line"></div><div class="line">void Func(void)</div><div class="line">{</div><div class="line"> A *a = new A;</div><div class="line"> <span class="keyword">if</span>(a == NULL)</div><div class="line"> {</div><div class="line"> cout << “Memory Exhausted” << endl;</div><div class="line"> <span class="keyword">exit</span>(<span class="number">1</span>);</div><div class="line"> }</div><div class="line"> …</div><div class="line">}</div><div class="line"></div><div class="line"><span class="number">3</span>)为new和malloc设置异常处理函数。</div><div class="line"></div><div class="line">例如Visual C可以用_set_new_hander函数为new设置用户自己定义的异常处理函数,也可以让malloc享用与new相同的异常处理函数。</div><div class="line">详细内容请参考C 使用手册。</div><div class="line"></div><div class="line">上述(<span class="number">1</span>)(<span class="number">2</span>)方式使用最普遍。</div><div class="line">如果一个函数内有多处需要申请动态内存,那么方式(<span class="number">1</span>)就显得力不从心(释放内存很麻烦),应该用方式(<span class="number">2</span>)来处理。</div><div class="line"></div><div class="line">很多人不忍心用<span class="keyword">exit</span>(<span class="number">1</span>),问:“不编写出错处理程序,让操作系统自己解决行不行?”</div><div class="line"></div><div class="line">答案是不行。</div><div class="line">如果发生“内存耗尽”这样的事情,一般说来应用程序已经无药可救。</div><div class="line">如果不用<span class="keyword">exit</span>(<span class="number">1</span>) 把坏程序杀死,它可能会害死操作系统。</div><div class="line">道理如同:如果不把歹徒击毙,歹徒在老死之前会犯下更多的罪。</div><div class="line"></div><div class="line">有一个很重要的现象要告诉大家。对于<span class="number">32</span>位以上的应用程序而言,无论怎样使用malloc与new,几乎不可能导致“内存耗尽”。</div><div class="line"></div><div class="line">我在Windows <span class="number">98</span>下用Visual C 编写了测试程序,见示例<span class="number">7</span>。</div><div class="line"></div><div class="line">这个程序会无休止地运行下去,根本不会终止。因为<span class="number">32</span>位操作系统支持“虚存”,内存用完了,自动用硬盘空间顶替。</div><div class="line"></div><div class="line">我只听到硬盘嘎吱嘎吱地响,Window <span class="number">98</span>已经累得对键盘、鼠标毫无反应。</div><div class="line"></div><div class="line">我可以得出这么一个结论:对于<span class="number">32</span>位以上的应用程序,“内存耗尽”错误处理程序毫无用处。</div><div class="line"></div><div class="line">这下可把Unix和Windows程序员们乐坏了:反正错误处理程序不起作用,我就不写了,省了很多麻烦。</div><div class="line"></div><div class="line">我不想误导读者,必须强调:不加错误处理将导致程序的质量很差,千万不可因小失大。</div><div class="line"></div><div class="line">void main(void)</div><div class="line">{</div><div class="line"> float *p = NULL;</div><div class="line"> <span class="keyword">while</span>(<span class="number">1</span>)</div><div class="line"> {</div><div class="line"> p = new float[<span class="number">1000000</span>];</div><div class="line"> cout << <span class="string">"我正在吃你的电脑内存"</span> << endl;</div><div class="line"> <span class="keyword">if</span>(p==NULL)</div><div class="line"> <span class="keyword">exit</span>(<span class="number">1</span>);</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line">以上示例<span class="number">7</span>试图耗尽操作系统的内存, 在MacOS上测试<span class="number">8</span>G内存立刻就空了,然后硬盘剩余空间很快的下降,笔记本温度上升。</div></pre></td></tr></table></figure>
<ul>
<li>8、malloc/free 的使用要点</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div></pre></td><td class="code"><pre><div class="line">函数<span class="built_in">malloc</span>的原型如下:</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">void</span> * <span class="title">malloc</span><span class="params">(<span class="keyword">size_t</span> size)</span></span>;</div><div class="line"></div><div class="line">用<span class="built_in">malloc</span>申请一块长度为length的整数类型的内存,程序如下:</div><div class="line"></div><div class="line"><span class="keyword">int</span> *p = (<span class="keyword">int</span> *) <span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="keyword">int</span>) * length);</div><div class="line"></div><div class="line">我们应当把注意力集中在两个要素上:“类型转换”和“<span class="keyword">sizeof</span>”。</div><div class="line"><span class="number">1</span>) <span class="built_in">malloc</span>返回值的类型是<span class="keyword">void</span> *,所以在调用<span class="built_in">malloc</span>时要显式地进行类型转换,将<span class="keyword">void</span> * 转换成所需要的指针类型。</div><div class="line">true</div><div class="line"><span class="number">2</span>) <span class="built_in">malloc</span>函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数。</div><div class="line"></div><div class="line">我们通常记不住<span class="keyword">int</span>,<span class="keyword">float</span>等数据类型的变量的确切字节数。例如:</div><div class="line">truea) <span class="keyword">int</span>变量在<span class="number">16</span>位系统下是<span class="number">2</span>个字节,在<span class="number">32</span>位下是<span class="number">4</span>个字节。</div><div class="line">true</div><div class="line">trueb) <span class="keyword">float</span>变量在<span class="number">16</span>位系统下是<span class="number">4</span>个字节,在<span class="number">32</span>位下也是<span class="number">4</span>字节。</div><div class="line">true</div><div class="line">最好用以下程序作一次测试:</div><div class="line">true<span class="built_in">cout</span> << <span class="keyword">sizeof</span>(<span class="keyword">char</span>) << <span class="built_in">endl</span>;</div><div class="line">true<span class="built_in">cout</span> << <span class="keyword">sizeof</span>(<span class="keyword">int</span>) << <span class="built_in">endl</span>;</div><div class="line">true<span class="built_in">cout</span> << <span class="keyword">sizeof</span>(<span class="keyword">unsigned</span> <span class="keyword">int</span>) << <span class="built_in">endl</span>;</div><div class="line">true<span class="built_in">cout</span> << <span class="keyword">sizeof</span>(<span class="keyword">long</span>) << <span class="built_in">endl</span>;</div><div class="line">true<span class="built_in">cout</span> << <span class="keyword">sizeof</span>(<span class="keyword">unsigned</span> <span class="keyword">long</span>) << <span class="built_in">endl</span>;</div><div class="line">true<span class="built_in">cout</span> << <span class="keyword">sizeof</span>(<span class="keyword">float</span>) << <span class="built_in">endl</span>;</div><div class="line">true<span class="built_in">cout</span> << <span class="keyword">sizeof</span>(<span class="keyword">double</span>) << <span class="built_in">endl</span>;</div><div class="line">true<span class="built_in">cout</span> << <span class="keyword">sizeof</span>(<span class="keyword">void</span> *) << <span class="built_in">endl</span>;</div><div class="line">true</div><div class="line">在<span class="built_in">malloc</span>的“()”中使用<span class="keyword">sizeof</span>运算符是良好的风格,但要当心有时我们会昏了头,写出 p = <span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(p))这样的程序来。</div><div class="line"></div><div class="line"><span class="number">3</span>) 函数<span class="built_in">free</span>的原型如下:</div><div class="line"></div><div class="line"><span class="keyword">void</span> <span class="built_in">free</span>( <span class="keyword">void</span> * memblock );</div><div class="line"></div><div class="line">为什么<span class="built_in">free</span>函数不象<span class="built_in">malloc</span>函数那样复杂呢?这是因为指针p的类型以及它所指的内存的容量事先都是知道的,语句<span class="built_in">free</span>(p)能正确地释放内存。</div><div class="line"></div><div class="line">truea)如果p是<span class="literal">NULL</span>指针,那么<span class="built_in">free</span>对p无论操作多少次都不会出问题。</div><div class="line"></div><div class="line">trueb) 如果p不是<span class="literal">NULL</span>指针,那么<span class="built_in">free</span>对p连续操作两次就会导致程序运行错误。</div></pre></td></tr></table></figure>
<ul>
<li>9、new/delete 的使用要点</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div></pre></td><td class="code"><pre><div class="line">运算符<span class="keyword">new</span>使用起来要比函数<span class="built_in">malloc</span>简单得多,例如:</div><div class="line"></div><div class="line">C : <span class="keyword">int</span> *p1 = (<span class="keyword">int</span> *)<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="keyword">int</span>)*length);</div><div class="line">C++: <span class="keyword">int</span> *p2 = <span class="keyword">new</span> <span class="keyword">int</span>[length];</div><div class="line"></div><div class="line">这是因为<span class="keyword">new</span>内置了<span class="keyword">sizeof</span>、类型转换和类型安全检查功能。</div><div class="line"></div><div class="line">对于非内部数据类型的对象而言,<span class="keyword">new</span>在创建动态对象的同时完成了初始化工作。</div><div class="line"></div><div class="line">如果对象有多个构造函数,那么<span class="keyword">new</span>的语句也可以有多种形式。例如:</div><div class="line"></div><div class="line">class Obj</div><div class="line">{</div><div class="line"> <span class="keyword">public</span> :</div><div class="line"> Obj(<span class="keyword">void</span>); <span class="comment">// 无参数的构造函数</span></div><div class="line"> Obj(<span class="keyword">int</span> x); <span class="comment">// 带一个参数的构造函数</span></div><div class="line">true...</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test</span><span class="params">(<span class="keyword">void</span>)</span></span></div><div class="line">{</div><div class="line"> Obj *a = <span class="keyword">new</span> Obj;</div><div class="line"> Obj *b = <span class="keyword">new</span> Obj(<span class="number">1</span>); <span class="comment">// 初值为1</span></div><div class="line"> ...</div><div class="line"> <span class="keyword">delete</span> a;</div><div class="line"> <span class="keyword">delete</span> b;</div><div class="line">}</div><div class="line"></div><div class="line">如果用<span class="keyword">new</span>创建对象数组,那么只能使用对象的无参数构造函数。例如:</div><div class="line"></div><div class="line">Obj *objects = <span class="keyword">new</span> Obj[<span class="number">100</span>]; <span class="comment">// 创建100个动态对象</span></div><div class="line">不能写成</div><div class="line">Obj *objects = <span class="keyword">new</span> Obj[<span class="number">100</span>](<span class="number">1</span>);<span class="comment">// 创建100个动态对象的同时赋初值1</span></div><div class="line"></div><div class="line">在用<span class="keyword">delete</span>释放对象数组时,留意不要丢了符号‘[]’。例如:</div><div class="line"></div><div class="line"><span class="keyword">delete</span> []objects; <span class="comment">// true 正确的用法</span></div><div class="line"><span class="keyword">delete</span> objects; <span class="comment">// false 错误的用法</span></div><div class="line"></div><div class="line">后者相当于<span class="keyword">delete</span> objects[<span class="number">0</span>],漏掉了另外<span class="number">99</span>个对象。</div></pre></td></tr></table></figure>
<ul>
<li>10、一些心得体会</li>
</ul>
<figure class="highlight lsl"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">我认识不少技术不错的C/C++程序员,很少有人能拍拍胸脯说通晓指针与内存管理。</div><div class="line"></div><div class="line">大佬的经验教训是:</div><div class="line">true<span class="number">1</span>)越是怕指针,就越要使用指针。不会正确使用指针,肯定算不上是合格的程序员。</div><div class="line">true</div><div class="line">true<span class="number">2</span>)必须养成“使用调试器逐步跟踪程序”的习惯,只有这样才能发现问题的本质。</div></pre></td></tr></table></figure>]]></content>
</entry>
<entry>
<title><![CDATA[简单的项目自动构建]]></title>
<url>/2017/06/13/%E5%88%A9%E7%94%A8Dockerfile%E7%9A%84%E9%A1%B9%E7%9B%AE%E8%87%AA%E5%8A%A8%E6%9E%84%E5%BB%BA%E5%AD%A6%E4%B9%A0/</url>
<content type="html"><![CDATA[<blockquote>
<p>这篇文章教你在ubuntu服务器的pro线上环境和本地dev开发环境之间搭建自动构建流CI。自动构建不会同步数据库结构和数据,文章简单使用纯前端页面进行讲解,使用后端语言只需要事先部署测试好服务器环境即可。学习这篇文章之前你需要做以下几件事:</p>
<p><code>购买服务器和域名并将域名解析到服务器上</code>,<code>服务器和本地环境都安装了git环境</code>,<code>注册了github账号</code>。</p>
</blockquote>
<a id="more"></a>
<ul>
<li><p>首先你应该购买好服务器,用ubuntu用户登录,然后更新源,install zsh curl。然后根据Oh_My_Zsh开源地址提供的sh命令安装主题框架,该框架目前内置git v2.7。</p>
</li>
<li><p>用useradd -s /etc/zsh -mr 添加管理员用户,用passwd修改新用户密码。也可以用ubuntu登录服务器修改passwd。</p>
</li>
<li><p>然后呢?你需要安装nginx。安装完成后由于你域名已经解析到这台服务器,访问域名就能看到nginx默认页面。这个步骤在后续我写Dockerfile搭建自动构建流时候会省略。</p>
</li>
<li><p>配置本地和服务端公钥私钥,书写shell让本地终端可以免密码自动登录服务器。</p>
</li>
<li><p>安装nginx,默认nginx项目根目录位于<code>/usr/share/nginx/html</code>,这里只为不讲多站点配置。</p>
</li>
</ul>
]]></content>
<tags>
<tag> 系统规划 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Vim学习第三步是插件]]></title>
<url>/2017/06/08/Vim%E5%AD%A6%E4%B9%A0%E7%AC%AC%E4%B8%89%E6%AD%A5%E6%98%AF%E6%8F%92%E4%BB%B6/</url>
<content type="html"><![CDATA[<blockquote>
<p>当然,你会用vim自带的配置提高工作效率了,可你能够配置个Emmet出来吗?你能配置个Xdebug出来吗?强大的vim强在它的生态系统上,无数的插件都有支持vim的版本哦。</p>
<p>现在到处都流行组件化思想了,我们的vim好早就支持各种插件就是一种组件化。这里我们来试试插件的管理和安装。</p>
</blockquote>
<a id="more"></a>
<ul>
<li><p>vim是vi命令的升级版,总之就是各种更强且兼容。那么如果你使用linux系统,可能需要<code>sudo yum install vim -y</code>或者<code>sudo apt-get install vim -y</code>下载一下。</p>
</li>
<li><p>vim是一个在命令行模式编辑文件的软件,它有个全局配置文件和用户级配置文件.vimrc。主要用于多用户的linux服务器上它们分别位于<code>/usr/share/vim/vimrc</code>和<code>~/.vimrc</code>。</p>
</li>
</ul>
<ul>
<li><p>举个例子来看看我这里的vim全局配置文件吧:前面是vim默认打开的xitong,后面set开始都是我添加的设置语法高亮,Tab长度,智能缩紧等等。</p>
</li>
<li><p>但是MacOS作为个人电脑,默认情况并没有用户级配置文件,你可以自行建立配置文件和文件夹进行vim相关的管理:</p>
<figure class="highlight vim"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">cd</span> && <span class="built_in">mkdir</span> <span class="keyword">vim</span></div><div class="line"></div><div class="line"><span class="keyword">cp</span> /usr/share/<span class="keyword">vim</span>/vimrc ~/.vimrc</div></pre></td></tr></table></figure></li>
</ul>
]]></content>
<tags>
<tag> 高效工具 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Vim学习第二步是配置]]></title>
<url>/2017/06/08/Vim%E5%AD%A6%E4%B9%A0%E7%AC%AC%E4%BA%8C%E6%AD%A5%E6%98%AF%E9%85%8D%E7%BD%AE/</url>
<content type="html"><![CDATA[<blockquote>
<p>即使你根据第一篇文章实实在在的去敲过那么vim快捷键,我也建议你用vim写上一两万文章字数或者代码量再来看看这第二篇文章。对快捷键这种基础知识要是没有相当的熟练,你就会抱怨vim的各种不人性化,这第二篇文章就是让你对vim跨目相看,让你知道它是多么人性化。</p>
<p>但即使你熟悉了不少vim快捷键,默认情况它还是挺low的,这时候你需要配置vim自带的一些设置。这里我们就不讲快捷键,来说说vim自带的那些配置可以让你的工作效率增长多少。</p>
</blockquote>
<a id="more"></a>
<ul>
<li><h1 id="显示行号"><a href="#显示行号" class="headerlink" title="显示行号"></a>显示行号</h1><p>:set number</p>
</li>
<li><h1 id="处理只读文件时弹框提示"><a href="#处理只读文件时弹框提示" class="headerlink" title="处理只读文件时弹框提示"></a>处理只读文件时弹框提示</h1><p>set confirm</p>
</li>
<li><h1 id="TAB键的宽度"><a href="#TAB键的宽度" class="headerlink" title="TAB键的宽度"></a>TAB键的宽度</h1><p>set tabstop=4</p>
</li>
<li><h1 id="统一缩进"><a href="#统一缩进" class="headerlink" title="统一缩进"></a>统一缩进</h1><p>set softtabstop=2<br>set shiftwidth=2</p>
</li>
<li><h1 id="是否兼容vi"><a href="#是否兼容vi" class="headerlink" title="是否兼容vi"></a>是否兼容vi</h1><p>“ 1: compatible为兼容<br>“ 2: nocompatible为不完全兼容<br>set nocompatible</p>
</li>
<li><h1 id="退格键:indent能删除行首的空格,eol断行,start打开文件时回到上次编辑点"><a href="#退格键:indent能删除行首的空格,eol断行,start打开文件时回到上次编辑点" class="headerlink" title="退格键:indent能删除行首的空格,eol断行,start打开文件时回到上次编辑点"></a>退格键:indent能删除行首的空格,eol断行,start打开文件时回到上次编辑点</h1><p>“ 1: vi兼容<br>“ 2: indent,eol<br>“ 3: indent,eol,start<br>set backspace=2</p>
</li>
</ul>
<ul>
<li><h1 id="解决菜单乱码"><a href="#解决菜单乱码" class="headerlink" title="解决菜单乱码"></a>解决菜单乱码</h1><p>set encoding=utf-8 </p>
</li>
<li><h1 id="自动重新加载外部修改内容"><a href="#自动重新加载外部修改内容" class="headerlink" title="自动重新加载外部修改内容"></a>自动重新加载外部修改内容</h1><p>set autoread </p>
</li>
<li><h1 id="语法高亮"><a href="#语法高亮" class="headerlink" title="语法高亮"></a>语法高亮</h1><p>syntax on </p>
</li>
<li><h1 id="当前行高亮"><a href="#当前行高亮" class="headerlink" title="当前行高亮"></a>当前行高亮</h1><p>set cursorline</p>
</li>
<li><h1 id="高亮显示搜索到的关键字"><a href="#高亮显示搜索到的关键字" class="headerlink" title="高亮显示搜索到的关键字"></a>高亮显示搜索到的关键字</h1><p>set hlsearch </p>
</li>
<li><h1 id="开启文件类型检测"><a href="#开启文件类型检测" class="headerlink" title="开启文件类型检测"></a>开启文件类型检测</h1><p>filetype plugin indent on </p>
</li>
<li><h1 id="括号等自动补全脚本"><a href="#括号等自动补全脚本" class="headerlink" title="括号等自动补全脚本"></a>括号等自动补全脚本</h1><p>inoremap ( ()<left><br>inoremap [ []<left><br>inoremap { {}<left></left></left></left></p>
</li>
<li><h1 id="智能对齐"><a href="#智能对齐" class="headerlink" title="智能对齐"></a>智能对齐</h1><p>set smartindent</p>
</li>
<li><h1 id="自动对齐"><a href="#自动对齐" class="headerlink" title="自动对齐"></a>自动对齐</h1><p>set autoindent</p>
</li>
<li><h1 id="自动缩进"><a href="#自动缩进" class="headerlink" title="自动缩进"></a>自动缩进</h1><p>set autoindent</p>
</li>
<li><h1 id="一次Tab为2个字符"><a href="#一次Tab为2个字符" class="headerlink" title="一次Tab为2个字符"></a>一次Tab为2个字符</h1><p>set tabstop=2</p>
</li>
<li><h1 id="按一次Tab前进2个字符"><a href="#按一次Tab前进2个字符" class="headerlink" title="按一次Tab前进2个字符"></a>按一次Tab前进2个字符</h1><p>set softtabstop=2<br>set shiftwidth=2</p>
</li>
<li><h1 id="用空格代替Tab"><a href="#用空格代替Tab" class="headerlink" title="用空格代替Tab"></a>用空格代替Tab</h1><p>set expandtab</p>
</li>
<li><h1 id="搜索忽略大小写"><a href="#搜索忽略大小写" class="headerlink" title="搜索忽略大小写"></a>搜索忽略大小写</h1><p>set ignorecase</p>
</li>
<li><h1 id="设置命令历史行数"><a href="#设置命令历史行数" class="headerlink" title="设置命令历史行数"></a>设置命令历史行数</h1><p>set history=100</p>
</li>
<li><h1 id="启动的时候不显示那个援助索马里儿童的提示"><a href="#启动的时候不显示那个援助索马里儿童的提示" class="headerlink" title="启动的时候不显示那个援助索马里儿童的提示"></a>启动的时候不显示那个援助索马里儿童的提示</h1><p>set shortmess=atl</p>
</li>
<li><h1 id="命令模式的行高度"><a href="#命令模式的行高度" class="headerlink" title="命令模式的行高度"></a>命令模式的行高度</h1><p>set cmdheight=2</p>
</li>
<li><h1 id="不要闪烁"><a href="#不要闪烁" class="headerlink" title="不要闪烁"></a>不要闪烁</h1><p>set novisualbell </p>
</li>
<li><h1 id="缺省不产生备份文件"><a href="#缺省不产生备份文件" class="headerlink" title="缺省不产生备份文件"></a>缺省不产生备份文件</h1><p>set nobackup</p>
</li>
<li><h1 id="使PHP识别EOT字符串"><a href="#使PHP识别EOT字符串" class="headerlink" title="使PHP识别EOT字符串"></a>使PHP识别EOT字符串</h1><p>hi link phpheredoc string</p>
</li>
<li><h1 id="设置鼠标模式为Windows"><a href="#设置鼠标模式为Windows" class="headerlink" title="设置鼠标模式为Windows"></a>设置鼠标模式为Windows</h1><p>behave mswin</p>
</li>
</ul>
]]></content>
<tags>
<tag> 高效工具 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Vim学习第一步是快捷键]]></title>
<url>/2017/06/08/Vim%E5%AD%A6%E4%B9%A0%E7%AC%AC%E4%B8%80%E6%AD%A5%E6%98%AF%E5%BF%AB%E6%8D%B7%E9%94%AE/</url>
<content type="html"><![CDATA[<blockquote>
<p>有时候自己经常要操作服务器,甚至在Mac上经常使用命令行导致不太愿意在小文件上特意open后使用IDE或者其他编辑器打开,这时候我还是得用vim。配合上Zsh的主题Oh_My_Zsh,操作服务器就简单多了。</p>
<p>这几篇设计到vim的文章,由于Windows命令行不支持vim命令只提供了图形化Gvim,对于跨平台的考虑,为兵部推荐使用Gvim学习。建议使用Windows平台的朋友升级到Windows10 1703版本,使用内置的Ubuntu进行学习。</p>
</blockquote>
<a id="more"></a>
<ul>
<li><p>打开vim后我分不清模式,不知道怎么写代码怎么办?</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">vim有三种模式:插入模式,命令模式,转义模式。</div><div class="line"></div><div class="line">打开某个文件后是命令模式,按下i就是插入模式,也可以按一些其他键。</div><div class="line"></div><div class="line">从插入模式回到命令模式只要按一下ESC,命令模式是其他两种模式的桥梁。</div><div class="line"></div><div class="line"><span class="section">转义模式就是使用类似:在屏幕下方书写的模式,文件保存退出和一些编辑器设置都在转义模式下操作。</span></div></pre></td></tr></table></figure>
</li>
<li><p>我使用vim命令打开了一个文件,怎么不保存退出?</p>
<figure class="highlight css"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">在转义模式下输入<span class="selector-pseudo">:w</span>回车即可保存,<span class="selector-pseudo">:wq</span>回车即可保存并退出。</div><div class="line"></div><div class="line">如果你打开了没有修改权限的文件,就需要先使用<span class="selector-pseudo">:q</span>!强制不保存退出。</div></pre></td></tr></table></figure>
</li>
<li><p>方向键有各种不便捷怎么办?</p>
<figure class="highlight vim"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">vim</span>的方向键是在命令模式下用hjkl逆时针代替左下上右。</div></pre></td></tr></table></figure>
</li>
<li><p>我使用vim命令打开了一个文件,怎么不保存退出?</p>
<figure class="highlight css"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">在转义模式下输入<span class="selector-pseudo">:q</span>回车即可。</div><div class="line"></div><div class="line">如果你改动了文件,就需要使用<span class="selector-pseudo">:q</span>!强制不保存退出。</div></pre></td></tr></table></figure>
</li>
<li><p>怎么在文件中查找某个单词或者字母?</p>
<figure class="highlight applescript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">在命令模式下使用/<span class="built_in">word</span>回车即可在当前文件当前行之后搜索<span class="built_in">word</span>单词。</div><div class="line"></div><div class="line">搜索完毕按n跳转到下一个匹配单词,按N跳转到上一个匹配单词。</div><div class="line"></div><div class="line">使用?<span class="built_in">word</span>在当前行之前搜索,个人爱好,我一般不用。</div><div class="line"></div><div class="line">建议配合搜索关键字hlsearch高亮使用。</div></pre></td></tr></table></figure>
</li>
<li><p>如何取消搜索后的高亮显示?</p>
<figure class="highlight css"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">转义模式输入<span class="selector-pseudo">:noh</span>回车即可。</div></pre></td></tr></table></figure>
</li>
<li><p>怎么撤回操作?</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">命令模式下按一下u即可。</div></pre></td></tr></table></figure>
</li>
<li><p>怎么删除当前行?</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">命令模式下按两下d,不限制按下的时间间隔。</div></pre></td></tr></table></figure>
</li>
<li><p>怎么跳转到行首和行尾?</p>
<figure class="highlight elixir"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">命令模式下按<span class="number">0</span>或者^就可以光标到行首,主意后者是要按Shift的。</div><div class="line"></div><div class="line">命令模式下按<span class="variable">$就</span>可以光标到行首。</div><div class="line"></div><div class="line">输入<span class="number">2</span><span class="variable">$就</span>可以到下一行行尾,主意输入数字过程屏幕是没有提示的。</div></pre></td></tr></table></figure>
</li>
<li><p>怎么跳转到文件头部和尾部?</p>
<figure class="highlight elixir"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">按两下g就到第一行行首。</div><div class="line"></div><div class="line">按一下G就到了文件最后一行,再按一下<span class="variable">$就</span>到了最后一行的行尾。</div></pre></td></tr></table></figure>
</li>
<li><p>光标怎么移动到某单词的开始和结束?</p>
<figure class="highlight vim"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">命令模式下按一下<span class="keyword">w</span>光标就到了单词尾巴。</div><div class="line"></div><div class="line">这里要注意<span class="keyword">w</span>其实是下一单词首位置,按<span class="keyword">e</span>才是<span class="keyword">vim</span>中说的单词尾部。</div><div class="line"></div><div class="line">按一下<span class="keyword">b</span>光标就到了当前单词头部。</div></pre></td></tr></table></figure>
</li>
<li><p>怎么跳转到指定行?</p>
<figure class="highlight excel"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">转义模式下输入<span class="symbol">:n</span>回车即可,<span class="built_in">n</span>为数字行号。</div><div class="line"></div><div class="line">也可以输入nG直接跳转到第<span class="built_in">n</span>行行首,如<span class="number">48</span>G。</div></pre></td></tr></table></figure>
</li>
<li><p>光标上移下移n行怎么做?</p>
<figure class="highlight excel"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="built_in">n</span>+就是下移,<span class="built_in">n</span>-就是上移,主意要按Shift键。</div><div class="line"></div><div class="line">例如光标上移<span class="number">10</span>行:<span class="number">10</span>-</div></pre></td></tr></table></figure>
</li>
<li><p>怎么重复执行历史的转义命令?</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="section">按下:之后按向上键即可。</span></div></pre></td></tr></table></figure>
</li>
<li><p>Mac上怎么在vim文件中输入表情?</p>
<figure class="highlight mathematica"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">插入模式下输入系统设置好的命令选择即可,默认快捷键为<span class="keyword">Control</span>+Command+<span class="keyword">Space</span>。</div></pre></td></tr></table></figure>
</li>
<li><p>复制,剪切,粘贴怎么做?</p>
<figure class="highlight x86asm"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">yy是整行复制。</div><div class="line"></div><div class="line"><span class="built_in">dd</span>剪切光标所在行。</div><div class="line"></div><div class="line">粘贴按p回车。</div></pre></td></tr></table></figure>
</li>
<li><p>怎么在vim中执行shell命令?</p>
<figure class="highlight jboss-cli"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">:!<span class="keyword">ls</span>就相当于终端执行<span class="keyword">ls</span>命令,用于写代码时候查看当前目录存在的文件。</div></pre></td></tr></table></figure>
</li>
<li><p>单文件中水平和垂直分屏怎么做?</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">首先在windows上的很多终端模拟器包括内置bash应该是不支持vim分屏的。</div><div class="line"></div><div class="line"><span class="section">水平分屏是:sp,垂直分屏是vsp,具体用法靠经验去尝试填坑吧。</span></div><div class="line"></div><div class="line">由于显示器横的,我就习惯用垂直分屏,切换使用。</div><div class="line"></div><div class="line"><span class="section">所在屏切换: 这个应该是Ctrl+w的,但是会和MacOS上的关闭窗口冲突哦。</span></div><div class="line"></div><div class="line"><span class="section">退出分屏在当前所在所在屏按:q。</span></div></pre></td></tr></table></figure>
</li>
<li><p>文件之外怎么开始水平和垂直分屏?</p>
<figure class="highlight vim"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">意思是我这个目录下有file1和file2,我怎么用<span class="keyword">vim</span>分屏同时打开两个甚至多个文件。</div><div class="line"></div><div class="line">垂直分屏:<span class="keyword">vim</span> -O file1 file2 ...</div><div class="line"></div><div class="line">水平分屏:<span class="keyword">vim</span> -<span class="keyword">o</span> file1 file2 ...</div></pre></td></tr></table></figure>
</li>
</ul>
<blockquote>
<p>这里以问答形式回复是希望大家可以同样的提问,完全没有基础可以先看看网上一些vim快捷键作弊表。看完这篇文章你肯定会问一些其他的操作,说实话:其他操作你要么自己写shell命令,要么就进入第二章节的配置,甚至更强大的操作是需要第三节的插件才能搞定的,我也是在一起学习呢。</p>
<p><a href="http://www.cnblogs.com/jiqingwu/archive/2012/06/14/vim_notes.html" target="_blank" rel="external">Vim使用笔记</a></p>
<p><a href=""></a></p>
</blockquote>
]]></content>
<tags>
<tag> 高效工具 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[转载于'Vimer的程序世界'的一篇创业类文章]]></title>
<url>/2017/06/08/%E8%BD%AC%E8%BD%BD%E4%BA%8E-Vimer%E7%9A%84%E7%A8%8B%E5%BA%8F%E4%B8%96%E7%95%8C-%E7%9A%84%E4%B8%80%E7%AF%87%E5%88%9B%E4%B8%9A%E7%B1%BB%E6%96%87%E7%AB%A0/</url>
<content type="html"><![CDATA[<blockquote>
<p>这两天折腾vim快捷键,编辑器设置和插件相关知识期间,偶然从<a href="http://easwy.com/blog/" target="_blank" rel="external">易水博客</a>得知这样一个Vim使用群体们的社区聚集地:<a href="http://www.vimer.cn/" target="_blank" rel="external">Vimer的程序世界</a>,站点内容不多,但写的都很翔实。其中看到这篇文章我便转载过来,以示警醒。</p>
<p>原文地址:<a href="http://www.vimer.cn/archives/3148.html" target="_blank" rel="external">关于员工的几件事</a></p>
</blockquote>
<a id="more"></a>
<ul>
<li>前段时间有朋友问我:创业这几年对你改变最大的是什么?我想了半天,说道:应该是思考的角度。</li>
</ul>
<h4 id="一-关于离职"><a href="#一-关于离职" class="headerlink" title="一. 关于离职"></a>一. 关于离职</h4><ul>
<li><p>只要涉及到团队,员工离职就是一个永远逃避不了的问题。</p>
</li>
<li><p>创业这几年,不停的有人入职、离职,人与人之间的关系可以多快的建立起来,有可以多快的消失掉。</p>
</li>
<li><p>而作为团队的leader要做的,就是通过 感情、成长、利益、希望 各种方面,将这段关系维持的尽量长一点。</p>
</li>
<li><p>之前,我一直在想,中小型的公司,即使能够一直还不错的活着,最终影响员工选择离开的是什么?<br>当时我得出的结论是:生活。</p>
</li>
<li><p>在深圳,即使以腾讯这个规模的体量,也无法确保员工的薪水能够在深圳买的起房子,而仅仅只是能够提供部分无息贷款的方式。</p>
</li>
</ul>
<blockquote>
<p>那么小公司呢?</p>
</blockquote>
<ul>
<li><p>我想到最后,只有一个方法,那就是小公司要自己成长到足够的体量,足以让核心的老员工们,最终能够达到足够的财务自由。</p>
</li>
<li><p>然而,现实远要比想象精彩。</p>
</li>
<li><p>我忘记了还有理想这回事。</p>
</li>
<li><p>最难挽留的离职,不是太累,也不是没前景,也不是薪水低,而是理想。</p>
</li>
<li><p>就像我当年离职创业一样,并不是任何加薪之类的方式可以挽留的了的。</p>
</li>
<li><p>其实慢慢的,当公司足够强壮的时候,即时是leader级别的人离职也渐渐不会对公司产生多大的影响了。</p>
</li>
<li><p>而我一直相信并且也一直在被验证的事情就是:</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">每一个离开的人,都在让这家公司变得更好。</div><div class="line"></div><div class="line">每一个坚持的人,终将收获这份更好。</div></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="二-关于上下级社交"><a href="#二-关于上下级社交" class="headerlink" title="二. 关于上下级社交"></a>二. 关于上下级社交</h4><ul>
<li><p>之所以提这个事情,是因为昨天很悲伤的发现,自己被公司很多员工屏蔽掉朋友圈了。</p>
</li>
<li><p>我之前在有一篇文章中看到过类似的讨论,朋友圈到底要不要屏蔽掉上司?</p>
</li>
<li><p>有很多愣头青非常自豪的评论道:下了班就是自由人,凭什么还要让老板看我的生活?</p>
</li>
<li><p>说的确实没错。</p>
</li>
<li><p>但是如果你只想和老板谈工作的话,那么工作中,就不要想着老板会和你讲人情了。</p>
</li>
<li><p>老实说,为什么我建议做leader的应该适时的发一下朋友圈状态?</p>
</li>
<li><p>并不是说真的要去跟大家汇报一下你当前的状态,而是为了给你的员工一个和你互动的机会。</p>
</li>
<li><p>现在的生活工作节奏这么快,单独抽时间来和每个人进行一对一的沟通根本不现实,而一条朋友圈可以很大程度的缓和这个问题。</p>
</li>
<li><p>那为什么不要屏蔽掉你领导的朋友圈呢?因为朋友圈被屏蔽是可以被发现的,就像我现在遇到的,你说多尴尬?</p>
</li>
<li><p>再有就是,朋友圈是一个多么适合让你的领导知道你状态的地方啊?这比你在QQ上直接突兀的找你领导聊天顺畅多了。</p>
</li>
<li><p>当然,也有同学担心自己在朋友圈说多错多,所以干脆屏蔽了之。</p>
</li>
<li><p>但是我想说的是,任何事情,逃避永远都是最容易的做法,但是却不见得最有效。</p>
</li>
</ul>
<h4 id="三-关于逃离北上广深"><a href="#三-关于逃离北上广深" class="headerlink" title="三. 关于逃离北上广深"></a>三. 关于逃离北上广深</h4><ul>
<li><p>这个问题已经被各大媒体讨论烂了,什么深圳卖一套房,回老家可以买3套房1辆车,日子过的可清闲。</p>
</li>
<li><p>对此我实在懒得评论,只有一句话:</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">除非你的孩子再也不来北上广,否则他就要跟你一样,再经受一次同样的痛苦!</div></pre></td></tr></table></figure>
</li>
</ul>
]]></content>
</entry>
<entry>
<title><![CDATA[关于不同系统中的CRLF处理问题]]></title>
<url>/2017/06/06/%E5%85%B3%E4%BA%8E%E4%B8%8D%E5%90%8C%E7%B3%BB%E7%BB%9F%E4%B8%AD%E7%9A%84CRLF%E5%A4%84%E7%90%86%E9%97%AE%E9%A2%98/</url>
<content type="html"><![CDATA[<blockquote>
<p>昨天胖子在群里问了个<code>git add</code>将代码从工作区加入暂存区时出现CRLF和LF转换的问题,正好一年前我刚玩linux时候研究过一阵子这个问题,今天早上使用tcg/voyager时候也出现了这个问题,这里我就稍微说一下问题出现的原因以及处理的办法。</p>
<p>如果您在Windows上进行编程,但你的合作团队有人在MacOS或者Linux上编程,你可能遇到这篇文章的说明问题。这是因为Windows在其文件中使用换行符和换行字符,而Mac和Linux系统只使用换行字符。这是跨平台工作令人难以置信的烦人事实; Windows上的许多编辑器用CRLF替换现有的LF行的结尾,或者当用户点击Enter键时插入两个行结束字符</p>
</blockquote>
<a id="more"></a>
<ul>
<li><p>首先我们必须知道现在电脑系统有windows,unix两大系列,unix下有很多变体称为<code>类Unix系统</code>,主要有MacOS,Linux,Hp-ux,Ibm-aix,Solaris等等。这其中由于Linux是开源集大成者,在它的体系中又衍生了以Fodora和Debian的两大阵营。类unix系统大多数时候是使用兼容的,但是windows和类unix系统之间无论是操作还是设计理念都不一样。</p>
</li>
<li><p>这次要提到的问题,起源就在上面这段话中。类unix系统中,回车就是回车(carriage return),换行就是换行(line feed),它们绑定13和10两个ASCII码值,回车和换行分别简称CR和LF。编辑代码的时候,Windows系统里面,每行结尾是”<回车><换行>”,即”\r\n”;类Unix系统里,每行结尾是”<回车>”。</p>
</li>
<li><p>这样会导致什么后果?Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。</p>
</li>
<li><p>那么胖子的<code>git add</code>操作中为什么会提示LF将会被替换为CRLF呢?主要可能有下面几个原因?</p>
<ul>
<li>团队开发,每个人实用的操作系统平台不同。</li>
<li>胖子使用了双系统,开发时候切换系统进行编码。</li>
<li>没有设置PhpStorm和Atom等常用IDE均有的LF绑定功能。</li>
</ul>
</li>
<li><p>解决办法呢?主要看你从git角度去解决还是文件角度去思考。如果你想把文件本身进行转换,请使用<code>IDE的LF-CR绑定设置</code>或者<code>.editorconfig</code>文件转换,如果你从代码提交暂存区或者仓库来考虑,那么Git有几个配置选项来帮助解决这些问题,你应该看看下面的几行代码:</p>
<figure class="highlight routeros"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">git<span class="built_in"> config </span>core.autocrlf <span class="literal">true</span></div><div class="line"></div><div class="line">git<span class="built_in"> config </span>core.autocrlf input</div><div class="line"></div><div class="line">git<span class="built_in"> config </span>core.autocrlf <span class="literal">false</span></div></pre></td></tr></table></figure>
</li>
</ul>
<blockquote>
<p>core.autocrlf这个设置应该在Windows检查中留下CRLF结尾,但是在Mac和Linux系统以及存储库中的LF结束。</p>
</blockquote>
<ul>
<li><p>第一行:当你将文件添加到暂存区时,Git可以通过设置core.autocrlf将CRLF行结尾自动转换为LF来处理这类问题。如果您在Windows机器上,将其设置为true,那么当您pull代码时,将LF结尾转换为CRLF。</p>
</li>
<li><p>第二行:如果您使用的是Linux或Mac系统,那么当您pull文件时,您不希望Git自动转换它们; 然而,如果你的Windows猪队友把未经处理带CRLF格式的文件push到远程代码库,那么你可能希望Git来自动解决这个问题。可以通过将core.autocrlf设置为input来告知Git将CRLF转换为LF。</p>
</li>
<li><p>第三行:如果你是Windows程序员,只执行一个Windows项目或者所团队都是用windows系统甚至服务器都用windows,那么您可以关闭此功能,通过将配置值设置为false,将回车记录在存储库中。</p>
</li>
<li><p>参考地址:</p>
<ul>
<li><a href="http://www.ruanyifeng.com/blog/2006/04/post_213.html" target="_blank" rel="external">阮一峰网络日志</a></li>
<li><a href="https://zh.wikipedia.org/wiki/%E7%B1%BBUnix%E7%B3%BB%E7%BB%9F" target="_blank" rel="external">维基百科:类Unix系统</a></li>
</ul>
</li>
</ul>
]]></content>
<tags>
<tag> 操作系统 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[来聊聊Apache和Nginx的本地多站点虚拟域名配置]]></title>
<url>/2017/06/05/%E6%9D%A5%E8%81%8A%E8%81%8AApache%E5%92%8CNginx%E7%9A%84%E6%9C%AC%E5%9C%B0%E5%A4%9A%E7%AB%99%E7%82%B9%E8%99%9A%E6%8B%9F%E5%9F%9F%E5%90%8D%E9%85%8D%E7%BD%AE/</url>
<content type="html"><![CDATA[<blockquote>
<p>以前写过一篇在windows系统上使用PhpStudy配置本地Apache虚拟域名的教程,如果我已经是高贵的Mac用户,作为类Unix系统中的集大成者,我当然是要使用纯Apache和Nginx配置多站点了,怎么能还用集成环境呢?</p>
<p>这篇文章就是教你在命令行下操作配置Apache和Nginx下的本地域名多站点,如果你看过上一篇文章我写的配置的原理,那么阅读和学会这篇文章就是超级简单的,建议没看过的先看上一篇文章哦:<code>来聊聊PhpStudy环境本底多站点虚拟域名配置</code>。</p>
</blockquote>
<a id="more"></a>
<ul>
<li>的饭撒上点</li>
</ul>
]]></content>
<tags>
<tag> linux </tag>
</tags>
</entry>
<entry>
<title><![CDATA[BootStrap3入门学习(特效篇)]]></title>
<url>/2017/06/05/BootStrap3%E5%85%A5%E9%97%A8%E5%AD%A6%E4%B9%A0-%E7%89%B9%E6%95%88%E7%AF%87/</url>
<content type="html"><![CDATA[<blockquote>
<p>教程整理自慕课网(原文部分错误在这篇文章得到修改,本文版本Bootstrap3.3.7)。文章有上下两个篇幅,分别是BootStrap3在样式和JS特效果组件的学习和说明。这篇文章是下半部分JS特效组件篇章。</p>
</blockquote>
<a id="more"></a>
<p>fsd</p>
]]></content>
<tags>
<tag> 基础学习 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[无敌组合之Oh_My_Zsh配合iTerm2]]></title>
<url>/2017/06/04/%E6%97%A0%E6%95%8C%E7%BB%84%E5%90%88%E4%B9%8BOh-My-Zsh%E9%85%8D%E5%90%88iTerm2/</url>
<content type="html"><![CDATA[<blockquote>
<p>由于iTerm2只有MacOS版本,所以首先你需要有一台Mac系统的电脑,黑苹果装的系统也行。然后你要知道iTerm2只是一个终端工具,比MacOS自带的terminal好在哪里呢?各种插件和命令提示,人性化的快捷键等等。</p>
<p>那么Oh_My_Zsh又是什么呢?你要知道shell是unix内核外面的一层壳,这个壳可以用很多材料去做,unix系统开发人员用塑料做了个csh壳,linux维护人员用泥巴做了个bash壳,考虑到类unix系统的shell兼容性,这些系统都会提供底层的接口让你选择安装和使用哪一种shell。不同的shell语言命令和语法都有点不同。</p>
</blockquote>
<a id="more"></a>
<ul>
<li><p>那么就有人在一种名为zsh的shell基础上开发了一套让人高效工作的主题系统,名为Oh_My_Zsh。当然其实它可以在bash的基础上开发,完认为主要是考虑到bash的历史问题太久远等问题吧。</p>
</li>
<li><p>iTerm2是一个终端软件,其3.0版本相比2.0版本增加了很多新功能,具体区别可以在iTerm2 3.0的文档中看到。</p>
</li>
<li><p>iTerm2 2.1.4版的官方文档在这里:<a href="https://www.iterm2.com/documentation/2.1/" target="_blank" rel="external">https://www.iterm2.com/documentation/2.1/</a> 。</p>
</li>
<li><p>iTerm2 3.0版本的官方文档在这里:<a href="https://www.iterm2.com/documentation.html" target="_blank" rel="external">https://www.iterm2.com/documentation.html</a> 。</p>
</li>
<li><p>Oh_My_Zsh最强大的地方是它的插件系统,其次是无尽额度主题系统。</p>
</li>
<li><p>Oh_My_Zsh的官方文档:<a href="https://github.com/robbyrussell/oh-my-zsh/wiki" target="_blank" rel="external">https://github.com/robbyrussell/oh-my-zsh/wiki</a> 。</p>
</li>
<li><p>最后贴上iTerm2最值得收藏的一些快捷键,包括<code>标签</code>,<code>分屏</code>,<code>其他</code>,<code>常用快捷键</code>,<code>选中复制</code>,<code>自动完成</code>,<code>剪切历史</code>等等。</p>
</li>
</ul>
<p><img src="http://upload-images.jianshu.io/upload_images/3995745-ceddf809923385aa.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1440/q/50" alt="iTerm2快捷键"></p>
]]></content>
<tags>
<tag> 高效工具 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[新时代的composer组件化学习道路]]></title>
<url>/2017/06/02/%E6%96%B0%E6%97%B6%E4%BB%A3%E7%9A%84composer%E7%BB%84%E4%BB%B6%E5%8C%96%E5%AD%A6%E4%B9%A0%E9%81%93%E8%B7%AF/</url>
<content type="html"><![CDATA[<blockquote>
<p>自己搭建一个php的mvc框架,这个想法是我学CodeIgniter框架没几天就产生的想法,也确实去做了,可只是目录结构上有mvc的样子有什么用呢?写的代码没有一点面向对象的感觉,全是require引入文件。</p>
<p>使用composer搭建一个面向对象的组件化php框架,这个想法已经在我脑海中存在了好几个月。这个框架本打算暑假开始搭建,可最近心里老是想起这件事,于是今天早上5:37起床开电脑把开头的准备工作搞定了,其他composer组件添加并集成使用部分就慢慢搞好了,搞定路由下一个就是有点麻烦的Model数据库操作了。</p>
</blockquote>
<a id="more"></a>
<h4 id="进度汇报"><a href="#进度汇报" class="headerlink" title="进度汇报"></a>进度汇报</h4><ul>
<li><p>首先是composer项目的初始化我没有用使用composer init,而且通过composer.json开始项目。然后新建app框架应用目录,config项目配置目录,public前端访问目录,framework自定义类库。接着立刻开始github寻找合适了composer路由组件,考虑到初步学习就找了个加注释仅有163行代码的Macaw。然后前端建立index.php引入composer自动加载文件和config/routes.php路由配置文件,并在routes.php中使用Macaw调用不存在的静态方法get,第一个参数’/index’,在闭包函数中输出字符串。</p>
</li>
<li><p>这个时候通过修改hosts和vhost.conf将qframe.dev映射到本地public目录,我这里使用的是apache。访问该虚拟域名/index发现并没有成功输出字符串,但是访问index.php/index 却可以。这是因为apache的rewrite module开启后还需要书写.htaccess请求转发文件,这个步骤是apache伪静态的内容,我就直接把laravel的这个文件cp过来用了。</p>
</li>
<li><p>这时候用postman测试restful常用四大方法都没问题,路由部分就结束了。开始控制器和路由的关联。在app中新建Controllers并书写基础控制器和测试控制器,路由和控制器中的写法和laravel使用的写法类似,再次访问网址直接看不到界面了,这是因为composer.json没有加入自动加载配置。添加autoload键值对并使用classmap数组加载控制器目录,然后执行dump-composer更新锁文件即可。</p>
</li>
<li><p>接下来进入一个本可以很麻烦的阶段:数据库操作。由于RESTful以资源实体为目标,我将Model修改为具体的Entities,也方便后期分层添加Model层的其他处理目录。暂时我只能在控制器中连接数据库进行CURD操作,后期再来依赖注入。那么我们新建数据库,数据表,插入数据,然后在Entities中建立Article.php文章实体,composer.json的classmap数组加载该目录。</p>
</li>
<li><p>在Article的first静态方法中连接数据库并返回查询到的数据,在控制器中直接Article::first()即可。关于为什么使用静态方法,这一点我认为是防止后续还需要这段数据,减少查库操作。</p>
</li>
</ul>
<h4 id="阶段疑问"><a href="#阶段疑问" class="headerlink" title="阶段疑问"></a>阶段疑问</h4><ul>
<li><p>.htaccess书写用到了正则表达式且涉及到apache模块的开发和使用问题,存在少许疑问。</p>
</li>
<li><p>Macaw.php一共就163行代码,暂时没有完全理解使用原因。</p>
</li>
<li><p>关于composer的autoload四种方式不太理解,以及spr-0在此处的兼容性使用。</p>
</li>
<li><p>关于数据库部分的配置和CURD操作封装问题,还需要学习一种composer组件,刚开始就不考虑这件事吧。</p>
</li>
<li><p>关于静态方法在此处使用的原因,不知道自己的理解有哪里不妥当和不完善之处。</p>
</li>
</ul>
]]></content>
<tags>
<tag> 面向对象 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[第N次安装Hexo框架和Next博客主题]]></title>
<url>/2017/06/01/%E7%AC%ACN%E6%AC%A1%E5%AE%89%E8%A3%85Hexo%E6%A1%86%E6%9E%B6%E5%92%8CNext%E5%8D%9A%E5%AE%A2%E4%B8%BB%E9%A2%98/</url>
<content type="html"><![CDATA[<blockquote>
<p>换了 Mac 之后 Hexo 框架和主题文章全没了,备份到码云的文章数据被 .gitignore 忽略了,没办法找个时间自己手动备份一下 Hexo 博客。这次懂事了,必须用iCloud把数据全备份下来,这里 windows 下的 OneDrive 即时备份机制真恶心。</p>
<p>然后就是<code>npm install -g hexo-cli</code>安装 hexo 客户端工具,在 ~/Documents/Hexo/ 目录下初始化框架:<code>hexo init</code>。这些操作在第一篇文章<code>又写Next博客</code>就提过,这里又说了一遍。为了表示差异性,这篇文章我就主要讲一些功能特效和 Next 主题的配置吧。</p>
</blockquote>
<a id="more"></a>
<ul>
<li>Next三种主题选择</li>
</ul>
<blockquote>
<p>在配置文件中搜索 Schemes ,你会看到<code>Muse, Mist, Pisces</code>三种 scheme,去掉你喜欢的主题前的 # 注释即可。修改主题需要重启 hexo 服务并执行清除缓存操作:<code>hexo clean</code>。</p>
</blockquote>
<ul>
<li>右下角的屏幕滚动百分比设置。</li>
</ul>
<blockquote>
<p>配置文件中将 scrollpercent 设置为 true 即可,如果你要让百分比在侧边栏显示,只需要把b2t的值也设置为 true。</p>
</blockquote>
<ul>
<li>多种canvas背景特效</li>
</ul>
<blockquote>
<p>在配置文件中选择性的把 canvas_ 开头的值设置为 true 即可,特效可以同时设置为 true。</p>
</blockquote>
<ul>
<li>关闭被墙的 Google 字体</li>
</ul>
<blockquote>
<p>配置文件中将 font 中的 enable 和 global 中的 external 设置为 false 即可。</p>
</blockquote>
<ul>
<li>给博文添加协议</li>
</ul>
<blockquote>
<p>配置文件中把 post_copyright 的 enable 设置为 true 即可,如果你想在侧边栏也有这样的提示图标,把 creative_commons 的值设置为 by-nc-sa 即可。</p>
</blockquote>
<ul>
<li>前端/本地搜索功能</li>
</ul>
<blockquote>
<p>配置文件中的 local_search 中将 enable 的值设置为 true 即可。</p>
</blockquote>
<ul>
<li>友情链接 /social links 设置</li>
</ul>
<blockquote>
<p>打开配置文件中 social 的默认注释并添加链接即可,例如: <code>简书博客: http://www.jianshu.com/u/9d64b43bc1a1</code>。同时可以为友情链接设置 FontWaesome 图标,图标名参考 FontAwesome 官网:<a href="http://fontawesome.io/icons" target="_blank" rel="external">http://fontawesome.io/icons</a></p>
</blockquote>
<ul>
<li>博主头像设置</li>
</ul>
<blockquote>
<p>在 next/images/ 中放入你的头像,名称为 avatar.jpg ,然后打开 Next 配置文件<code>Sidebar Avatar</code>中avatar默认的注释并修改对应的值为<code>/images/avatar.jpg</code>,你也可以根据这里的说明把头像放倒 uploads 文件夹下。</p>
</blockquote>
<ul>
<li>网站图标设置</li>
</ul>
<blockquote>
<p>将图片转换为图标,将图标文件 favicon.ico 放到 next/source/ 目录下,然后在 next 配置文件中搜索并修改 facicon 的值为<code>/favicon.ico</code>。</p>
</blockquote>
<ul>
<li>代码高亮主题</li>
</ul>
<blockquote>
<p>Next 有五款使用了Tomorrow Theme的代码高亮主题,在配置文件中修改 highlight_theme 的值即可。文章使用(<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"></div><div class="line">- 开启微信/支付宝打赏功能</div><div class="line"></div><div class="line">> 首先确保 layout/_macro/ 目录下存在 post.swig 和 reward.swig 两个文件,缺少则以utf-8为编码新建这两个文件,并点击[这个地址](https://github.com/iissnan/hexo-theme-next/blob/master/layout/_macro/reward.swig)中的代码复制粘贴到新建的文件中。然后再配置文件中的任意位置添加如下几行代码:</div></pre></td></tr></table></figure></p>
</blockquote>
<h1 id="增加Donate-打赏功能"><a href="#增加Donate-打赏功能" class="headerlink" title="增加Donate 打赏功能"></a>增加Donate 打赏功能</h1><p>alipay: /uploads/alipay.png<br>wechatpay: /uploads/wechatpay.png<br>reward_comment: 坚持原创技术分享,您的支持将鼓励我继续创作!<br>```</p>
<blockquote>
<p>注意事项:微信和支付宝提供的图片格式不一样,尺寸也不同。</p>
<p>上述操作我目前是失败了请求各位道友指点。</p>
</blockquote>
<ul>
<li>订阅微信公众号</li>
</ul>
<blockquote>
<p>Next 5.0.1版本加入该功能,在每篇文章末尾显示公众号二维码。你只需要将公众号二维码 wechat-qcode.jpg 从微信平台下载后放在 source/uploads/ 目录下,然后将配置文件中的 wechat_subscriber 的enable 值设置为 true,qcode 设置为 /uploads/wechat-qcode.jpg,descripion 值设置为 <code>欢迎您扫一扫上面的二维码,关注技术博客最新动态</code>。</p>
</blockquote>
<ul>
<li>用户评论系统</li>
</ul>
<p>></p>
<ul>
<li>自定义导航栏</li>
</ul>
<blockquote>
<p>打开 menu 中的注释再访问网址,你会发现网页提示<code>Cannot GET /categories/</code>,你需要</p>
</blockquote>
<ul>
<li>自定义导航栏之文章分类</li>
</ul>
<p>></p>
<ul>
<li>自定义导航栏之关于博主</li>
</ul>
<p>></p>
<ul>
<li>网站404页面设置</li>
</ul>
<blockquote>
<p>在 /source/ 目录下心间 404.html 页面,内容随你开心填写,建议使用下面腾讯公益404儿童丢失页面:<a href="http://theme-next.iissnan.com/theme-settings.html#volunteer-404" target="_blank" rel="external">http://theme-next.iissnan.com/theme-settings.html#volunteer-404</a></p>
</blockquote>
<ul>
<li>自定义导航栏之标签管理</li>
</ul>
<p>></p>
]]></content>
<tags>
<tag> 技术博客 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[听说PHP中有个东西叫Trait]]></title>
<url>/2017/05/31/%E5%90%AC%E8%AF%B4PHP%E4%B8%AD%E6%9C%89%E4%B8%AA%E4%B8%9C%E8%A5%BF%E5%8F%ABTrait/</url>
<content type="html"><![CDATA[<blockquote>
<p>在Laravel文档中经常出现这个让我郁闷的词汇,在群里问了一下才知道这东西不是laravel所有,而是php内容。于是去php官方文档查看,看的一脸懵逼。想想还是直接借助Google,php trait是什么?</p>
<p>搜索第二条就是安正超大牛的博客,很短,稍微看一下就基本能理解了。<code>trait是php5.4加入的一种用于代码复用的语法</code>,类也用于复用,也就是说这东西和类的作用是相似的,包括书写方式也类似。</p>
</blockquote>
<a id="more"></a>
<ul>
<li><p>据我所知的面向对象语言中只有C++明确支持多继承,那么java,php这些只有单继承的语言怎么办?由于有些类是要实现接口的,java的做法是普通类之间不能多继承,但可以继承多个接口。</p>
</li>
<li><p>php实现这个多继承就是用Trait特征,意思很简单,根据一定的特征把重复的方法放在一个文件,这个文件就叫做一个trait,然后use引入这个Trait就能使用了,可以同时引入多个特征。那么到底根据什么特征来区别呢?这就是Trait复用的思考重点了。</p>
</li>
<li><p>一个类很多乱七八糟的属性和方法,你可以根据价格,根据地区划分出多个Trait,需要的时候随意组合起来使用,和依赖注入的原理非常像,耦合度很低,类似于composer组件化思想。</p>
</li>
<li><p>安大神也认为Trait分类拆分会是大家碰到最头疼的问题,他给出三个拆分技巧:</p>
</li>
</ul>
<figure class="highlight lasso"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">从需求或功能描述拆分,而不是写了两段代码发现代码一样就提到一起;</div><div class="line"></div><div class="line">拆分时可能需要将某些属性也一起带走;</div><div class="line"></div><div class="line">拆分时如果给 <span class="keyword">Trait</span> 起名困难时,请认真思考你是否真的拆分对了。</div><div class="line"></div><div class="line">因为正确的拆分是很容易描述 “它是一个具有什么功能的特性” 的;</div></pre></td></tr></table></figure>
<ul>
<li>参考地址: <a href="http://overtrue.me/articles/2016/04/about-php-trait.html" target="_blank" rel="external">http://overtrue.me/articles/2016/04/about-php-trait.html</a></li>
</ul>
]]></content>
<tags>
<tag> 面向对象 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[ThinkPHP5基础学习]]></title>
<url>/2017/05/30/ThinkPHP5%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0/</url>
<content type="html"><![CDATA[<blockquote>
<p>ThinkPHP是伟大的中国人自己开发的一套php面向对象框架,最新的TP5改进很多方面并专注于钱后端分离的API开发,中文的注释,中文的文档,中文的社区都让中国中小规模的企业不得不选择这个框架。适合人员迭代和快速开发,一套约定的编码规范让团队协作更加清爽,内置的日志和调试器功能强大,直接就能查看到性能分析,支持composer组件化集成。</p>
<p>总之,很强,很有学习的必要!</p>
</blockquote>
<a id="more"></a>
<h3 id="一、获取ThinkPHP"><a href="#一、获取ThinkPHP" class="headerlink" title="一、获取ThinkPHP"></a>一、获取ThinkPHP</h3><ul>
<li><p>获取ThinkPHP的方式很多,<a href="http://thinkphp.cn" target="_blank" rel="external">官方网站</a>是最好的下载和文档获取来源。建议使用composer或者git安装:</p>
<ul>
<li>topthink/thinkphp是3.2版本。</li>
<li>topthink/think是最新thinkphp5。</li>
<li>topthink/framework是核心框架,一般不选择。</li>
</ul>
</li>
<li><p>官网下载版本提供了完整版和核心版两个版本,核心版本只保留了核心类库和必须的文件,去掉了所有的扩展类库和驱动,支持标准模式和SAE模式,一般下载完整版进行开发。</p>
</li>
</ul>
<hr>