脑袋里装的浆糊咩?总是记不住,总是做不对。。。。要说你多少次???

发布新日志

  • 菜鸟学习:LINUX 资源不可用-liux系统参数调优

    2015-03-11 16:57:28

     输入什么命令都提示:
    -bash: fork: Resource temporarily unavailable

    原来是linux系统参数没有调优
    新听到一个名词,文件句柄数。。。我太菜鸟了。。记性差差差
     
    在linux服务器大并发调优时,往往需要预先调优linux参数,其中修改linux最大文件句柄数是最常修改的参数之一。


    在linux中执行ulimit -a 即可查询linux相关的参数,如下所示:
    [root@mongodb11 ~]# ulimit -a
    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 256324
    max locked memory       (kbytes, -l) 64
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 1024
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 10240
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 256324
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited

    默认情况下,linux最大文件句柄数为1024个。当你的服务器在大并发达到极限时,就会报出“too many open files”。
    那么如何修改linux最大文件句柄数呢?其实很简单:
    1、ulimit -n 2048

      这命令就可以修改linux最大文件句柄数,修改以后使用ulimit -a 查看修改的状态,如:
    [root@mongodb11 ~]# ulimit -n 2048
    [root@mongodb11 ~]# ulimit -a
    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 256324
    max locked memory       (kbytes, -l) 64
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 2048
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 10240
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 256324
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited

    但是,这种方法只针对当前进程有效。重新打开一个shell或者开启一个进程,你就会发现参数还是ulimit -n xx修改之前的数字。那么有没有一劳永逸的方法呢?

    当然有!那就是修改系统参数。

    2、修改linux系统参数。vi /etc/security/limits.conf 添加

    *  soft  nofile  65536

    *  hard  nofile  65536

    修改以后保存,注销当前用户,重新登录,执行ulimit -a ,ok ,参数生效了:

    [root@localhost ~]# ulimit -a
    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 256600
    max locked memory       (kbytes, -l) 64
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 65536
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 10240
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 256600
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited

     

    文章转载请注明出处:http://www.cnblogs.com/likehua/p/3831331.html 
  • LINUX 资源不可用-liux系统参数调优

    2015-03-11 16:51:08

     输入什么命令都提示:
    -bash: fork: Resource temporarily unavailable

    原来是linux系统参数没有调优
    新听到一个名词,文件句柄数。。。我太菜鸟了。。记性差差差
     
    在linux服务器大并发调优时,往往需要预先调优linux参数,其中修改linux最大文件句柄数是最常修改的参数之一。

    修改linux最大文件句柄数

    大家知道在linux服务器大并发调优时,往往需要预先调优linux参数,其中修改linux最大文件句柄数是最常修改的参数之一。

    在linux中执行ulimit -a 即可查询linux相关的参数,如下所示:

    [root@mongodb11 ~]# ulimit -a
    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 256324
    max locked memory       (kbytes, -l) 64
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 1024
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 10240
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 256324
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited

    默认情况下,linux最大文件句柄数为1024个。当你的服务器在大并发达到极限时,就会报出“too many open files”。

    那么如何修改linux最大文件句柄数呢?其实很简单:

    1、ulimit -n 2048

      这命令就可以修改linux最大文件句柄数,修改以后使用ulimit -a 查看修改的状态,如:

    [root@mongodb11 ~]# ulimit -n 2048
    [root@mongodb11 ~]# ulimit -a
    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 256324
    max locked memory       (kbytes, -l) 64
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 2048
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 10240
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 256324
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited

    但是,这种方法只针对当前进程有效。重新打开一个shell或者开启一个进程,你就会发现参数还是ulimit -n xx修改之前的数字。那么有没有一劳永逸的方法呢?

    当然有!那就是修改系统参数。

    2、修改linux系统参数。vi /etc/security/limits.conf 添加

    *  soft  nofile  65536

    *  hard  nofile  65536

    修改以后保存,注销当前用户,重新登录,执行ulimit -a ,ok ,参数生效了:

    [root@localhost ~]# ulimit -a
    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 256600
    max locked memory       (kbytes, -l) 64
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 65536
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 10240
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 256600
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited

     

    文章转载请注明出处:http://www.cnblogs.com/likehua/p/3831331.html 
     
  • 存档:软件测试面试题

    2010-07-23 19:35:35

    软件测试面试题分享

    字体:        | 上一篇 下一篇 | 打印  | 我要投稿  | 每周一问,答贴有奖

      1、软件质量的定义是什么?

      2、软件测试的对象包括哪些?

      3、试结合软件开发流程模型,描述对应不同的阶段测试需要哪些工作

      4、单元测试、集成测试、系统测试、验收测试各测试的正确策略含义和被测对象是什么?

      5、单元测试、集成测试、系统测试的侧重点是什么?

      6、alpha测试和Beta测试的定义是什么?并描述Alpha、Beta测试的区别?

      7、白盒和黑盒测试的定义是什么?

      8、软件测试过程中都有哪些工作要做,分别由哪些不同的角色来完成这些任务?

      9、测试计划的目的是什么,测试计划主要包括哪些部分,每一部分主要的内容和作用是什么,其中哪些是最重要?做好测试计划工作的关键是什么?

      10、测试计划的目的是什么?测试计划的内容都包括哪些?其中哪些是最重要的?

      11、什么是测试用例,它由哪些基本元素组成?并举例说明

      12、什么是测试脚本,测试用例与测试脚本两者的关系是什么?

      13、你认为提前做好测试用例有用吗?为什么?

      14、如果业务层和数据层之间有信赖关系,你该怎么写单元测试?

      15、对于产品的用户友好性测试,你认为从哪些方面来测试

      16、bug中需要包括哪些内容并举例说明。如何提高bug记录的质量?

      17、bug管理系统的主要功能是什么,以及在项目中各个角色的使用者是如何使用bug管理系统的?

      18、若你提交了一个bug但开发人员说这不是问题,你该如何处理?

      19、你认为一个测试工作人员最基本的素质是什么?从(能力、责任心)选一个,简答为什么?

      20、怎么认为测试可以结束了?在你以前的工作中,对于分配给你的模块你用什么标准来衡量自己测试完毕了?

    21、你认为一个合格的测试人员应该具备哪些素质?请说明原因

      22、你认为性能测试工作的目的是什么?做好性能测试工作的关键是什么?以前做过性能测试吗?使用哪些工具进行的?

      23、设要对一个自动饮料售货机软件进行黑盒测试,设软件的规格说明如下:

      有一个处理单价为1元5角的盒装饮料的自动售货机软件。若投入1元5角硬币,按下“可乐”“雪碧”或“红茶”按钮,相应的饮料就送出来,若投入2元硬币,在送出饮料的同时退还5角硬币

      (1)、试用因果图法,建立该软件的因果图;

      (2)、设计测试该软件的全部测试用例。

      24、设计最少的测试用例实现条件覆盖:

    if(A>0 and B>0)
    X=X/A;
    if(A>1 or X>1)
    X=X+1;
    System.out.printf("X="+x);

      25、使用你熟练的一种语言,将一个单向链表反转

      26、有两表

      表一 AA

      种类 T  库存总量 S
      A        997
      B       1234

      表二  BB

      种类T   出库数量 S
      A        105
      A        213
      B        115
      B        211
      B        303

      用一条SQL语句求出A、B两类货物库存各剩多少?

      27、下面是一个注册入口,输入用户名和有效的邮箱,点击“立即注册”按钮。你会在输入的邮箱中收到一个注册验证的邮件,该邮件中有一个链接,点击后,就能注册成功。请你考虑应该从哪些测试要点来展开测试?

  • 存档:必须掌握的shell编程

    2010-07-20 20:21:01

    转贴Linux Shell编程(基础教程)

    Linux Shell在线模拟器
    http://www.masswerk.at/jsuix/index.html

    一个在网页上的linux shell模拟器,是可以为那些不熟悉linux 的人们在Microsoft Win环境下练习linux 的一个工具。既不耽误学习,也不耽误正常的工作,哈。


    E w+^Ipl16573151Testing软件测试网x6g3rq'Z$E
    1. Linux 脚本编写基础
    ^1T0CO^_;i1657311.1 语法基本介绍51Testing软件测试网)S4lk a*z YI'b9X/X
    1.1.1 开头51Testing软件测试网 |5}^$ws:i;Im y
           程序必须以下面的行开始(必须放在文件的第一行):51Testing软件测试网](J:a&c j,qH
           #!/bin/sh
    ncC S[u*y5`-O W165731    符号#!用来告诉系统它后面的参数是用来执行该文件的程序。在这个例子中我们使用/bin/sh来执行程序。  当编辑好脚本时,如果要执行该脚本,还必须使其可执行。
    ?WJZ"Q8Y?~165731    要使脚本可执行:   编译 chmod +x filename 这样才能用./filename 来运行51Testing软件测试网 UB%tl-c2H)V"k
    1.1.2 注释51Testing软件测试网S,N%?RF&N7G b
      在进行shell编程时,以#开头的句子表示注释,直到这一行的结束。我们真诚地建议您在程序中使用注释。如果您使用了注释,那么即使相当长的时间内没有使用该脚本,您也能在很短的时间内明白该脚本的作用及工作原理。51Testing软件测试网"uJP/C:?:vI a6nMsI
    1.1.3 变量51Testing软件测试网CB T1H5j r ty
      在其他编程语言中您必须使用变量。在shell编程中,所有的变量都由字符串组成,并且您不需要对变量进行声明。要赋值给一个变量,您可以这样写:
    Z7ZD!C%v[Tt `165731        #!/bin/sh51Testing软件测试网-jB#t0P8CJj
            #对变量赋值:51Testing软件测试网D`*z7o,D X/z
            a="hello world"
    :]g$K~7Ms;ecU165731        # 现在打印变量a的内容:51Testing软件测试网$jd W;OW
            echo "A is:"51Testing软件测试网2x(r5A d"q [ ~i
            echo $a51Testing软件测试网(ap&| {Z
           有时候变量名很容易与其他文字混淆,比如:
    n3gf'|oE#S165731        num=251Testing软件测试网$kfk1AY
            echo "this is the $numnd"
    ;z3_5|6\En165731       这并不会打印出"this is the 2nd",而仅仅打印"this is the ",因为shell会去搜索变量numnd的值,但是这个变量时没有值的。可以使用花括号来告诉shell我们要打印的是num变量:51Testing软件测试网,y!Qs R:H9L/{
            num=251Testing软件测试网CT,^g#y
            echo "this is the ${num}nd"51Testing软件测试网.^ n#P2^;?0q
            这将打印: this is the 2nd51Testing软件测试网8F na^1Rf
    1.1.4 环境变量
    `|%G3oW#Rx)F165731       由export关键字处理过的变量叫做环境变量。我们不对环境变量进行讨论,因为通常情况下仅仅在登录51Testing软件测试网 A0f S;D{;d
    脚本中使用环境变量。51Testing软件测试网\ BM!s;`@
    1.1.5 Shell命令和流程控制
    6? kD$c8\-_5j*K+h165731       在shell脚本中可以使用三类命令:51Testing软件测试网z0jr6SIg$m
           1)Unix 命令:
    8pDQe }8}BC165731      虽然在shell脚本中可以使用任意的unix命令,但是还是由一些相对更常用的命令。这些命令通常是用来进行文件和文字操作的。51Testing软件测试网/m|&@M Q;as
            常用命令语法及功能51Testing软件测试网Q l\5e:SS&kw9y-G
      echo "some text": 将文字内容打印在屏幕上51Testing软件测试网9Qb1I k t
      ls: 文件列表51Testing软件测试网x6JQ E_
      wc –l filewc -w filewc -c file: 计算文件行数计算文件中的单词数计算文件中的字符数51Testing软件测试网"E c}+s%QV?ds&T!f
      cp sourcefile destfile: 文件拷贝
    -t @:lU6V'K n(j.n165731  mv oldname newname : 重命名文件或移动文件
    Fu.nv2^/U8PEi]0p165731  rm file: 删除文件51Testing软件测试网'w5t3c2j+b@ d
      grep 'pattern' file: 在文件内搜索字符串比如:grep 'searchstring' file.txt51Testing软件测试网&o8g Ft8R&}o1j
      cut -b colnum file: 指定欲显示的文件内容范围,并将它们输出到标准输出设备比如:输出每行第5个到第9个字符cut -b5-9 file.txt千万不要和cat命令混淆,这是两个完全不同的命令
    j5zZ HeH#VdbH165731  cat file.txt: 输出文件内容到标准输出设备(屏幕)上51Testing软件测试网)AtC D@S*ZSy^
      file somefile: 得到文件类型
    s b?^Dv O#q1X165731  read var: 提示用户输入,并将输入赋值给变量51Testing软件测试网6`IP8LUk)P#zB
      sort file.txt: 对file.txt文件中的行进行排序51Testing软件测试网)H'U$aX$P+c*R F)WF2T
      uniq: 删除文本文件中出现的行列比如: sort file.txt | uniq51Testing软件测试网!pE0}4u'M|
      expr: 进行数学运算Example: add 2 and 3expr 2 "+" 3
    .N3G9j@&q$f.A165731  find: 搜索文件比如:根据文件名搜索find . -name filename -print
    "]5Z!}xZ3O \165731  tee: 将数据输出到标准输出设备(屏幕) 和文件比如:somecommand | tee outfile51Testing软件测试网9]R$V)ax}
      basename file: 返回不包含路径的文件名比如: basename /bin/tux将返回 tux
    v1zHfI6{)x165731  dirname file: 返回文件所在路径比如:dirname /bin/tux将返回 /bin51Testing软件测试网^G s0cgt)h
      head file: 打印文本文件开头几行
    R/xfC3?7`T165731  tail file : 打印文本文件末尾几行
    fBvQX2Wvf165731  sed: Sed是一个基本的查找替换程序。可以从标准输入(比如命令管道)读入文本,并将结果输出到标准输出(屏幕)。该命令采用正则表达式(见参考)进行搜索。不要和shell中的通配符相混淆。比如:将linuxfocus 替换为LinuxFocus :cat text.file | sed 's/linuxfocus/LinuxFocus/' > newtext.file
    LmFsy1Q165731  awk: awk 用来从文本文件中提取字段。缺省地,字段分割符是空格,可以使用-F指定其他分割符。51Testing软件测试网]Q5h"p C
    cat file.txt | awk -F, '{print $1 "," $3 }'这里我们使用,作为字段分割符,同时打印第一个和第三个字段。如果该文件内容如下: Adam Bor, 34, IndiaKerry Miller, 22, USA
    +a5{F5@4j"b4cX&|:p165731        命令输出结果为:Adam Bor, IndiaKerry Miller, USA
    t]_4| i5}9F165731        2) 概念: 管道, 重定向和 backtick
    I&JS2uJ"L0C @165731  这些不是系统命令,但是他们真的很重要。
    :jT0prMst!\165731  管道 (|) 将一个命令的输出作为另外一个命令的输入。
    Yd w,Z ~ r O165731                 grep "hello" file.txt | wc -l51Testing软件测试网6R G9F#FVMcj P
      在file.txt中搜索包含有”hello”的行并计算其行数。
    ng"V o;B4v,o1Xx165731  在这里grep命令的输出作为wc命令的输入。当然您可以使用多个命令。51Testing软件测试网[Lf]*h;oq
      重定向:将命令的结果输出到文件,而不是标准输出(屏幕)。51Testing软件测试网9N!MH`+Q
          > 写入文件并覆盖旧文件
    _+g0`4fH$h:VJ:[1x165731      >> 加到文件的尾部,保留旧文件内容。
    )aZ2O:PRG3q165731        反短斜线
    1fu8l-DVV+e2TNt165731     使用反短斜线可以将一个命令的输出作为另外一个命令的一个命令行参数。
    j YN#U\&M165731         命令:
    1S4}*k;wg165731           find . -mtime -1 -type f -print51Testing软件测试网.r&qp;Vec)u7x O.AE
         用来查找过去24小时(-mtime –2则表示过去48小时)内修改过的文件。如果您想将所有查找到的文件打一个包,则可以使用以下脚本:
    {[k^ P7C S'N!FY165731             #!/bin/sh
    x+O0L X%Q1Zp#JG165731             # The ticks are backticks (`) not normal quotes ('):
    \@ KL%c$K6vv y/P/X2P165731              tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`51Testing软件测试网(? W\D6h U
           3) 流程控制51Testing软件测试网 TE0ylH\+?-]
            1.if
    "N6Lv,i"S[165731    "if" 表达式 如果条件为真则执行then后面的部分:51Testing软件测试网/gB8a2Vn"zH
                if ....; then51Testing软件测试网 v R3U@.C;{6Ml D
               ....51Testing软件测试网un6\:v3kY&o7{!w
               elif ....; then51Testing软件测试网AF%NW5U
               ....51Testing软件测试网k%X}:KZiQ]G1n
               else
    QK&r6R?Z165731           ....
    jn,cv;j165731           fi51Testing软件测试网wX9P0soF;q
               大多数情况下,可以使用测试命令来对条件进行测试。比如可以比较字符串、判断文件是否存在及是否可读等等…51Testing软件测试网9\$nC D7` G
        通常用" [ ] "来表示条件测试。注意这里的空格很重要。要确保方括号的空格。51Testing软件测试网lxx O/u/Ka
                     [ -f "somefile" ] :判断是否是一个文件51Testing软件测试网4UE0RJ(~0X'|~
                     [ -x "/bin/ls" ] :判断/bin/ls是否存在并有可执行权限51Testing软件测试网-j+O,lmT
                     [ -n "$var" ] :判断$var变量是否有值51Testing软件测试网|j$^ Jv(uiX,g
                     [ "$a" = "$b" ] :判断$a和$b是否相等
    O-bL!a}"J \165731    执行man test可以查看所有测试表达式可以比较和判断的类型。
    "Xq1JZ'ZU%Ft&GM P W165731   直接执行以下脚本:51Testing软件测试网kK6mE+H2|.vK
                   #!/bin/sh
    2G*Qs Uc,Epsfc#t165731               if [ "$SHELL" = "/bin/bash" ]; then
    v.Q*aCTj165731                    echo "your login shell is the bash (bourne again shell)"51Testing软件测试网B!e^ v\+N e4Qq
                   else
    !Wjw5o"cym g]6Jm165731                    echo "your login shell is not bash but $SHELL"51Testing软件测试网 g:wc%ECq C2{$X
                   fi
    Aa1Kx fa L165731   变量$SHELL包含了登录shell的名称,我们和/bin/bash进行了比较。
    /QNplQ z$A ]jt165731        51Testing软件测试网!I1g*G zU0?^'cv
            快捷操作符
    D0}.f;N D.z!e165731        熟悉C语言的朋友可能会很喜欢下面的表达式:51Testing软件测试网#}^9W}v!D
                      [ -f "/etc/shadow" ] && echo "This computer uses shadow passwors"
    j(~{^^s%j165731  这里 && 就是一个快捷操作符,如果左边的表达式为真则执行右边的语句。您也可以认为是逻辑运算中的与操作。上例中表示如果/etc/shadow文件存在则打印” This computer uses shadow passwors”。同样或操作(||)在shell编程中也是可用的。这里有个例子:51Testing软件测试网h*V_B8`ko gS)H
                     #!/bin/sh
    qGp?TZ9m6p%w?165731                 mailfolder=/var/spool/mail/james
    0Q(o%j"~7or165731                 [ -r "$mailfolder" ]' '{ echo "Can not read $mailfolder" ; exit 1; }
    9X'^,HY?165731                 echo "$mailfolder has mail from:"
    F7fn;vksx v;X165731                 grep "^From " $mailfolder51Testing软件测试网9[&ZcS)VVr+W$^H]$B$W
            该脚本首先判断mailfolder是否可读。如果可读则打印该文件中的"From" 一行。如果不可读则或操作生效,打印错误信息后脚本退出。这里有个问题,那就是我们必须有两个命令:51Testing软件测试网3@%J| G!R U
      -打印错误信息51Testing软件测试网v9w/S t/O.Y6G%?Z
      -退出程序
    4j-B*v@9uyO)W165731  我们使用花括号以匿名函数的形式将两个命令放到一起作为一个命令使用。一般函数将在下文提及。51Testing软件测试网x b7Iqm0o(w g
      不用与和或操作符,我们也可以用if表达式作任何事情,但是使用与或操作符会更便利很多。51Testing软件测试网Mycc+T0@#cla C(}
    51Testing软件测试网.Lb[0dZ$_!G
             2.case51Testing软件测试网 UrG5} qS3lv
                   case :表达式可以用来匹配一个给定的字符串,而不是数字。
    6J!?6H5n:q{9c W(`165731                      case ... in
    h h+k0e-J165731                            ...) do something here ;;
    m {xQ{/s v P3m165731                      esac
    L%n]8K5wwLh}165731         让我们看一个例子。 file命令可以辨别出一个给定文件的文件类型,比如:
    &X;[G6P'B165731                     file lf.gz
    hp0PS'Un@165731                   这将返回:51Testing软件测试网 d"A&_1I4o
                             lf.gz: gzip compressed data, deflated, original filename,51Testing软件测试网/H-ikt;qJH/I
                             last modified: Mon Aug 27 23:09:18 2001, os: Unix
    9G-r0F\L Q a6LUF165731             我们利用这一点写了一个叫做smartzip的脚本,该脚本可以自动解压bzip2, gzip 和zip 类型的压缩文件:51Testing软件测试网4o.Yq4y!Z
                   #!/bin/sh
    q^_/o/@kJi)i4y165731               ftype=`file "$1"`
    ;Fo|3Km0hX165731               case "$ftype" in
    5[F*x }$C165731                       "$1: Zip archive"*)
    T } h&v$e-I"{t165731                  unzip "$1" ;;51Testing软件测试网Z\Iiw$]9Lil3Q!}!O
                             "$1: gzip compressed"*)51Testing软件测试网!Kq$@!R&b6rw}
                        gunzip "$1" ;;51Testing软件测试网o;~2bL}8OS
                              "$1: bzip2 compressed"*)51Testing软件测试网x;Dp}suB
                         bunzip2 "$1" ;;
    M8Q9?2? thm(c_d+_5k165731                           *) echo "File $1 can not be uncompressed with smartzip";;51Testing软件测试网MHW1I5}{Rt1n,X
                    esac51Testing软件测试网rZ*{0?@.]
             您可能注意到我们在这里使用了一个特殊的变量$1。该变量包含了传递给该程序的第一个参数值。51Testing软件测试网 O0} U,Rp
    也就是说,当我们运行:51Testing软件测试网"Q#j8w n%|V?V^
                        smartzip articles.zip51Testing软件测试网 m{ F pk g @
                        $1 就是字符串 articles.zip
    .F M~#}gg.yL&c4z!e165731                3. selsect
    M:RD7VoTOnL:h165731                  select 表达式是一种bash的扩展应用,尤其擅长于交互式使用。用户可以从一组不同的值中进行选择。
    K~:o+{ fq z3B165731                    select var in ... ; do
    #U-d]jf5w)W-?w165731                         break
    a'iy/u)G;u"d ^`n165731                            done51Testing软件测试网!dqC.IJp
                                .... now $ var can be used ....
    6Hn#z`lIh6n fa|165731                   下面是一个例子:51Testing软件测试网N%Y4\ I Q#J3ev)Q
                             #!/bin/sh
    K.CF]4v;D F*{7o165731                         echo "What is your favourite OS?"51Testing软件测试网'F,ddZrp7jR
                             select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do
    ^7` c1ygjGF1i)C165731                    break51Testing软件测试网b"a H(b?{ j HG
                                    done51Testing软件测试网X1o] [crq9G}-U
                               echo "You have selected $var"51Testing软件测试网6rU+I @fuqR(P
                  下面是该脚本运行的结果:
    5sC&|HP165731                               What is your favourite OS?
    V1t?Ziwh165731                                    1) Linux51Testing软件测试网6m/r \;x/S(h?,@
                                        2) Gnu Hurd51Testing软件测试网;`&m[;?a,L`
                                        3) Free BSD
    ^5d!q~,~1J)H"bv165731                                    4) Other51Testing软件测试网m?X }+R3_A
                                      #? 1
    :UN-J*^S5@%`k165731                                You have selected Linux51Testing软件测试网%ftS%B-z5y+uG
             注:var是个变量,可以换成其它的值。break用来跳出循环,如果没有break则一直循环下去。done与select对应。
    (m{n(S xZ;kF8B165731                  4.loop51Testing软件测试网u|ea%i
                          loop表达式:
    %JQ\0l GQ165731                            while ...; do
    }\J'lj5q&kag(K!\165731                                      ....51Testing软件测试网{+t'S_;{#Ppa
                                   done51Testing软件测试网/D8}V[X)q
                 while-loop 将运行直到表达式测试为真。will run while the expression that we test for is true.51Testing软件测试网1Rbo)K$U(y9z
    关键字"break" 用来跳出循环。而关键字”continue”用来不执行余下的部分而直接跳到下一个循环。51Testing软件测试网s4e+T4P)C/O
      51Testing软件测试网*Vs1|0} i;u$v~;{)l
                         for-loop表达式查看一个字符串列表 (字符串用空格分隔) 然后将其赋给一个变量:
    9Up}qj wnE0m165731                          1,   for var in ....; do51Testing软件测试网 tio'}})TMi
                                     ....
    At)k x3dY0w165731                                done51Testing软件测试网/oM5f|VC
                           在下面的例子中,将分别打印ABC到屏幕上:51Testing软件测试网{'Kimi)C3Q
                                #!/bin/sh
    H6j/k]&}1z165731                                    for var in A B C ; do51Testing软件测试网~ [ _;o7LK~
                                     echo "var is $var"51Testing软件测试网)m4taT'Bu'y ]Ib
                                         done
    +X)o!hX.i+L16573151Testing软件测试网X:{Z,e;U
                               2,   for (( 条件一; 条件二; 条件三 );do
    /\f'n9W7mdM165731                                ...
    -q8W [0aj165731                                done
    :uiZ:Z9i(tg}\165731                        例:
    #] EO{#r$a:j H165731                     51Testing软件测试网5d$b qW6q6tr
                       for ((i=1;i<10;i=$[$i+1]));do51Testing软件测试网Hkj&}+c

    _*M4m@ K9Zz165731                             echo "a"
    g%_)W m4u YH9q{165731                          done51Testing软件测试网8P'n%i9f |ijK
    输出:
    $n1X,_+U*Er cn165731
    OH_8mi5M-P E v?165731a
    ~M[F q/\165731a
    ;T7sp8P1IWV/F&_165731a
    "K*^;^:OW4jvX165731a
    v3E[r/f.[s(~6f165731a
    9jW/V+o/X165731a51Testing软件测试网/rt+](| W m(PU-m'S
    a
    4]`h@9Y0o165731a51Testing软件测试网 iRi:`,oQ-h
    a51Testing软件测试网]i*e~8q3U*YR

    $_'Bn;L0\2sa1g R165731条件一:这可以看成是『初始值』,如上面的例子中,初始值是 i=1 啦!51Testing软件测试网HpOK F!YVE|"tp
    条件二:这可以看成是『符合值』,如上面的例子中,当 i<=100 的时候都是符合条件的!
    gt5hO1c#w.wB165731条件三:这可以看成是『步阶』!也就是说, i 每次都加一! 所以啦!上面的例子是说:由 i=1 开始到 i<= 100 ,每次 i 都加一来执行底下的程序段(就是 s=s+i ),当 i >100 (也就是 i=101 )就跳出这一段程序段!怎样!不难吧!51Testing软件测试网8y%CvN9gJ
    51Testing软件测试网.aXwaoA Z0uX5b4h
    51Testing软件测试网9L&C T F8hCG0Z1O*e

    $l$U-M:hBi:J;s1s |165731
    2Mf@fA:Q165731                        下面是一个更为有用的脚本showrpm,其功能是打印一些RPM包的统计信息:51Testing软件测试网yeUp/s:E8_*j*g9YAc
                              #!/bin/sh51Testing软件测试网bh;IQ,Y`$P'|-G&g t
                              # list a content summary of a number of RPM packages
    OC]l rS`g165731                          # USAGE: showrpm rpmfile1 rpmfile2 ...51Testing软件测试网 E2T f$M N'v\/v:r"a'u
                              # EXAMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm
    M [_kG1q [.gYE-D165731                            for rpmpackage in $*; do51Testing软件测试网!P3?/f*[|z ?*R
                             if [ -r "$rpmpackage" ];then
    )R/\_~7G4t5{k165731                         echo "=============== $rpmpackage =============="
    Z T;V)\ mA165731                          rpm -qi -p $rpmpackage
    }nfV U!k165731                          else51Testing软件测试网sNp9LY+x;ug.B^
                               echo "ERROR: cannot read file $rpmpackage"51Testing软件测试网 YY u'~%bm$\3A
                             fi51Testing软件测试网f$nd*n5se3`.j
                                  done51Testing软件测试网H,Ev,`.v2^
                       这里出现了第二个特殊的变量$*,该变量包含了所有输入的命令行参数值。
    2y.h0v%_L}165731                        如果您运行showrpm openssh.rpm w3m.rpm webgrep.rpm
    .vqJ'wpbLMd"N165731                                   此时 $* 包含了 3 个字符串,即openssh.rpm, w3m.rpm and webgrep.rpm.
    `/^(SJ;cIB.L9X165731
    j&o n {5rfU6y/@Q16573151Testing软件测试网/L4h[V&^d:Ybv#\3hG

    .lk u(bHzo0c.g165731『until:直到条件相同的时候才离开程序』;51Testing软件测试网8T1g8_6Z5bc"\6v5Li
    『while:当条件相同的时候,就继续做!』  51Testing软件测试网%Pf)la[ {V/S

    yov~i,f ?165731until [ condition1 ] && { || } [ condition2 ] ...
    u4R1p5K4]B6u165731
    L w,o p zF0G'[165731
    %{-qKcdI(\16573151Testing软件测试网 CbCa9@
    51Testing软件测试网p4LZ%p"z+J3H
                     5. 引号
    U3[0[[kK T165731                   在向程序传递任何参数之前,程序会扩展通配符和变量。这里所谓扩展的意思是程序会把通配符(比如*)替换成合适的文件名,它变量替换成变量值。为了防止程序作这种替换,您可以使用引号:让我们来看一个例子,假设在当前目录下有一些文件,两个jpg文件, mail.jpg 和tux.jpg。51Testing软件测试网)J _D]%cS"J#w&l
              编译SHELL脚本
    J {bRK`*? qT165731          #ch#!/bin/sh mod +x filename51Testing软件测试网J-G6[3z8i7x
     cho *.jpg       ./filename 来执行您的脚本。51Testing软件测试网j.r:fi l+NV.I.X;{
      这将打印出"mail.jpg tux.jpg"的结果。
    G'a3_y-E-\},vE{C165731    引号 (单引号和双引号) 将防止这种通配符扩展:
    'e7UW#U\3e/Yuh&X165731             #!/bin/sh
    nu2jT I"hz9g165731             echo "*.jpg"51Testing软件测试网&?T.{? @4[H-iN ]
                 echo '*.jpg'51Testing软件测试网LK{sk,g*^
      这将打印"*.jpg" 两次。
    K^S*l9Hz;Lm%?165731  单引号更严格一些。它可以防止任何变量扩展。双引号可以防止通配符扩展但允许变量扩展。51Testing软件测试网Ytsv-K
             #!/bin/sh
    zg#Vf"mLA0S6yu165731         echo $SHELL
    $A.|1B:M6j8i'EC9?o:_165731         echo "$SHELL"51Testing软件测试网cBV%E~
             echo '$SHELL'51Testing软件测试网RJ(P!{ E}c
       运行结果为:51Testing软件测试网(S$c ^W O)v?
                 /bin/bash51Testing软件测试网|;p!FK-g(_"K4r| D
                 /bin/bash
    6c,U(P1?p165731             $SHELL51Testing软件测试网M8oP:ukC
      最后,还有一种防止这种扩展的方法,那就是使用转义字符——反斜杆:
    j_LG^8l5h!`"Ru165731           echo *.jpg
    xL6r%z.Xf165731           echo $SHELL
    !E6Q5lHX*H|165731  这将输出:
    #x5i J K0}165731           *.jpg51Testing软件测试网s!M&U j&d
               $SHELL
    cjy?/Ju.s}N165731         6. Here documents
    :_^f.J/mm/[165731          当要将几行文字传递给一个命令时,here documents(译者注:目前还没有见到过对该词适合的翻译)一种不错的方法。对每个脚本写一段帮助性的文字是很有用的,此时如果我们四有那个 here documents就不必用echo函数一行行输出。 一个 "Here document" 以 << 开头,后面接上一个字符串,这个字符串还必须出现在here document的末尾。下面是一个例子,在该例子中,我们对多个文件进行重命名,并且使用here documents打印帮助:
    :L~1bJ3MN165731         #!/bin/sh
    3c^0Z(k!N9d4c165731         # we have less than 3 arguments. Print the help text:
    |k `!R G165731            if [ $# -lt 3 ] ; then51Testing软件测试网G+B vf8E8\
                     cat <51Testing软件测试网z'}#ed/|4d;]giW
                     ren -- renames a number of files using sed regular expressions51Testing软件测试网vPD"Y*Y'e
                     USAGE: ren 'regexp' 'replacement' files...51Testing软件测试网H0Z+h.J5K
                     EXAMPLE: rename all *.HTM files in *.html:51Testing软件测试网 J#@|;n\W9V
                  ren 'HTM$' 'html' *.HTM51Testing软件测试网3`V-NJoVgw
                     HELP51Testing软件测试网J`7j M0i5o'j
                  exit 051Testing软件测试网)T'd$_*u-nf*S.uS
                fi
    "Ax_ pry KXl165731            OLD="$1"
    &V$CD#I1trwZM165731            NEW="$2"51Testing软件测试网Go4qt(})Y)a2Rq7g
              # The shift command removes one argument from the list of
    yQ#JY v%d[5l165731          # command line arguments.
    X6\1m4pL8U\4W165731          shift
    TWfg"r165731          shift
    .X`;`Yuz$D%N165731          # $* contains now all the files:
    JuQ0bNx|165731         for file in $*; do
    +s6OV-u/r`X%h(W l165731          if [ -f "$file" ] ; then51Testing软件测试网9uU5A,P+d1M7V"N
                 newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"`
    o\:t6R%gl H4z165731             if [ -f "$newfile" ]; then
    Q(LX)dK+u165731                  echo "ERROR: $newfile exists already"
    ft%Fn Hb@165731             else
    B4ZYxP`l165731                  echo "renaming $file to $newfile ..."
    4J1l P8yKs165731                  mv "$file" "$newfile"
    5s5pK4VvZ165731              fi
    m']b(Q%P!p8Q~i165731            fi
    K"Dp {/p[165731           done
    [WR6|!h%eq#]i4zh7K165731        这是一个复杂一些的例子。让我们详细讨论一下。第一个if表达式判断输入命令行参数是否小于3个 (特殊变量$# 表示包含参数的个数) 。如果输入参数小于3个,则将帮助文字传递给cat命令,然后由cat命令将其打印在屏幕上。打印帮助文字后程序退出。如果输入参数等于或大于3个,我们就将第一个参数赋值给变量OLD,第二个参数赋值给变量NEW。下一步,我们使用shift命令将第一个和第二个参数从参数列表中删除,这样原来的第三个参数就成为参数列表$*的第一个参数。然后我们开始循环,命令行参数列表被一个接一个地被赋值给变量$file。接着我们判断该文件是否存在,如果存在则通过sed命令搜索和替换来产生新的文件名。然后将反短斜线内命令结果赋值给newfile。这样我们就达到了我们的目的:得到了旧文件名和新
    &J I'[D1S165731文件名。然后使用mv命令进行重命名。51Testing软件测试网P4|;U"Md
              4)函数
    #MN }"KQ'L165731             如果您写了一些稍微复杂一些的程序,您就会发现在程序中可能在几个地方使用了相同的代码,并且您也会发现,如果我们使用了函数,会方便很多。一个函数是这个样子的:51Testing软件测试网*@~9L o,T K
              functionname()
    p:y7i%k1yB \O165731          {51Testing软件测试网,l+N}xI7?0@!\Y5A{
                     # inside the body $1 is the first argument given to the function
    3Fae j-F165731                 # $2 the second ...
    .dNf7@/z8L(J&sC&t165731                             body51Testing软件测试网]r2B:O~ o1y
                }
    Qs6`j @v(a165731          您需要在每个程序的开始对函数进行声明。
    gRK'SII2z C165731   下面是一个叫做xtitlebar的脚本,使用这个脚本您可以改变终端窗口的名称。
    )I^ [AY%x165731           这里使用了一个叫做help的函数。正如您可以看到的那样,这个定义的函数被使用了两次。
    ;yI q8` Or1B]k165731               #!/bin/sh51Testing软件测试网P X"M9dI(u\
                   # vim: set sw=4 ts=4 et:
    v ?@?r:]8g@165731               help()51Testing软件测试网g*H4Dh g6T|
                   {
    t3{pdl~S X~b,p165731              cat <51Testing软件测试网t.V}6C {$^:^} QV$Z
                         xtitlebar -- change the name of an xterm, gnome-terminal or kde konsole
    G2z)?%qg165731                     USAGE: xtitlebar [-h] "string_for_titelbar"51Testing软件测试网6_N,}2j:W,Wg
                          OPTIONS: -h help text51Testing软件测试网9Q t;_e6W8wQ)~
                         EXAMPLE: xtitlebar "cvs"
    e V:w"GQ;\fp Z0z(yyhF165731                     HELP
    M;hc;kCB['ap-W165731             exit 0
    S'\U] ZpA165731               }51Testing软件测试网d,h'K0b eq#S4S0|n3o6{
                   # in case of error or if -h is given we call the function help:
    -UUBks165731               [ -z "$1" ] && help51Testing软件测试网&hcF[$xZ9_q
                   [ "$1" = "-h" ] && help
    4e _:Nsx1W+^m H J165731               # send the escape sequence to change the xterm titelbar:
    YY.PesO6^165731                 echo -e "33]0;$107"51Testing软件测试网l} z"W&R`nA
                    #51Testing软件测试网:s Nm"pV+s['n
                在脚本中提供帮助是一种很好的编程习惯,这样方便其他用户(和您)使用和理解脚本。51Testing软件测试网Z4_1w,VU
            命令行参数51Testing软件测试网G C;^A7Jf:[a
      我们已经见过$* 和 $1, $2 ... $9 等特殊变量,这些特殊变量包含了用户从命令行输入的参数。迄今为止,我们仅仅了解了一些简单的命令行语法(比如一些强制性的参数和查看帮助的-h选项)。但是在编写更复杂的程序时,您可能会发现您需要更多的自定义的选项。通常的惯例是在所有可选的参数之前加一个减号,后面再加上参数值 (比如文件名)。有好多方法可以实现对输入参数的分析,但是下面的使用case表达式的例子无遗是一个不错的方法。51Testing软件测试网Q];M2F O#HJ(z(j0P
             #!/bin/sh51Testing软件测试网?Gn7iOL"{ h z
             help()51Testing软件测试网 \$i0UcZ0bPE
             {
    1I/A vB(Q7A9f165731            cat <51Testing软件测试网ds{)S_y.H
                   This is a generic command line parser demo.
    lyNmgp165731               USAGE EXAMPLE: cmdparser -l hello -f -- -somefile1 somefile251Testing软件测试网,J"X]x+S.y"u%_(D3g
                   HELP
    VK%r M c"Qs165731            exit 051Testing软件测试网PO,oBz"_:^
             }51Testing软件测试网.SF1c c6d6M\ C
              while [ -n "$1" ]; do
    n da"G}l/M165731        case $1 in51Testing软件测试网#nOy|1kq+H
           -h) help;shift 1;; # function help is called51Testing软件测试网n_)lzV~*LC@a1s$]
           -f) opt_f=1;shift 1;; # variable opt_f is set51Testing软件测试网7NXA"l m b
            -l) opt_l=$2;shift 2;; # -l takes an argument -> shift by 251Testing软件测试网Q"h5Wy4G
            --) shift;break;; # end of options
    7i-F-rUS8|-Y*H165731       -*) echo "error: no such option $1. -h for help";exit 1;;
    @.G$VD[;H7T165731       *) break;;51Testing软件测试网;v$D7[.M0d`'y%r!j
              esac
    3uDIV[y165731          done
    i}wAa-s"y&[K8I165731          echo "opt_f is $opt_f"
    p_ g$Y*z9U#_W U165731          echo "opt_l is $opt_l"51Testing软件测试网hC } Z8jG:b6G e
              echo "first arg is $1"51Testing软件测试网 n T sw:pb4f2rG
              echo "2nd arg is $2"51Testing软件测试网*PK0m2`1f([-I#@Ku
      您可以这样运行该脚本:51Testing软件测试网9U2l_Y#W!gf9wT-}
                     cmdparser -l hello -f -- -somefile1 somefile2
    &B@we4T165731  返回的结果是:51Testing软件测试网p'|9Xji6N
                 opt_f is 151Testing软件测试网T H8iV.]*FU
                 opt_l is hello51Testing软件测试网 Uq[ KM,u.X
                 first arg is -somefile151Testing软件测试网9]5E/x_ z+lK
                 2nd arg is somefile2
    \$g2}5_*BGuj165731  这个脚本是如何工作的呢?脚本首先在所有输入命令行参数中进行循环,将输入参数与case表达式进行比较,如果匹配则设置一个变量并且移除该参数。根据unix系统的惯例,首先输入的应该是包含减号的参数.51Testing软件测试网$T h6{.?i N9keJ
    51Testing软件测试网o _:dDug8R.q

    E,yb5N tp`-e&WT165731第2部分 实例51Testing软件测试网^k-l^;r|d0J

    MXp,[;IC/@[b165731    现在我们来讨论编写一个脚本的一般步骤。任何优秀的脚本都应该具有帮助和输入参数。并且写一个伪脚本(framework.sh),该脚本包含了大多数脚本都需要的框架结构,是一个非常不错的主意。这时候,在写一个新的脚本时我们只需要执行一下copy命令:
    LK!f@r8Y&CA|h165731cp framework.sh myscript.
    FI Un#[,O_165731 然后再插入自己的函数。51Testing软件测试网$]eO@#_|M
      让我们再看两个例子:
    &ew \s!He-U$ik.a5YAb165731  二进制到十进制的转换
    5t F"g_Rz9Gx165731  脚本 b2d 将二进制数 (比如 1101) 转换为相应的十进制数。这也是一个用expr命令进行数学运算的例子:51Testing软件测试网j)? e` A Z
    #!/bin/sh
    |1u @$G.V ^t165731# vim: set sw=4 ts=4 et:
    ;V}!}p5J*A-Fco165731help()51Testing软件测试网 Y7zf3PQPjO
    {51Testing软件测试网|2o.d DTn
     cat <
    -mO'uJazi&VMd165731b2h -- convert binary to decimal
    ]k:b$~h165731USAGE: b2h [-h] binarynum51Testing软件测试网8u$rcx }B
    OPTIONS: -h help text
    %s{G-F'U*p I1Y8M165731EXAMPLE: b2h 11101051Testing软件测试网J5}6R%BR1xiz
    will return 5851Testing软件测试网S4~.uu#] zW
    HELP
    3a*OD'{Y(~8C"eXZ165731 exit 0
    0HL*n'@RNlE_Z\165731}
    2Zu2^3Emhe165731error()
    A w!O4n0br'TX165731{51Testing软件测试网 `la$O.rzHY
      # print an error and exit
    aM5O+USSLzB S165731  echo "$1"
    5Ir't5T9O.t4N8P8j165731  exit 1
    6@`;lq*N4c"AE165731}51Testing软件测试网;gI&rY\&Y}
    lastchar()51Testing软件测试网$Hf`Q7N
    {51Testing软件测试网5G%Q?7X+bD"x
      # return the last character of a string in $rval51Testing软件测试网DlA4p+Z8a9HC s[2]D
      if [ -z "$1" ]; then51Testing软件测试网 U/\g2V8J~5Aa E9C
        # empty string51Testing软件测试网mM(n AZG
        rval=""51Testing软件测试网V5S {y;S
        return51Testing软件测试网 vk*WL ]S9f'r R
      fi51Testing软件测试网2XYE@8{2Gx
      # wc puts some space behind the output this is why we need sed:51Testing软件测试网;`GN(nr(ev
      numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
    7_'U9O,B5Wh.t ]]'u165731  # now cut out the last char51Testing软件测试网 Z&Y.R]p$s7P}%O;eI'C
      rval=`echo -n "$1" | cut -b $numofchar`
    ;S1r-f_/N;z&w165731}51Testing软件测试网bZd4m9e
    chop()51Testing软件测试网*l2H$O-f }?_"Zr9N9Z`
    {51Testing软件测试网p)R1Z%NLfY ac`U
      # remove the last character in string and return it in $rval51Testing软件测试网FN+``ga0[FI
      if [ -z "$1" ]; then51Testing软件测试网 |qInc.WP-KX
        # empty string
    EL j+?d165731    rval=""
    (kcCAJG%C_GF165731    return51Testing软件测试网 M,SH8C'`8h|
      fi
    n V/s l,o9O165731  # wc puts some space behind the output this is why we need sed:51Testing软件测试网m'c&Di^ sZ2w1k_
      numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
    3Y r/t-E K VgO)f.h165731  if [ "$numofchar" = "1" ]; then
    F/_!}u)hk#p165731    # only one char in string
    @%Wd'p9g}165731    rval=""51Testing软件测试网a+y La VP
        return
    )^.I:_ Yo165731  fi51Testing软件测试网g`MY)bV;{
      numofcharminus1=`expr $numofchar "-" 1`
    5q1s o7C0J O,?~ n165731  # now cut all but the last char:51Testing软件测试网a kMxXu:g g$V!e!f
      rval=`echo -n "$1" | cut -b 0-${numofcharminus1}`51Testing软件测试网?0y-W"zQMb
    }
    d-nb{ ^6l5A165731while [ -n "$1" ]; do
    6K/Kt g iQc zk*Q165731case $1 in51Testing软件测试网9~:ZG|~;t*dJ
      -h) help;shift 1;; # function help is called51Testing软件测试网z7^ d;y g-bz[xw
      --) shift;break;; # end of options
    G'Q%IZ@)T&}Sb(m165731  -*) error "error: no such option $1. -h for help";;
    NU`wUoT T,T165731  *) break;;
    (Q7{nKzfmJ165731esac51Testing软件测试网5aY%G%\s:t
    done51Testing软件测试网g9yua4`D.\
    # The main program
    $ER*W|C ?'H*o&j165731sum=051Testing软件测试网'YL!k8["W(u~
    weight=151Testing软件测试网cl+V"w V*rk
    # one arg must be given:51Testing软件测试网%k_7mEd.yv(m
    [ -z "$1" ] && help51Testing软件测试网 T,|A,e5E%Vkq\[
    binnum="$1"
    F)_e3_ J ?165731binnumorig="$1"51Testing软件测试网ZmX8o|j C
    while [ -n "$binnum" ]; do51Testing软件测试网2K Hs/P0O9u+xK,F
      lastchar "$binnum"
    /h VU:L{`K165731  if [ "$rval" = "1" ]; then51Testing软件测试网L'BL9A,K;A?%R%W
        sum=`expr "$weight" "+" "$sum"`
    _I _?4d~A165731  fi51Testing软件测试网*h6aJE%}k
      # remove the last position in $binnum
    w'~^ N*l4H165731  chop "$binnum"51Testing软件测试网+lmr`Yj:w
      binnum="$rval"
    1p&t0paQ165731  weight=`expr "$weight" "*" 2`
    w-nGrm_l1J165731done
    7{3_0c-m#C |.j0m165731echo "binary $binnumorig is decimal $sum"
    d b N?gJs9c165731   该脚本使用的算法是利用十进制和二进制数权值 (1,2,4,8,16,..),比如二进制"10"可以这样转换成十进制:51Testing软件测试网6SNN$@XjU#Ni
    0 * 1 + 1 * 2 = 2
    s0b(A"P |'J9
  • 存档:总是做不对的C题目

    2010-07-20 15:14:39

    C语言面试题大汇总<1>
     

    .    static有什么用途?(请至少说明两种)
    1.限制变量的作用域
    2.设置变量的存储域
    7.    引用与指针有什么区别?
    1) 引用必须被初始化,指针不必。
    2) 引用初始化以后不能被改变,指针可以改变所指的对象。
    2) 不存在指向空值的引用,但是存在指向空值的指针。
    8.    描述实时系统的基本特性
    在特定时间内完成特定的任务,实时性与可靠性
    9.    全局变量和局部变量在内存中是否有区别?如果有,是什么区别?
    全局变量储存在静态数据库,局部变量在堆栈
    10.   什么是平衡二叉树?
    左右子树都是平衡二叉树 且左右子树的深度差值的绝对值不大于1
    11.   堆栈溢出一般是由什么原因导致的?
    没有回收垃圾资源
    12.   什么函数不能声明为虚函数?
    constructor
    13.   冒泡排序算法的时间复杂度是什么?
    O(n^2)
    14.   写出float x 与“零值”比较的if语句。
    if(x>0.000001&&x<-0.000001)
    16.   Internet采用哪种网络协议?该协议的主要层次结构?
    tcp/ip 应用层/传输层/网络层/数据链路层/物理层
    17.   Internet物理地址和IP地址转换采用什么协议?
    ARP (Address Resolution Protocol)(地址解析協議)
    18.IP地址的编码分为哪俩部分?
    IP地址由两部分组成,网络号和主机号。不过是要和“子网掩码”按位与上之后才能区分哪些是网络位哪些是主机位。

    2.用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。写出C程序。
    循环链表,用取余操作做
    3.不能做switch()的参数类型是:
    switch的参数不能为实型。
    華為
    1、局部变量能否和全局变量重名?
    答:能,局部会屏蔽全局。要用全局变量,需要使用"::"
    局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内
    2、如何引用一个已经定义过的全局变量?
    答:extern
    可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个变写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错
    3、全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
    答:可以,在不同的C文件中以static形式来声明同名全局变量。
    可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错
    4、语句for( ;1 ;)有什么问题?它是什么意思?
    答:和while(1)相同。
    5、do……while和while……do有什么区别?
    答:前一个循环一遍再判断,后一个判断以后再循环
    6、请写出下列代码的输出内容
    #include<stdio.h>
    main()
    {
    int a,b,c,d;
    a=10;
    b=a++;
    c=++a;
    d=10*a++;
    printf("b,c,d:%d,%d,%d",b,c,d);
    return 0;
    }
    答:10,12,120
    1、static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
    全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用, 因此可以避免在其它源文件中引起错误。
    从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。
    static函数与普通函数作用域不同。仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件
    static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用;
    static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;
    static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
    2、程序的局部变量存在于(堆栈)中,全局变量存在于(静态区 )中,动态申请数据存在于( 堆)中。
    3、设有以下说明和定义:
    typedef union {long i; int k[5]; char c;} DATE;
    struct data { int cat; DATE cow; double dog;} too;
    DATE max;
    则语句 printf("%d",sizeof(struct date)+sizeof(max));的执行结果是:___52____
    答:DATE是一个union, 变量公用空间. 里面最大的变量类型是int[5], 占用20个字节. 所以它的大小是20
    data是一个struct, 每个变量分开占用空间. 依次为int4 + DATE20 + double8 = 32.
    所以结果是 20 + 32 = 52.
    当然...在某些16位编辑器下, int可能是2字节,那么结果是 int2 + DATE10 + double8 = 20
    4、队列和栈有什么区别?
    队列先进先出,栈后进先出
     
    5、写出下列代码的输出内容
    #include<stdio.h>
    int inc(int a)
    {
    return(++a);
    }
    int multi(int*a,int*b,int*c)
    {
    return(*c=*a**b);
    }
    typedef int(FUNC1)(int in);
    typedef int(FUNC2) (int*,int*,int*);
    void show(FUNC2 fun,int arg1, int*arg2)
    {
    INCp=&inc;
    int temp =p(arg1);
    fun(&temp,&arg1, arg2);
    printf("%d\n",*arg2);
    }
    main()
    {
    int a;
    show(multi,10,&a);
    return 0;
    }
    答:110
    7、请找出下面代码中的所以错误
    说明:以下代码是把一个字符串倒序,如“abcd”倒序后变为“dcba”
    1、#include"string.h"
    2、main()
    3、{
    4、 char*src="hello,world";
    5、 char* dest=NULL;
    6、 int len=strlen(src);
    7、 dest=(char*)malloc(len);
    8、 char* d=dest;
    9、 char* s=src[len];
    10、 while(len--!=0)
    11、 d++=s--;
    12、 printf("%s",dest);
    13、 return 0;
    14、}
    答:
    方法1:
    int main(){
    char* src = "hello,world";
    int len = strlen(src);
    char* dest = (char*)malloc(len+1);//要为\0分配一个空间
    char* d = dest;
    char* s = &src[len-1];//指向最后一个字符
    while( len-- != 0 )
    *d++=*s--;
    *d = 0;//尾部要加\0
    printf("%s\n",dest);
    free(dest);// 使用完,应当释放空间,以免造成内存汇泄露
    return 0;
    }
    方法2:
    #include <stdio.h>
    #include <string.h>
    main()
    {
    char str[]="hello,world";
    int len=strlen(str);
    char t;
    for(int i=0; i<len/2; i++)
    {
    t=str[i];
    str[i]=str[len-i-1]; str[len-i-1]=t;
    }
    printf("%s",str);
    return 0;
    }
    1.-1,2,7,28,,126请问28和126中间那个数是什么?为什么?
    第一题的答案应该是4^3-1=63
    规律是n^3-1(当n为偶数0,2,4)
          n^3+1(当n为奇数1,3,5)
    答案:63
    2.用两个栈实现一个队列的功能?要求给出算法和思路!
    设2个栈为A,B, 一开始均为空.
    入队:
    将新元素push入栈A;
    出队:
    (1)判断栈B是否为空;
    (2)如果不为空,则将栈A中所有元素依次pop出并push到栈B;
    (3)将栈B的栈顶元素pop出;
    这样实现的队列入队和出队的平摊复杂度都还是O(1), 比上面的几种方法要好。3.在c语言库函数中将一个字符转换成整型的函数是atool()吗,这个函数的原型是什么?
    函数名: atol
    功 能: 把字符串转换成长整型数
    用 法: long atol(const char *nptr);
    程序例:
    #include <stdlib.h>
    #include <stdio.h>
    int main(void)
    {
    long l;
    char *str = "98765432";
    l = atol(lstr);
    printf("string = %s integer = %ld\n", str, l);
    return(0);
    }
     
     
     
    2.对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?
    c用宏定义,c++用inline
      3.直接链接两个信令点的一组链路称作什么?
    PPP点到点连接
      4.接入网用的是什么接口?
      5.voip都用了那些协议?
      6.软件测试都有那些种类?
    黑盒:针对系统功能的测试    白合:测试函数功能,各函数接口
      7.确定模块的功能和模块的接口是在软件设计的那个队段完成的?
    概要设计阶段
      8.enum string
        {
        x1,
        x2,
        x3=10,
        x4,
        x5,
        }x;
       问x= 0x801005,0x8010f4  ;
      9.unsigned char *p1;
        unsigned long *p2;
        p1=(unsigned char *)0x801000;
        p2=(unsigned long *)0x810000;
        请问p1+5=  ;
            p2+5=  ;
    三.选择题:
      1.Ethternet链接到Internet用到以下那个协议?
      A.HDLC;B.ARP;C.UDP;D.TCP;E.ID
      2.属于网络层协议的是:
      A.TCP;B.IP;C.ICMP;D.X.25
      3.Windows消息调度机制是:
      A.指令队列;B.指令堆栈;C.消息队列;D.消息堆栈;
      4.unsigned short hash(unsigned short key)
        {
          return (key>>)%256
        }
       请问hash(16),hash(256)的值分别是:
      A.1.16;B.8.32;C.4.16;D.1.32
    四.找错题:
      1.请问下面程序有什么错误?
       int a[60][250][1000],i,j,k;
       for(k=0;k<=1000;k++)
        for(j=0;j<250;j++)
         for(i=0;i<60;i++)
          a[i][j][k]=0;
    把循环语句内外换一下
      2.#define Max_CB 500
        void LmiQueryCSmd(Struct MSgCB * pmsg)
         {
         unsigned char ucCmdNum;
         ......
       
         for(ucCmdNum=0;ucCmdNum<Max_CB;ucCmdNum++)
          {
          ......;
          }
    死循环
       3.以下是求一个数的平方的程序,请找出错误:
        #define SQUARE(a)((a)*(a))
        int a=5;
        int b;
        b=SQUARE(a++);
       4.typedef unsigned char BYTE
         int examply_fun(BYTE gt_len; BYTE *gt_code)
          { 
          BYTE *gt_buf;
          gt_buf=(BYTE *)MALLOC(Max_GT_Length);
          ......
          if(gt_len>Max_GT_Length)
            {
            return GT_Length_ERROR; 
            }
            .......
          }
    五.问答题:
       1.IP Phone的原理是什么?
    IPV6
       2.TCP/IP通信建立的过程怎样,端口有什么作用?
    三次握手,确定是哪个应用程序使用该协议
       3.1号信令和7号信令有什么区别,我国某前广泛使用的是那一种?
       4.列举5种以上的电话新业务?
    微软亚洲技术中心的面试题!!!
    1.进程和线程的差别。
    线程是指进程内的一个执行单元,也是进程内的可调度实体.
    与进程的区别:
    (1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位
    (2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行
    (3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源.
    (4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。
    2.测试方法
    人工测试:个人复查、抽查和会审
    机器测试:黑盒测试和白盒测试
    2.Heap与stack的差别。
    Heap是堆,stack是栈。
    Stack的空间由操作系统自动分配/释放,Heap上的空间手动分配/释放。
    Stack空间有限,Heap是很大的自由存储区
    C中的malloc函数分配的内存空间即在堆上,C++中对应的是new操作符。
    程序在编译期对变量和函数分配内存都在栈上进行,且程序运行过程中函数调用时参数的传递也在栈上进行
    3.Windows下的内存是如何管理的?
    4.介绍.Net和.Net的安全性。
    5.客户端如何访问.Net组件实现Web Service?
    6.C/C++编译器中虚表是如何完成的?
    7.谈谈COM的线程模型。然后讨论进程内/外组件的差别。
    8.谈谈IA32下的分页机制
    小页(4K)两级分页模式,大页(4M)一级
    9.给两个变量,如何找出一个带环单链表中是什么地方出现环的?
    一个递增一,一个递增二,他们指向同一个接点时就是环出现的地方
    10.在IA32中一共有多少种办法从用户态跳到内核态?
    通过调用门,从ring3到ring0,中断从ring3到ring0,进入vm86等等
    11.如果只想让程序有一个实例运行,不能运行两个。像winamp一样,只能开一个窗口,怎样实现?
    用内存映射或全局原子(互斥变量)、查找窗口句柄..
    FindWindow,互斥,写标志到文件或注册表,共享内存。.  
    12.如何截取键盘的响应,让所有的'a’变成'b’?
    键盘钩子SetWindowsHookEx
     13.Apartment在COM中有什么用?为什么要引入?
     14.存储过程是什么?有什么用?有什么优点?
    我的理解就是一堆sql的集合,可以建立非常复杂的查询,编译运行,所以运行一次后,以后再运行速度比单独执行SQL快很多
     15.Template有什么特点?什么时候用?
    16.谈谈Windows DNA结构的特点和优点。

    网络编程中设计并发服务器,使用多进程 与 多线程 ,请问有什么区别?
    1,进程:子进程是父进程的复制品。子进程获得父进程数据空间、堆和栈的复制品。
    2,线程:相对与进程而言,线程是一个更加接近与执行体的概念,它可以与同进程的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
    两者都可以提高程序的并发度,提高程序运行效率和响应时间。
    线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源管理和保护;而进程正相反。同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。
    思科
    1. 用宏定义写出swap(x,y)
    #define swap(x, y)\
    x = x + y;\
    y = x - y;\
    x = x - y;
    2.数组a[N],存放了1至N-1个数,其中某个数重复一次。写一个函数,找出被重复的数字.时间复杂度必须为o(N)函数原型:
    int do_dup(int a[],int N)
    3 一语句实现x是否为2的若干次幂的判断
    int i = 512;
    cout << boolalpha << ((i & (i - 1)) ? false : true) << endl;
    4.unsigned int intvert(unsigned int x,int p,int n)实现对x的进行转换,p为起始转化位,n为需要转换的长度,假设起始点在右边.如x=0b0001 0001,p=4,n=3转换后x=0b0110 0001
    unsigned int intvert(unsigned int x,int p,int n){
    unsigned int _t = 0;
    unsigned int _a = 1;
    for(int i = 0; i < n; ++i){
    _t |= _a;
    _a = _a << 1;
    }
    _t = _t << p;
    x ^= _t;
    return x;
    }
     
    慧通:
    什么是预编译
    何时需要预编译:
    1、总是使用不经常改动的大型代码体。
    2、程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件预编译为一个预编译头。
    char * const p;
    char const * p
    const char *p
    上述三个有什么区别?
    char * const p; //常量指针,p的值不可以修改
    char const * p;//指向常量的指针,指向的常量值不可以改
    const char *p; //和char const *p
    char str1[] = "abc";
    char str2[] = "abc";
    const char str3[] = "abc";
    const char str4[] = "abc";
    const char *str5 = "abc";
    const char *str6 = "abc";
    char *str7 = "abc";
    char *str8 = "abc";

    cout << ( str1 == str2 ) << endl;
    cout << ( str3 == str4 ) << endl;
    cout << ( str5 == str6 ) << endl;
    cout << ( str7 == str8 ) << endl;
    结果是:0 0 1 1
    解答:str1,str2,str3,str4是数组变量,它们有各自的内存空间;
    而str5,str6,str7,str8是指针,它们指向相同的常量区域。

    12. 以下代码中的两个sizeof用法有问题吗?[C易]
    void UpperCase( char str[] ) // 将 str 中的小写字母转换成大写字母
    {
        for( size_t i=0; i<sizeof(str)/sizeof(str[0]); ++i )
            if( 'a'<=str[i] && str[i]<='z' )
                str[i] -= ('a'-'A' );
    }
    char str[] = "aBcDe";
    cout << "str字符长度为: " << sizeof(str)/sizeof(str[0]) << endl;
    UpperCase( str );
    cout << str << endl;
    答:函数内的sizeof有问题。根据语法,sizeof如用于数组,只能测出静态数组的大小,无法检测动态分配的或外部数组大小。函数外的str是一个静态定义的数组,因此其大小为6,函数内的str实际只是一个指向字符串的指针,没有任何额外的与数组相关的信息,因此sizeof作用于上只将其当指针看,一个指针为4个字节,因此返回4。
    一个32位的机器,该机器的指针是多少位
    指针是多少位只要看地址总线的位数就行了。80386以后的机子都是32的数据总线。所以指针的位数就是4个字节了。
    main()
    {
      int a[5]={1,2,3,4,5};
       int *ptr=(int *)(&a+1);
       printf("%d,%d",*(a+1),*(ptr-1));
    }
    输出:2,5
    *(a+1)就是a[1],*(ptr-1)就是a[4],执行结果是2,5
    &a+1不是首地址+1,系统会认为加一个a数组的偏移,是偏移了一个数组的大小(本例是5个int)
    int *ptr=(int *)(&a+1);
    则ptr实际是&(a[5]),也就是a+5
    原因如下:
    &a是数组指针,其类型为 int (*)[5];
    而指针加1要根据指针类型加上一定的值,
    不同类型的指针+1之后增加的大小不同
    a是长度为5的int数组指针,所以要加 5*sizeof(int)
    所以ptr实际是a[5]
    但是prt与(&a+1)类型是不一样的(这点很重要)
    所以prt-1只会减去sizeof(int*)
    a,&a的地址是一样的,但意思不一样,a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5].

    1.请问以下代码有什么问题:
    int  main()
    {
    char a;
    char *str=&a;
    strcpy(str,"hello");
    printf(str);
    return 0;
    }
    没有为str分配内存空间,将会发生异常
    问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,但因为越界进行内在读写而导致程序崩溃。
    char* s="AAA";
    printf("%s",s);
    s[0]='B';
    printf("%s",s);
    有什么错?
    "AAA"是字符串常量。s是指针,指向这个字符串常量,所以声明s的时候就有问题。
    cosnt char* s="AAA";
    然后又因为是常量,所以对是s[0]的赋值操作是不合法的。

     
    1、写一个“标准”宏,这个宏输入两个参数并返回较小的一个。
    .#define Min(X, Y) ((X)>(Y)?(Y):(X))//结尾没有;
    2、嵌入式系统中经常要用到无限循环,你怎么用C编写死循环。
    while(1){}或者for(;;)
    3、关键字static的作用是什么?
    定义静态变量
    4、关键字const有什么含意?
    表示常量不可以修改的变量。
    5、关键字volatile有什么含意?并举出三个不同的例子?
    提示编译器对象的值可能在编译器未监测到的情况下改变。

    int (*s[10])(int) 表示的是什么啊
    int (*s[10])(int) 函数指针数组,每个指针指向一个int func(int param)的函数。

    1.有以下表达式:
    int a=248; b=4;int const c=21;const int *d=&a;
    int *const e=&b;int const *f const =&a;
    请问下列表达式哪些会被编译器禁止?为什么?
    *c=32;d=&b;*d=43;e=34;e=&a;f=0x321f;
    *c 这是个什么东东,禁止
    *d 说了是const, 禁止
    e = &a 说了是const 禁止
    const *f const =&a; 禁止
    2.交换两个变量的值,不使用第三个变量。即a=3,b=5,交换之后a=5,b=3;
    有两种解法, 一种用算术算法, 一种用^(异或)
    a = a + b;
    b = a - b;
    a = a - b;
    or
    a = a^b;// 只能对int,char..
    b = a^b;
    a = a^b;
    or
    a ^= b ^= a;
    3.c和c++中的struct有什么不同?
    c和c++中struct的主要区别是c中的struct不可以含有成员函数,而c++中的struct可以。c++中struct和class的主要区别在于默认的存取权限不同,struct默认为public,而class默认为private
    4.#include <stdio.h>
      #include <stdlib.h>
      void getmemory(char *p)
      {
        p=(char *) malloc(100);
        strcpy(p,"hello world");
      }
      int main( )
      {
        char *str=NULL;
        getmemory(str);
        printf("%s/n",str);
        free(str);
        return 0;
       }
    程序崩溃,getmemory中的malloc 不能返回动态内存, free()对str操作很危险
    5.char szstr[10];
      strcpy(szstr,"0123456789");
      产生什么结果?为什么?
      长度不一样,会造成非法的OS
    6.列举几种进程的同步机制,并比较其优缺点。
       原子操作
    信号量机制
       自旋锁
       管程,会合,分布式系统
    7.进程之间通信的途径
    共享存储系统
    消息传递系统
    管道:以文件系统为基础
    11.进程死锁的原因
    资源竞争及进程推进顺序非法
    12.死锁的4个必要条件
    互斥、请求保持、不可剥夺、环路
    13.死锁的处理
    鸵鸟策略、预防策略、避免策略、检测与解除死锁
    15.   操作系统中进程调度策略有哪几种?
    FCFS(先来先服务),优先级,时间片轮转,多级反馈
    8.类的静态成员和非静态成员有何区别?
    类的静态成员每个类只有一个,非静态成员每个对象一个
    9.纯虚函数如何定义?使用时应注意什么?
    virtual void f()=0;
    是接口,子类必须要实现
    10.数组和链表的区别
    数组:数据顺序存储,固定大小
    连表:数据可以随机存储,大小可动态改变
    12.ISO的七层模型是什么?tcp/udp是属于哪一层?tcp/udp有何优缺点?
    应用层
    表示层
    会话层
    运输层
    网络层
    物理链路层
    物理层
    tcp /udp属于运输层
    TCP 服务提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。
    与 TCP 不同, UDP 并不提供对 IP 协议的可靠机制、流控制以及错误恢复功能等。由于 UDP 比较简单, UDP 头包含很少的字节,比 TCP 负载消耗少。
    tcp: 提供稳定的传输服务,有流量控制,缺点是包头大,冗余性不好
    udp: 不提供稳定的服务,包头小,开销小  

    1:(void *)ptr 和 (*(void**))ptr的结果是否相同?其中ptr为同一个指针
    .(void *)ptr 和 (*(void**))ptr值是相同的
    2:int main()
       {
        int x=3;
        printf("%d",x);
        return 1;
      
       }
    问函数既然不会被其它函数调用,为什么要返回1?
    mian中,c标准认为0表示成功,非0表示错误。具体的值是某中具体出错信息

    1,要对绝对地址0x100000赋值,我们可以用
    (unsigned int*)0x100000 = 1234;
    那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做?
    *((void (*)( ))0x100000 ) ( );
    首先要将0x100000强制转换成函数指针,即:
    (void (*)())0x100000
    然后再调用它:
    *((void (*)())0x100000)();
    用typedef可以看得更直观些:
    typedef void(*)() voidFuncPtr;
    *((voidFuncPtr)0x100000)();
    2,已知一个数组table,用一个宏定义,求出数据的元素个数
    #define NTBL
    #define NTBL (sizeof(table)/sizeof(table[0]))
    面试题: 线程与进程的区别和联系? 线程是否具有相同的堆栈? dll是否有独立的堆栈?
    进程是死的,只是一些资源的集合,真正的程序执行都是线程来完成的,程序启动的时候操作系统就帮你创建了一个主线程。
    每个线程有自己的堆栈。
    DLL中有没有独立的堆栈,这个问题不好回答,或者说这个问题本身是否有问题。因为DLL中的代码是被某些线程所执行,只有线程拥有堆栈,如果DLL中的代码是EXE中的线程所调用,那么这个时候是不是说这个DLL没有自己独立的堆栈?如果DLL中的代码是由DLL自己创建的线程所执行,那么是不是说DLL有独立的堆栈?
    以上讲的是堆栈,如果对于堆来说,每个DLL有自己的堆,所以如果是从DLL中动态分配的内存,最好是从DLL中删除,如果你从DLL中分配内存,然后在EXE中,或者另外一个DLL中删除,很有可能导致程序崩溃

    unsigned short A = 10;
    printf("~A = %u\n", ~A);
    char c=128;
    printf("c=%d\n",c);
    输出多少?并分析过程
    第一题,~A =0xfffffff5,int值 为-11,但输出的是uint。所以输出4294967285
    第二题,c=0x10,输出的是int,最高位为1,是负数,所以它的值就是0x00的补码就是128,所以输出-128。
    这两道题都是在考察二进制向int或uint转换时的最高位处理。
    分析下面的程序:
    void GetMemory(char **p,int num)
    {
        *p=(char *)malloc(num);
       
    }       
    int main()
    {
        char *str=NULL;
       
        GetMemory(&str,100);
       
        strcpy(str,"hello");
       
        free(str);
       
        if(str!=NULL)
        {
            strcpy(str,"world");
        }   
           
        printf("\n str is %s",str);
        getchar();
    }   
    问输出结果是什么?希望大家能说说原因,先谢谢了
    输出str is world。
    free 只是释放的str指向的内存空间,它本身的值还是存在的.
    所以free之后,有一个好的习惯就是将str=NULL.
    此时str指向空间的内存已被回收,如果输出语句之前还存在分配空间的操作的话,这段存储空间是可能被重新分配给其他变量的,
    尽管这段程序确实是存在大大的问题(上面各位已经说得很清楚了),但是通常会打印出world来。
    这是因为,进程中的内存管理一般不是由操作系统完成的,而是由库函数自己完成的。
    当你malloc一块内存的时候,管理库向操作系统申请一块空间(可能会比你申请的大一些),然后在这块空间中记录一些管理信息(一般是在你申请的内存前面一点),并将可用内存的地址返回。但是释放内存的时候,管理库通常都不会将内存还给操作系统,因此你是可以继续访问这块地址的,只不过。。。。。。。。楼上都说过了,最好别这么干。
    char a[10],strlen(a)为什么等于15?运行的结果
    #include "stdio.h"
    #include "string.h"
    void main()
    {
    char aa[10];
    printf("%d",strlen(aa));
    }
    sizeof()和初不初始化,没有关系;
    strlen()和初始化有关。

    char (*str)[20];/*str是一个数组指针,即指向数组的指针.*/
    char *str[20];/*str是一个指针数组,其元素为指针型数据.*/
    long a=0x801010;
    a+5=?
    0x801010用二进制表示为:“1000 0000 0001 0000 0001 0000”,十进制的值为8392720,再加上5就是8392725罗
     
     
    1)给定结构struct A
    {
           char t:4;
           char k:4;
           unsigned short i:8;
           unsigned long m;
    };问sizeof(A) = ?
    给定结构struct A
    {
           char t:4; 4位
           char k:4; 4位
           unsigned short i:8; 8位     
           unsigned long m; // 偏移2字节保证4字节对齐
    }; // 共8字节
    2)下面的函数实现在一个数上加一个数,有什么错误?请改正。
    int add_n ( int n )
    {
        static int i = 100;
        i += n;
        return i;
    }
    当你第二次调用时得不到正确的结果,难道你写个函数就是为了调用一次?问题就出在 static上?

    // 帮忙分析一下
    #include<iostream.h>
    #include <string.h>
    #include <malloc.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <memory.h>
    typedef struct  AA
    {
            int b1:5;
            int b2:2;
    }AA;
    void main()
    {
            AA aa;
            char cc[100];
             strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz");
           memcpy(&aa,cc,sizeof(AA));
            cout << aa.b1 <<endl;
            cout << aa.b2 <<endl;
    }
    答案是 -16和1
    首先sizeof(AA)的大小为4,b1和b2分别占5bit和2bit.
    经过strcpy和memcpy后,aa的4个字节所存放的值是:
    0,1,2,3的ASC码,即00110000,00110001,00110010,00110011
    所以,最后一步:显示的是这4个字节的前5位,和之后的2位
    分别为:10000,和01
    因为int是有正负之分  所以:答案是-16和1
    求函数返回值,输入x=9999;
    int func ( x )
    {
        int countx = 0;
        while ( x )
        {
            countx ++;
            x = x&(x-1);
        }
        return countx;
    }
    结果呢?
    知道了这是统计9999的二进制数值中有多少个1的函数,且有
    9999=9×1024+512+256+15
    9×1024中含有1的个数为2;
    512中含有1的个数为1;
    256中含有1的个数为1;
    15中含有1的个数为4;
    故共有1的个数为8,结果为8。
    1000 - 1 = 0111,正好是原数取反。这就是原理。
    用这种方法来求1的个数是很效率很高的。
    不必去一个一个地移位。循环次数最少。
    int a,b,c 请写函数实现C=a+b ,不可以改变数据类型,如将c改为long int,关键是如何处理溢出问题
    bool add (int a, int b,int *c)
    {
    *c=a+b;
    return (a>0 && b>0 &&(*c<a || *c<b) || (a<0 && b<0 &&(*c>a || *c>b)));
    }

    分析:
    struct bit
    {   int a:3;
        int  b:2;
        int c:3;
    };
    int main()
    {
      bit s;
      char *c=(char*)&s;
       cout<<sizeof(bit)<<endl;
      *c=0x99;
       cout << s.a <<endl <<s.b<<endl<<s.c<<endl;
         int a=-1;
       printf("%x",a);
      return 0;
    }
    输出为什么是
    4
    1
    -1
    -4
    ffffffff
    因为0x99在内存中表示为 100 11 001 , a = 001, b = 11, c = 100
    当c为有符合数时, c = 100, 最高1为表示c为负数,负数在计算机用补码表示,所以c = -4;同理
    b = -1;
    当c为有符合数时, c = 100,即 c = 4,同理 b = 3

    位域 :  
    有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:    
    struct 位域结构名    
    { 位域列表 };   
    其中位域列表的形式为: 类型说明符 位域名:位域长度    
    例如:    
    struct bs   
    {   
    int a:8;   
    int b:2;   
    int c:6;   
    };   
    位域变量的说明与结构变量说明的方式相同。 可采用先定义后说明,同时定义说明或者直接说明这三种方式。例如:    
    struct bs   
    {   
    int a:8;   
    int b:2;   
    int c:6;   
    }data;   
    说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。对于位域的定义尚有以下几点说明:   
    1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:    
    struct bs   
    {   
    unsigned a:4   
    unsigned :0 /*空域*/   
    unsigned b:4 /*从下一单元开始存放*/   
    unsigned c:4   
    }   
    在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。   
    2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。   
    3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:    
    struct k   
    {   
    int a:1   
    int :2 /*该2位不能使用*/   
    int b:3   
    int c:2   
    };   
    从以上分析可以看出,位域在本质上就是一种结构类型, 不过其成员是按二进位分配的。   
    二、位域的使用位域的使用和结构成员的使用相同,其一般形式为: 位域变量名•位域名 位域允许用各种格式输出。   
    main(){   
    struct bs   
    {   
    unsigned a:1;   
    unsigned b:3;   
    unsigned c:4;   
    } bit,*pbit;   
    bit.a=1;   
    bit.b=7;   
    bit.c=15;   
    pri
    改错:
    #include <stdio.h>
    int main(void) {
        int **p;
        int arr[100];
        p = &arr;
        return 0;
    }
    解答:
    搞错了,是指针类型不同,
    int **p; //二级指针
    &arr; //得到的是指向第一维为100的数组的指针
    #include <stdio.h>
    int main(void) {
    int **p, *q;
    int arr[100];
    q = arr;
    p = &q;
    return 0;
    }

    下面这个程序执行后会有什么错误或者效果:
     #define MAX 255
     int main()
    {
       unsigned char A[MAX],i;//i被定义为unsigned char
       for (i=0;i<=MAX;i++)
          A[i]=i;
    }
    解答:死循环加数组越界访问(C/C++不进行数组越界检查)
    MAX=255
    数组A的下标范围为:0..MAX-1,这是其一..
    其二.当i循环到255时,循环内执行:
      A[255]=255;
    这句本身没有问题..但是返回for (i=0;i<=MAX;i++)语句时,
    由于unsigned char的取值范围在(0..255),i++以后i又为0了..无限循环下去.
    struct name1{
       char  str;
       short x;
       int   num;
    }
    struct name2{
       char str;
       int num;
       short x;
    }
    sizeof(struct name1)=8,sizeof(struct name2)=12
    在第二个结构中,为保证num按四个字节对齐,char后必须留出3字节的空间;同时为保证整个结构的自然对齐(这里是4字节对齐),在x后还要补齐2个字节,这样就是12字节。
    intel:
    A.c 和B.c两个c文件中使用了两个相同名字的static变量,编译的时候会不会有问题?这两个static变量会保存到哪里(栈还是堆或者其他的)?
    static的全局变量,表明这个变量仅在本模块中有意义,不会影响其他模块。
    他们都放在数据区,但是编译器对他们的命名是不同的。
    如果要使变量在其他模块也有意义的话,需要使用extern关键字。
    struct s1
    {
      int i: 8;
      int j: 4;
      int a: 3;
      double b;
    };
    struct s2
    {
      int i: 8;
      int j: 4;
      double b;
      int a:3;
    };
    printf("sizeof(s1)= %d\n", sizeof(s1));
    printf("sizeof(s2)= %d\n", sizeof(s2));
    result: 16, 24
    第一个struct s1
    {
      int i: 8;
      int j: 4;
      int a: 3;
      double b;
    };
    理论上是这样的,首先是i在相对0的位置,占8位一个字节,然后,j就在相对一个字节的位置,由于一个位置的字节数是4位的倍数,因此不用对齐,就放在那里了,然后是a,要在3位的倍数关系的位置上,因此要移一位,在15位的位置上放下,目前总共是18位,折算过来是2字节2位的样子,由于double是8字节的,因此要在相对0要是8个字节的位置上放下,因此从18位开始到8个字节之间的位置被忽略,直接放在8字节的位置了,因此,总共是16字节。
    第二个最后会对照是不是结构体内最大数据的倍数,不是的话,会补成是最大数据的倍

  • 存档:API测试疑惑

    2010-07-19 19:24:06

    API(Application Programming Interface)应用程序接口,应用编程接口
    e.g.(摘自http://www.douban.com/service/apidoc/)豆瓣API是豆瓣为第三方开发人员提供的编程接口。利用豆瓣API,你可以在你的网站或程序中使用豆瓣的数据和功能(请务必遵守API使用条款)。
    目前的豆瓣API支持的功能包括:
    搜索并查看书籍、电影、音乐信息
    搜索并查看用户信息,查看用户友邻信息
    查看用户收藏
    添加、更新、删除用户收藏
    查看评论
    发布、修改、删除评论
    查看、添加、删除用户广播
    查看、添加、删除用户日记
    搜索并查看、添加、删除活动
    查看、添加、删除、回复推荐
    豆瓣 API 测试控制台http://modou.us/console

    猫扑API测试控制台:


    API测试除了要测试功能以外还要测试接口。一个API或者函数可以作为一个单元,对这个单元进行单元测试,你可以用黑盒方法,也可以用白盒方法。黑盒方法就是不去看这个单元的实现代码,只根据这个单元的功能说明来设计测试用例并进行测试。测试的时候你可能需要写一点简单的代码来调用这个函数,这就是所谓的驱动函数,你也可能需要写一些代码来接收或者验证被测单元的输出是否正确,这就是所谓的桩函数;白盒测试方法就是你通过分析被测单元的实现代码,根据不同的测试策略(如分支覆盖或者逻辑覆盖等)来设计测试用例并作相应的测试。
    另外,API的测试中,接口的测试也很重要,自己写点测试代码,调用api。这些准备好,然后再考虑测试数据的覆盖。
    xavier_007说:
    接口测试我感觉自己写或者借助现有的工具都可以。
    例如测试cpp的api
    可以在win32上自己搭建环境,针对每个接口设计测试用例集,然后批量执行就可以了
    也可以用工具,我用的是gtest,还好
    正在尝试在wince上跑

    API测试区别单元测试的英文原文存档

    March 2006 - API Testing vs. Unit Testing: What's the difference?
    With the emergence of extreme programming, test-driven development and other agile methods, unit testing has become an important part of almost every development effort. At the same time, many applications provide application programming interfaces (APIs) to allow code-level access to the functionality. These APIs, just like any other interface into the product, must be tested before they are released to the end-users. This article will examine the key similarities and differences between these two types of testing, focusing on the tools, the people involved in each, and the approaches taken to get the best results for your time and effort.

    Since both API-testing and unit-testing target the code-level, we can use similar tools for both activities. The most commonly used unit-testing tools, such as the jUnit test framework (http://www.junit.org), can also be used to build your API testing harness.

    In many organizations we've worked with, the unit testing and API testing activities are owned by different teams. Unit testing is almost always an activity that is owned by the development team; developers are expected to build unit tests for each of their code modules (these are typically classes, functions, stored procedures, or some other 'atomic' unit of code), and to ensure that each module passes its unit tests before the code is included in a build. This practice makes a lot of sense because it helps the developers solidify their code. Often times, this effort requires debugging and bug-fixing in real-time.

    API testing, on the other hand, is typically an activity owned by the QA team, a staff other than the author of the code. API tests are often run after the build has been created, and it is common that the authors of the tests do not have access to the source code; they are essentially creating black box tests against an API rather than the traditional GUI.

    Another key difference between API and unit testing lies in the test case design. Unit tests are typically designed by the developers to verify the functionality of each unit. The scope of unit testing often does not consider the system-level interactions of the various units; the developers simply verify that each unit in isolation performs as it should.

    API testing, like other activities owned by the QA team, must consider the 'full' functionality of the system, as it will be used by the end user (in this case, another program). This means that API tests must be far more extensive than unit tests, and take into consideration the sorts of 'scenarios' that the API will be used for, which typically involve interactions between several different modules within the application.

    So if your product contains an API that must be tested, how should you approach the task? First of all, recognize that API testing is a testing activity that happens to require some coding, and is usually beyond the scope of what developers should be expected to do. The testing team should own this activity. Secondly, recognize that traditional testing techniques such as equivalence classes and boundary analysis are also applicable to API testing, so even if you are not too comfortable with coding, you can still design good API tests. Finally, recognize that you will not be able to test all possible scenarios that are possible to use with your API. Focus your testing on the most likely usage scenarios, and also apply techniques such as Soap Opera Testing and forced error testing using various flavors of data type and size to increase your confidence in the test coverage.

  • C笔记--C语言中的形参&实参

    2010-07-06 14:40:35

    记住这条基本原理:形参相当于函数中定义的变量,调用函数传递参数的过程相当于定义形参变量并且用实参的值来初始化。例如这样调用:
    void print_time(int hour, int minute)
    {
    	printf("%d:%d\n", hour, minute);
    }
    
    int main(void)
    {
    	int h = 23, m = 59;
    	print_time(h, m);
    	return 0;
    }

    相当于在函数print_time中执行了这样一些语句:

    int hour = h;
    int minute = m;
    printf("%d:%d\n", hour, minute);

    main函数的变量hprint_time函数的参数hour是两个不同的变量,只不过它们的存储空间中都保存了相同的值23,因为变量h的值赋给了参数hour。同理,变量m的值赋给了参数minute。C语言的这种传递参数的方式称为Call by Value。在调用函数时,每个参数都需要得到一个值,函数定义中有几个形参,在调用时就要传几个实参,不能多也不能少,每个参数的类型也必须对应上。

    ---------------分界线-------

    在定义函数中指定的形参,在未出现函数调用时,他们并不占内存中的存储单元。只有在发生函数调用时,函数max中的形参才被分配内存单元。在调用结束后,形参所占的内存单元也被释放。
    实参可以是常量、变量和表达式,但要求有确定的值。在调用时将实参的值赋给形参。
    在C语言中,实参向形参的数据传递是值传递,单向传递,只由实参传给形参,而不能由形参传给实参。在内存中,实参单元和形参单元是不同的单元。在调用函数时,给形参分配存储单元,并将实参对应的值传递给形参,调用结束后,形参单元被释放,实参单元仍保留原值。
    指针变量作函数参数也要遵循这一规则。不可能通过调用函数来改变实参变量的值,但可以改变实参指针变量所指变量的值。



    函数的形参和实参具有以下特点:

    1.形参变量只有在被调用时才分配内存单元,在调用结束时, 即刻释放所分配的内存单元。因此,形参只有在函数内部有效。 函数调用结束返回主调函数后则不能再使用该形参变量。

    2.实参可以是常量、变量、表达式、函数等, 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形参。 因此应预先用赋值,输入等办法使实参获得确定值。

    3.实参和形参在数量上,类型上,顺序上应严格一致, 否则会发生“类型不匹配”的错误。

    4.函数调用中发生的数据传送是单向的。 即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。

  • 存档【网络转载】:我总记不住的loadrunner关联

    2010-06-18 13:16:47

    如何在脚本中做关联 (Correlation)
    当录制脚本时,VuGen会拦截client端(浏览器)与server端(网站服务器)之间的对话,并且通通记录下来,产生脚本。在VuGen的Recording Log中,您可以找到浏览器与服务器之间所有的对话,包含通讯内容、日期、时间、浏览器的请求、服务器的响应内容等等。脚本和Recording Log最大的差别在于,脚本只记录了client端要对server端所说的话,而Recording Log则是完整纪录二者的对话。

    当执行脚本时,您可以把VuGen想象成是一个演员,它伪装成浏览器,然后根据脚本,把当初真的浏览器所说过的话,再对网站伺服器重新说一遍,VuGen企图骗过服务器,让服务器以为它就是当初的浏览器,然后把网站内容传送给VuGen。
    所以纪录在脚本中要跟服务器所说的话,完全与当初录制时所说的一样,是写死的(hard-coded)。这样的作法在遇到有些比较聪明的服务器时,还是会失效。这时就需要透过「关联(correlation)」的做法来让VuGen可以再次成功地骗过服务器。
    何谓关联(correlation)?
    所谓的关联(correlation)就是把脚本中某些写死的(hard-coded)数据,转变成是撷取自服务器所送的、动态的、每次都不一样的数据。
    举一个常见的例子,刚刚提到有些比较聪明的服务器,这些服务器在每个浏览器第一次跟它要数据时,都会在数据中夹带一个唯一的辨识码,接下来就会利用这个辨识码来辨识跟它要数据的是不是同一个浏览器。一般称这个辨识码为Session ID。对于每个新的交易,服务器都会产生新的Session ID给浏览器。这也就是为什么执行脚本会失败的原因,因为VuGen还是用旧的Session ID向服务器要数据,服务器会发现这个Session ID是失效的或是它根本不认识这个Session ID,当然就不会传送正确的网页数据给VuGen了。
    下面的图示说明了这样的情形:
    当录制脚本时,浏览器送出网页A的请求,服务器将网页A的内容传送给浏览器,并且夹带了一个ID=123的数据,当浏览器再送出网页B的情求时,这时就要用到ID=123的数据,服务器才会认为这是合法的请求,并且把网页B的内容送回给浏览器。
    在执行脚本时会发生什么状况?浏览器再送出网页B的请求时,用的还是当初录制的ID=123的数据,而不是用服务器新给的ID=456,整个脚本的执行就会失败。

    要对付这种服务器,我们必须想办法找出这个Session ID到底是什么、位于何处,然后把它撷取下来,放到某个参数中,并且取代掉脚本中有用到Session ID的部份,这样就可以成功骗过服务器,正确地完成整个交易了。
    哪些错误代表着我应该做关联(correlation)?
    假如脚本需要关联(correlation),在还没做之前是不会执行通过的,也就是说会有错误讯息发生。不过,很不幸地,并没有任何特定的错误讯息是和关联(correlation)有关系的。会出现什么错误讯息,与系统实做的错误处理机制有关。错误讯息有可能会提醒您要重新登入,但是也有可能直接就显示HTTP 404的错误讯息。
    要如何做关联(correlation)?
    关联(correlation)函数
    关联(correlation)会用到下列的函数:
    • web_reg_save_param:这是最新版,也是最常用来做关联(correlation)的函数。
    语法:
    web_reg_save_param ( “Parameter Name” , < list of Attributes >, LAST );
    • web_create_html_param、web_create_html_param_ex:这二个函数主要是保留作为向前兼容的目的的。建议使用 web_reg_save_param 函数。
    详细用法请参考使用手册。在VuGen中点选【Help】>【Function reference】>【Contexts】>【Web and Wireless Vuser Functions】>【Correlation Functions】。
    如何找出要关联(correlation)数据
    简单的说,每一次执行时都会变动的值,就有可能需要做关联(correlation)。
    VuGen提供二种方式帮助您找出需要做关联(correlation)的值:
    1. 自动关联
    2. 手动关联
    自动关联
    VuGen内建自动关联引擎(auto-correlation engine),可以自动找出需要关联的值,并且自动使用关联函数建立关联。
    自动关联提供下列二种机制:
    • Rules Correlation:在录制过程中VuGen会根据订定的规则,实时自动找出要关联的值。规则来源有两种:
    o 内建(Built-in Correlation):
    VuGen已经针对常用的一些应用系统,如AribaBuyer、BlueMartini、BroadVision、InterStage、mySAP、NetDynamics、Oracle、PeopleSoft、Siebel、SilverJRunner等,内建关联规则,这些应用系统可能会有一种以上的关联规则。您可以在【Recording Options】>【Internet Protocol】>【Correlation】中启用关联规则,则当录制这些应用系统的脚本时,VuGen会在脚本中自动建立关联。
    您也可以在【Recording Options】>【Internet Protocol】>【Correlation】检视每个关联规则的定义。
    o 使用者自订(User-defined Rules Correlation):
    除了内建的关联规则之外,使用者也可以自订关联规则。您可以在【Recording Options】>【Internet Protocol】>【Correlation】建立新的关联规则。
    • Correlation Studio:有别于Rules Correlation,Correlation Studio则是在执行脚本后才会建立关联,也就是说当录制完脚本后,脚本至少须被执行过一次,Correlation Studio才会作用。Correlation Studio会尝试找出录制时与执行时,服务器响应内容的差异部分,藉以找出需要关联的数据,并建立关联。
    Rule Correlation
    请依照以下步骤使用Rule Correlation:
    1. 启用auto-correlation
    1. 点选VuGen的【Tools】>【Recording Options】,开启【Recording Options】对话窗口,选取【Internet Protocol】>【Correlation】,勾选【Enable correlation during recording】,以启用自动关联。
    2. 假如录制的应用系统属于内建关联规则的系统,如AribaBuyer、BlueMartini、BroadVision、InterStage、mySAP、NetDynamics、Oracle、PeopleSoft、Siebel、SilverJRunner等,请勾选相对应的应用系统。
    3. 或者也可以针对录制的应用系统加入新的关联规则,此即为使用者自订的关联规则。
    4. 设定当VuGen侦测到符合关联规则的数据时,要如何处理:
     【Issue a pop-up message and let me decide online】:跳出一个讯息对话窗口,询问您是否要建立关联。
     【Perform. correlation in sceipt】:直接自动建立关联
    2. 录制脚本
    开始录制脚本,在录制过程中,当VuGen侦测到符合关联规则的数据时,会依照设定建立关联,您会在脚本中看到类似以下的脚本,此为BroadVision应用系统建立关联的例子,在脚本批注部分可以看到关联前的数据为何。

    3. 执行脚本验证关联是OK的。
    Correlation Studio
    当录制的应用系统不属于VuGen预设支持的应用系统时,Rule Correlation可能既无法发挥作用,这时可以利用Correlation Studio来做关联。
    Correlation Studio会尝试找出录制时与执行时,服务器响应内容的差异部分,藉以找出需要关联的数据,并建立关联。
    使用Correlation Studio的步骤如下:
    1. 录制脚本并执行
    2. 执行完毕后,VuGen会跳出下面的【Scan Action for Correlation】窗口,询问您是否要扫描脚本并建立关联,按下【Yes】按钮。

    3. 扫描完后,可以在脚本下方的【Correlation Results】中看到扫描的结果。

    4. 检查一下扫瞄的结果后,选择要做关联的数据,然后按下【Correlate】按钮,一笔一笔做,或是按下【Correlate All】让VuGen一次就对所有的数据建立关联。
    注意:由于Correlation Studio会找出所有有变动的数据,但是并不是所有的数据都需要做关联,所以不建议您直接用【Correlate All】。
    5. 一般来说,您必须一直重复步骤1~4直到所有需要做关联的数据都找出来为止。因为有时前面的关联还没做好之前,将无法执行到后面需要做关联的部份。
    有可能有些需要做关联的动态数据,连Correlation Studio都无法侦测出来,这时您就需要自行做手动关联了。
    手动关联
    手动关联的执行过程大致如下:
    1. 使用相同的业务流程与数据,录制二份脚本
    2. 使用WinDiff工具协助找出需要关联的数据
    3. 使用web_reg_save_param函数手动建立关联
    4. 将脚本中有用到关联的数据,以参数取代
    接下来将详细的说明如何执行每个步骤
    使用相同的业务流程与数据,录制二份脚本
    1. 先录制一份脚本并存档。
    2. 依照相同的操作步骤与数据录制第二份脚本并存盘。注意,所有的步骤和输入的数据一定都要一样,这样才能找出由服务器端产生的动态数据。
    有时候会遇到真的无法使用相同的输入数据,那您也要记住您使用的输入数据,到时才能判断是您输入的数据,还是变动的数据。
    使用WinDiff工具协助找出需要关联的数据
    1. 在第二份脚本中,点选VuGen的【Tools】>【Compare with Vuser…】,并选择第一份脚本。
    2. 接着WinDiff会开启,同时显示二份脚本,并显示有差异的地方。WinDiff会以一整行黄色标示有差异的脚本,并且以红色的字体显示真正差异的文字。(假如没看到红色字体,请点选【Options】>【View】>【Show Inline Differences】)。
    3. 逐一检视二份脚本中差异的部份,每一个差异都可能是需要做关联的地方。选取差异的脚本,然后复制。
    在复制时,有时并不需要取整行脚本,可能只会选取脚本中的一部分。
    注意:请忽略lr_thik_time的差异部份,因为lr_thik_time是用来模拟每个步骤之间使用者思考延迟的时间。

    4. 接着要在Recording Log(单一protocol)或是Generation Log(多重protocol)中找这个值。将鼠标光标点到Recording Log的第一行开头,按下Ctrl+F,开启【Find】窗口,贴上刚刚复制的脚本,找出在Recording Log第一次出现的位置。

    结果会有二种:
    o 在Recording Log中找不到要找的数据,这时请先确认您找对了脚本,毕竟现在开启了二个几乎一样的脚本,很容易弄错。
    o 在Recording Log中找到了要找的数据,这时要确认数据是从服务器端传送过来的。首先可以先检查数据的标头,从标头的Receiving response可以知道数据是从服务器端传送到client端的。假如此数据第一次出现是在Sending request中,则表示此数据是由client端产生,不需要做关联,但是有可能需要做参数化(parameterized)。
    您要找的标头格式如下:
    *** [tid=b9 Action1 2] Receiving response from host astra.merc-int.com:80 ( 25/11/2002 12:04:00 )

    5. 现在您已经找到录制二次都不一样,而且是由服务器所产生的动态数据了,而此数据极有可能需要做关联。
    使用web_reg_save_param函数手动建立关联
    在找到是由服务器所产生的动态数据之后,接下来要做的就是找出适当的位置,使用web_reg_save_param函数,将这个动态数据撷取到某个参数中。
    1. 要在哪里使用web_reg_save_param函数?
    在之前的步骤,我们已经在Execution Log找到可能需要关联的动态数据。在Execution Log中选取动态数据前的文字然后复制,我们将会利用这段文字,来帮助我们找出要关联的动态数据。

    不过在这之前我们要先找出使用web_reg_save_param函数的正确位置,所以我们要再重新执行一遍脚本,而且这次会开启所有的Log。
    1. 在VuGen中点选【Vuser】>【Run-Time Settings】。
    2. 点选【General】>【Log】。
    3. 勾选【Enable logging】、【Always sends messages】、【Extended log】,以及【Extended log】下的所有选项。
    4. 按下【OK】就可以执行脚本了。
    执行完脚本之后,在Execution Log中搜寻刚刚复制的字符串。找到字符串后,在字符串前面会有A.tion1.c(7),这个7就是到时候要插入web_reg_save_param函数的位置,也就是要插入到脚本的第7行。
    在脚本的第7行前插入一行空白行,然后输入
    web_reg_save_param(“UserSession”,
    “UserSession” 这个 “UserSession” 就是到时要使用的参数名称,建议给个有意义的名字。
    注意:到这里整个web_reg_save_param函数还没完成。

    2. 找出web_reg_save_param中要用到的边界
    web_reg_save_param函数主要是透过动态数据的前面和后面的固定字符串,来辨识要撷取的动态数据的,所以我们还需要找出动态数据的边界字符串。
    找出左边界字符串
    再回到Execution Log中,选取动态数据前的字符串并且复制它。
    这时会有个问题,到底要选取多少字符串才足以唯一识别要找的动态数据呢?建议是越多越好,但是尽量不要包含到特殊字符。
    在这边我们选取「input type=hidden name=userSession value=」字符串。选好之后,还要再确认一次这段字符串真的是可以唯一识别的,所以我们在Execution Log中透过Ctrl+F的搜寻,找找看这段字符串是否可以找到要找的动态数据。假如找不到,web_reg_save_param函数还有个ORD参数可以使用,ORD参数可以设定出现在第几次的字符串才是要找的字符串。
    将这个边界字符串加到未完成的web_reg_save_param函数中:
    web_reg_save_param(“UserSession”, “LB= input type=hidden name=userSession value=”,
    找出右边界字符串
    接下来要找出动态数据的右边界字符串,这个字符串就比较好找了,从动态数据的最后一个字符开始,通常就是我们要找的右边界字符串了。
    以这个例子来看,就是「>」,所以再把右边界字符串加入,web_reg_save_param函数中,这时web_reg_save_param函数已经快完成了。最后再加上「LAST);」就完成整个web_reg_save_param函数了。
    web_reg_save_param(“UserSession”, “LB= input type=hidden name=userSession value=”, “RB=>”, LAST);

    将脚本中有用到关联的数据,以参数取代
    当使用web_reg_save_param建立参数后,接下来就是用“UserSession”参数去取代脚本中写死的(hard-coded)资料。
    范例:

    “Name=userSession”, “Value=75893.0884568651DQADHfApHDHfcDtccpfAttcf”, ENDITEM,
    换成
    “Name=userSession”, “Value={UserSession}”, ENDITEM,

    到这里您已经完成了一个关联了,接下来就是执行脚本,是否能成功运行,假如还是有问题,就要检查看看是否还需要再做另一个关联。
    关于 web_reg_save_param 函数
    对于关联(correlation)来说,web_reg_save_param是最重要的一个函数,其功能是在下载的网页内容中,透过设定的边界字符串,找出特定的数据并将其储存在一个参数中,以供后续脚本使用。
    接下来将针对web_reg_save_param做比较详细的说明。
    Service and registration type function
    web_reg_save_param是一个Service function。service function主要是用来完成一些特殊的工作的,如关联、设定proxy、提供认证信息等,当其作用时,不会对网页的内容做任何的修改。
    web_reg_save_param同时也是一个registration type function (只要函数名称中包含_reg_的字眼,表示其为registration type function)。registration type function意味着其真正作用的时机是在下一个action function完成时执行的。举例来说,当某个web_url执行时所接收到的网页内容中包含了要做关联的动态数据,则必须将web_reg_save_param放在此web_url之前,则web_reg_save_param会在web_url执行完毕后,也就是网页内容都下载完后,再执行web_reg_save_param找寻要做关联的动态数据并建立参数。
    所以要记住一点,要使用registration type function时,要注意其放置的位置必须在要作用的action function之前。
    语法
    int web_reg_save_param(const char *ParamName, <list of Attributes>, LAST);
    参数说明
    ParamName:存放动态数据的参数名称
    list of Attributes:其它属性,包含 Notfound, LB, RB, RelFrameID, Search, ORD, SaveOffset, Convert, 以及 SaveLen。属性值不分大小写,例如 Search=all。以下将详细说明每个属性值的意义:
    • Notfound:指定当找不到要找的动态数据时该怎么处置。
    o Notfound=error:当找不到动态数据时,发出一个错误讯息。假如没设定此属性,此为LoadRunner的默认值。
    o Notfound=warning:当找不到动态数据时,不发出错误讯息,只发出警告,脚本也会继续执行下去不会中断。在对角本除错时,可以使用此属性值。
    • LB:动态数据的左边界字符串。此属性质是必须要有的,而且区分大小写。
    • RB:动态数据的右边界字符串。此属性质是必须要有的,而且区分大小写。
    • RelFrameID:相对于URL而言,欲搜寻的网页的Frame。此属性质可以是All或是数字,而且可有可无。
    • Search:搜寻的范围。可以是Headers(只搜寻headers)、Body(只搜寻body部分,不搜寻header)、Noresource(只搜寻body部分,不搜寻header与resource)或是All(搜寻全部范围,此为默认值)。此属性质可有可无。
    • ORD:指明从第几次出现的左边界开始才是要撷取的数据。此属性质可有可无,默认值是1。假如值为All,则所有找到符合的数据会储存在数组中。
    • SaveOffset:当找到符合的动态数据时,从第几个字符开始才开始储存到参数中。此属性质不可为负数,其默认值为0。
    • Convert:可能的值有二种:
    o HTML_TO_URL: 将HTML-encoded数据转成URL-encoded数据格式
    o HTML_TO_TEXT:将HTML-encoded数据转成纯文字数据格式
    • SaveLen:从offect开始算起,到指定的长度内的字符串,才储存到参数中。此参数可有可无,默认值是-1,表示储存到结尾整个字符串。
    范例
    web_reg_save_param("A", "LB/ic=<a href=", "RB='>", "Ord=All", LAST);nner会搜寻网页中所有以 「<a href=」 开头,且以 「’>」结束,当中包含的字符串,并且储存在「A」参数中。
    Tips and Tricks
    以下提供一些关联的常见问题:
    • 如何打印出参数值?
    lr_output_message这二个函数来做到。例如:
    lr_output_message(“Value Captured = %s”, lr_eval_string(“{ParameterName}”));
    lr_eval_string与lr_output_message函数的使用说明请参考LoadRunner Online Function Reference。
    • 在脚本的data目录下找不到路制时的快照(snapshot)
    造成在脚本的data目录下找不到路制时的快照(snapshot)的可能原因如下:
    o 脚本是由VuGen 6.02或更早的版本所录制的
    o 汇入的Action不会包含快照(snapshot)的档案
    o 脚本是储存在只读的目录下,早成VuGen无法储存执行时撷取的快照(snapshot)
    o 某些步骤并不会产生快照(snapshot),如浏览某个资源
    o 快照(snapshot)功能被取消
    【Tools】>【General options】>【Correlation】tab >【Save correlation information during replay】
    • 开启WinDiff时出现「File no longer available」的错误讯息
    WinDiff这个工具有些限制,无法开启包含空格符的目录或是脚本,所以建议命名时不要使用空格符,并且尽可能将名称取短一点。
    • 录制时突然跳出【Correlation warning】对话窗口
    当你有勾选自动关联的【Issue a popup message and let me decide online】选项,当VuGen发现有可能要做关联的数据时,就会跳出【Correlation warning】的窗口,询问你要做关联(Correlation in scrīpt)还是要忽略(Ignore)。
    另外你也可以勾选【Perform. correlation in scrīpt】,让VuGen自动作关联,不会再跳出询问窗口。
    或是勾选【Disable correlation engine】,关闭自动关联的功能。

    • 如何手动启动「Scan action for correlation」的功能
    要手动启动「Scan action for correlation」的功能,请先执行脚本一次后,点选【Vuser】>【Scan Action for Correlation】。

    • 执行完脚本后并未出现【Scan Action for Correlation】窗口
    要启用【Scan Action for Correlation】功能,请点选【Tools】>【General options】>【Correlation】tab,勾选【Show Scan for correlation popup after replay of Vuser】选项。

  • 存档:打开关闭excel的vbs函数

    2010-06-18 12:53:01

    作者:郝宁

    '*********************************************************************************************
    ' 函数说明:打开工作薄
    ' 参数说明:
    '          (1)ExcelSH:Excel中要使用的Sheet对象;
    '          (2)sheetName:要打开的工作薄Sheet名称;
    '          (3)path:要打开的工作薄路径;
    ' 返回结果:
    '          (1)成功:工作表对象ExcelSH
    '          (1)失败:Nothing
    ' 调用方法:
    '          OpenExcel (excelSH, "Test Data","C:\Documents and Settings\Administrator\Desktop\Test_Data.xls")
    ' @Version 1.0           
    ' @Version
    '*********************************************************************************************
    Function OpenExcel (byRef excelSH, filePath, sheetName)
    On Error Resume Next
    Set excelApp = CreateObject("Excel.Application")
    excelApp.Visible = True
    Set excelWK = excelApp.Workbooks.Open(filePath)
    Set excelSH = excelWK.Worksheets(sheetName)
    On Error GoTo 0
    End Function

    '*********************************************************************************************
    ' 函数说明:关闭Excel应用程序;
    ' 参数说明:
    '          (1)ExcelApp:Excel应用程序名称;
    ' 调用方法:
    '           CloseExcel(ExcelApp)
    ' @Version 1.0           
    ' @Version
    '*********************************************************************************************
    Sub CloseExcel ()
    On Error Resume Next
    excelWK.Save
    excelApp.Quit
    Set excelSH = Nothing
    Set excelWK = Nothing
    Set excelApp = Nothing
    err = 0
    On Error GoTo 0

    End Sub
    提高技术的脚步从未停止过,也决不会停止。
  • 存档:假装不在^_^

    2010-06-18 12:41:03

    作者:假装不在

    很久很久以前,有一个人,路过这里.....其实他也很想说。

    我有同事做了同一个项目快4年,进项目前,项目的脚本就已经成型,而这4年里面就是跑跑脚本。4年后突然发现,原来自己学到的非常少,知道的更是少。甚至那时候就觉得自动化也就这样,很简单。

    这故事告诉我们,当接触的东西不多的时候,看外面世界的缝就越小。不要整天拿个“破”web说什么自动化也就不过如此,QTP对web的支持已经算是做得非常不错了,做起来自然很简单。但即使如此也不能说自己精通web自动化测试,不知道精通这个词是否已经被用到烂掉了,SAP Web 有试过?

    自动化先别说什么框架什么思想,先从最基础的说,自动化基础是什么?就是对象识别+对象操作。如果你框架再巨大,织布织得多厉害,连穿针引线都不会,就别说织布其实很简单。

    不说脱离QTP去干一番啥事业,就算靠着QTP也未必能把目前主流预言的程序对象征服完,试问下测试过的语言有多少种?如果说Only one,或者我觉得还是需要多些认知。4年的自动化不算什么,如果4年里都只跑跑脚本,或者都只弄同一个东西,哪其实1年的经验就等同于4年的经验,没必要说测试了多少年,经历比工作年限重要。

    我也培训新人,但我不是这么傲慢和他们说什么QTP其实没什么,很简单,什么录制回放,不耐性的说:Excel哪些到时候都去问百度谷歌吧。我说,QTP要入门简单,要学精不容易,但起码要多动自己的脑筋,这样可以让你学习进步得更快。我和他们说,在企业里,老板看中的是你能剥削的价值和可替代性。因为为了能被剥削,你就要去学点自动化,如果自动化都不会,你连被剥削的权利都没有;因为为了不可替代性,需要的是研究研究再研究,拓展拓展再拓展。不要再哪里撞个3 4年钟出去了还是2 3年前一样。你的敌人永远在读书,如果今天不走,明天就要用跑的。

    最后总结的,知道得越多,越觉得自己无知!如果自己没发现自己无知,哪就应该去多看看外面的世界。学习自动化不要停下来,遇到瓶颈的时候可以试着帮别人去解决问题,或者静心思考自己还能做什么,是因为你不敢去想,不敢去发挥创意,才会有瓶颈的出现!

    我的测试博客:http://www.51testing.com/?uid/174770
    MSN:luchenzhi@hotmail.com
    M群:group283284@msnzone.cn
    热烈欢迎大家讨论自动化难题与QTP问题
  • 左/右联接查询区别

    2010-04-06 11:33:53

    2.操作实例

    表A记录如下:
    aID               aNum
    1                  a20050111
    2                  a20050112
    3                  a20050113
    4                  a20050114
    5                  a20050115

    表B记录如下:
    bID               bName
    1                   2006032401
    2                  2006032402
    3                  2006032403
    4                  2006032404
    8                  2006032408


    实验如下:
    1.left join

    sql语句如下:
    select * from A
    left join B
    on A.aID = B.bID

    结果如下:
    aID               aNum                          bID                  bName
    1                   a20050111                1                      2006032401
    2                   a20050112                2                     2006032402
    3                   a20050113                3                     2006032403
    4                   a20050114                4                     2006032404
    5                   a20050115                NULL              NULL
    (所影响的行数为 5 行)

    结果说明:
    left join是以A表的记录为基础的,A可以看成左表,B可以看成右表,left join是以左表为准的.
    换句话说,左表(A)的记录将会全部表示出来,而右表(B)只会显示符合搜索条件的记录(例子中为: A.aID = B.bID).
    B表记录不足的地方均为NULL.

    2.right join
    sql语句如下:
    select * from A
    right join B
    on A.aID = B.bID
    结果如下:
    aID               aNum                          bID                  bName
    1                   a20050111                1                      2006032401
    2                   a20050112                2                     2006032402
    3                   a20050113                3                     2006032403
    4                   a20050114                4                     2006032404
    NULL           NULL                          8                     2006032408
    (所影响的行数为 5 行)
    结果说明:
            仔细观察一下,就会发现,和left join的结果刚好相反,这次是以右表(B)为基础的,A表不足的地方用NULL填充.


    3.inner join
    sql语句如下:
    select * from A
    innerjoin B
    on A.aID = B.bID

    结果如下:
    aID               aNum                          bID                  bName
    1                   a20050111                1                      2006032401
    2                   a20050112                2                     2006032402
    3                   a20050113                3                     2006032403
    4                   a20050114                4                     2006032404

    结果说明:
            很明显,这里只显示出了 A.aID = B.bID的记录.这说明inner join并不以谁为基础,它只显示符合条件的记录.  

  • 穷人家的孩子一定要成功!(李阳)

    2010-04-02 09:57:29

     
    The future of China depends on us!
    中国的未来由我们决定。
    We cannot afford to waste our lives!
    我们的生命浪费不起!
    We must do as much as we can, as soon as we can!
    我们必须全力以赴!
     
           今天晚上,李阳和大家分享了一些观点:
       一、大多数人做的事不一定是对的!
    The things that the majority do are not necessarily correct!
       二、时光不会倒流!要抓住当下的每一分钟苦练英语!
       三、跪下来读英语,是为了将来让世界在我面前下跪。
       四、只要不饿死,就能改变这个世界。
       五、穷人家的孩子没有自卑和堕落的权力。
       六、在最短的时间里读最多的次数,你就可以超越千万人!
       七、笑话你的人越多,成功的速度越快。
       八、不成功的原因是自己不够穷!
       九、随时随地提醒自己:我还可以更努力、更出色!
       十、成功的秘诀就是拥有可以和这个世界交换的能力。
     
        The reason you're not successful is that you are not poor enough. You're not faced with constant hardship and struggle. Poor people have no reason to feel frustrated and hopeless. The only choice they have is to work incredibly hard to rise above their poverty.
         亲爱的朋友们,请把上面这段话脱口而出!
  • 服务器的备份

    2010-03-23 21:56:12

    服务器冗余备份原理:

    DRBD (Distributed Replicated Block Device) 是 Linux 平台上的分布式储存系统。其中包含了核心模组,数个使用者空间管理程式及 shell scripts,通常用于高可用性(high availability, HA)丛集。DRBD 类似磁盘阵列的RAID 1(镜像),只不过 RAID 1 是在同一台电脑内,而 DRBD 是透过网络。它允许您在远程机器上建立一个本地块设备的实时镜像。与心跳连接结合使用,它可打造出高可用性的Linux 集群。

    DRBD 是以 GPL2 授权散布的自由软件。 http://www.turbolinux.com.cn/turbo/wiki/doku.php?id=%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86:drbd%E7%9A%84%E4%BD%BF%E7%94%A8

    Heart Bit

  • 【转】一组合理的测试策略:

    2010-03-07 16:56:51

    一组合理的测试策略:

    1.如果规格说明中包含输入条件组合的情况,应首先使用因果图分析方法.

    2.在任何情况下都应使用边界值分析方法.应记住,这是对输入和输出边界进  行的分析.边界值分析可以产生一  系列补充的测试条件.

    3.应为输入和输出确定有效和无效等价类,在必要情况下对上面确认的测试用  例进行补充.

    4.使用错误猜测技术增加更多的测试用例.

    5.针对上述测试用例集检查程序的逻辑结构.应使用判定覆盖,条件覆盖,判定  /条件覆盖或多重条件覆盖准则 (最后一个最为完整)

  • 【转】将因果图转化为判定表--3个实例

    2010-03-07 16:36:40

    一、使用因果图的好处

    1 考虑了多个输入之间的相互组合、相互制约关系

    2 能够帮助我们按一定步骤,高效率地选择测试用例,同时还能为我们指出,程序规格说明描述中存在着什么问题

    二、利用因果图导出测试用例需要经过的一般步骤

    1.分析程序规格说明的描述中,哪些是原因,哪些是结果。

    2.分析程序规格说明的描述中语义的内容,并将其表示成连接各个原因与各个结果的因果图

    3.在因果图上使用若干个特殊的符号标明特定的约束条件

    4.把因果图转换成判定表

    5.把判定表中每一列表示的情况写成测试用例
    三、因果图基本符号

     

     

    补充概念解释:

    1) 关系

    ① 恒等:若ci是1,则ei也是1;否则ei为0。

    ② 非:若ci是1,则ei是0;否则ei是1。

    ③ 或:若c1或c2或c3是1,则ei是1;否则ei为0。“或”可有任意个输入。

    ④ 与:若c1和c2都是1,则ei为1;否则ei为0。“与”也可有任意个输入。

    2) 约束

    输入状态相互之间还可能存在某些依赖关系,称为约束。例如, 某些输入条件本身不可能同时出现。输出状态之间也往往存在约束。在因果图中,用特定的符号标明这些约束。

    四、因果图实例讲解(一)

    某软件规格说明中包含这样的要求:
    第一列字符必须是A或B,第二列字符必须是一个数字,在此情况下进行文件的修改。但如果第一列字符不正确,则给出信息L;如果第二列字符不是数字,则给出信息M。

    分开原因和结果

    原因:1----第一列字符是A;
    2----第一列字符是B;
    3----第二列字符是一数字。
    结果:21----修改文件;
    22----给出信息L;
    23----给出信息M。

     

    3) 根据因果图建立判定表。

    表中8种情况的左面两列情况中,原因①和原因②同时为1,这是不可能出现的,故应排除这两种情况。表的最下一栏给出了6种情况的测试用例,这是我们所需要的数据。

    2. 有一个处理单价为5角钱的饮料的自动售货机软件测试用例的设计。其规格说明如下:若投入5角钱或1元钱的硬币,押下〖橙汁〗或〖啤酒〗的按钮,则相应的饮料就送出来。若售货机没有零钱找,则一个显示〖零钱找完〗的红灯亮,这时在投入1元硬币并押下按钮后,饮料不送出来而且1元硬币也退出来;若有零钱找,则显示〖零钱找完〗的红灯灭,在送出饮料的同时退还5角硬币。

    1) 分析这一段说明,列出原因和结果

    原因:

    1.售货机有零钱找

    2.投入1元硬币

    3.投入5角硬币

    4.押下橙汁按钮

    5.押下啤酒按钮

    结果:

    21.售货机〖零钱找完〗灯亮

    22.退还1元硬币

    23.退还5角硬币

    24.送出橙汁饮料

    25.送出啤酒饮料

    2) 画出因果图,如图所示。所有原因结点列在左边,所有结果结点列在右边。建立中间结点,表示处理的中间状态。中间结点:

    11. 投入1元硬币且押下饮料按钮

    12. 押下〖橙汁〗或〖啤酒〗的按钮

    13. 应当找5角零钱并且售货机有零钱找

    14. 钱已付清

    3) 转换成判定表:

    4) 在判定表中,阴影部分表示因违反约束条件的不可能出现的情况,删去。第16列与第32列因什么动作也没做,也删去。最后可根据剩下的16列作为确定测试用例的依据。

    以中国象棋中走马的测试用例设计为例学习因果图的使用方法。

    一、 分析中国象棋中走马的实际情况(下面未注明的均指的是对马的说明)
    1、如果落点在棋盘外,则不移动棋子;2、如果落点与起点不构成日字型,则不移动棋子;3、如果落点处有自己方棋子,则不移动棋子;4、如果在落点方向的邻近交叉点有棋子(绊马腿),则不移动棋子;5、如果不属于1-4条,且落点处无棋子,则移动棋子;6、如果不属于1-4条,且落点处为对方棋子(非老将),则移动棋子并除去对方棋子;7如果不属于1-4条,且落点处为对方老将,则移动棋子,并提示战胜对方,游戏结束。

    二、 根据分析明确原因和结果

    原因:
    1、 落点在棋盘上;
    2、 落点与起点构成日字;
    3、 落点处为自己方棋子;
    4、 落点方向的邻近交叉点无棋子;
    5、 落点处无棋子;
    6、 落点处为对方棋子(非老将);
    7、 落点处为对方老将。
    结果:
    21、不移动棋子;
    22、移动棋子;
    23、移动棋子,并除去对方棋子;
    24、移动棋子,并提示战胜对方,结束游戏。

    添加中间节点11,目的是作为导出结果的进一步原因,简化因果图导出的判定表

    考虑结果不能同时发生,所以对其施加唯一约束O。原因5、6、7不能同时发生,所以对其施加异约束E.

    根据因果图建立判定表:(分为两表)

     

    注:1、以上判定表中由于表格大小限制没有列出最后所选的测试用例;2、第2表中部分列被合并表示不可能发生的现象;3、通过中间节点将用例的判定表简化为两个小表。减少工作量。

  • 【转】如何在应聘职位前准备可能面试到的内容?

    2010-03-07 16:19:02

    原文地址http://bbs.51testing.com/viewthread.php?tid=182451&page=2#pid1427669

    由 Christina_LL 于 2010-2-25 22:48 编辑 ]

    一、做好充分的准备

    如果打算换工作,应该提前一或者半年做准备工作,一般情况我是不赞成换工作的。但是如果确实不适合现在的工作,不换不得已,那就只能走了,适时地放弃意味着又一次选择,探明此路不通的努力远非白费。既然因为不得已离开现在的工作,那就给自己的工作做个总结,吸取教训,首先问问自己一下的问题,自己回答清楚了再离开,不然很可能就要频繁的换工作了。

    1、为什么离开这家公司

    就像我,因为身体吃不消不得已离开以前的公司,所以我再找工作的时候就首先本着可持续发展的道路,工作时间一定要合理。

    2、知己知彼

    我在这家公司学到了什么,有什么经验可作为找新工作的资本,只有考虑清楚了这些,才能在面试的时候展示自己的亮点,有了亮点才能让招聘者认可你。知己知彼首先要知己,知己才能知道目标,也就是知彼此,才能百战不殆。除了知已,还要清楚自己以后的发展方向,在哪个领域,做个长期的打算。有句话说,有志人立长志,无志人常立志。相信大家都想做个有志的人,那就从实际做起吧。

    3、我还需要学习什么

    如果你的实力不足以让你找到一份满意的工作,那么从现在开始为自己充电吧。

    4、我是冲动吗

    自己是因为冲动离开现在的公司吗,冲动是魔鬼。

    二、面试技巧

    1、认真对待每次面试

    在面试的时候,把每次机会都当成最后一次机会,珍惜这个机会。当有很多机会的时候,才可以去挑选。如果机会溜走了,就没得挑选了。我就是拿了好几份offer的。

    2、面试时怎么说话

    首先说话要清晰,可能好多人觉得这个很easy,觉得我口齿很清晰呀。口齿清晰的人不一定能说话清晰,不一定能表达清楚自己的意思。怎么做到说话清晰呢?首先,还是要知己知彼,就像是两个很好的朋友,用几个简单的词就能清楚的表达自己的意思,但是碰到陌生人,用很长的一大段也说不清,这个例子想说的是文化的差异,如果是与外国人面试,就更要多研究研究文化的差异了。还有就是语言的差异,就像芬兰人会把/t/当成/d/,/p/当成/b/,如果不清楚这些,很难交流的。说话清楚了,对方就能感知你的意思了。然后要思路清晰,这是表达你的交流能力的,很多人会在简历中写道,很强的交流能力,如果在面试的时候表达都没条例,何谈很强的交流能力。还有就是说话大声、清晰,否则会显得你很羞涩,或者没经过场,是面试又不是相亲,是展露自己才华的时候。要想说话大声、清晰首先要消除心理障碍,不要怕。就算面试官很牛又怎么样呢,不然他就不会来面试你了,归根结底都是人,没什么好怕的,坦诚对待一切。

    3、坦诚

    面试是一个让面试官了解你的过程,你有的才能,不用谦虚地掩盖;你没有的才能,也不用编造。人才是德才兼备的人。小事靠才,大事靠德。所以建议展示真是的自己。

    4、巧答技术问题

    对于面试官提出的技术性问题,如果你只讲理论,面试官会以为你不懂实际;如果你只说实际的东西或者例子,面试官会以为你理论基础不扎实;所以最好的策略是,先讲理论,然后举例子。不建议先举例子,再讲理论。老师再学校讲课通常是先举例子,然后将理论,因为老师面对的是学生。而现在我们面对的是面试官,面试官是明知故问的。

    5、巧答发散思维问题

    对于这样的问题,首先分类,然后一一作答。比如,你喜欢什么样的交流方式,MSN,e-mail,面对面地交谈,还是电话?你说喜欢任何一个都显示你有某方面的不足,你如果选择MSN,表现了你不擅于与人面对面的交流,逻辑思维不强(不然可能用e-mail);如果你选择了电话,你是否考虑到公司的财政;......。

    6、分析问题

    除了技术型的问题,面试官还会问很多其他的问题,当听到这些问题时,首先要清楚面试官的目的是什么,大多数的答案是多选或者单选型的,相信每个人都知道善恶美丑,选什么样的选项不是个问题。只有知道了面试官的目的,才能给面试官想要的结果。不然就像面试官展示了你理解力不强的弱项。

    7、怎么说怎么圆

    不管自己说什么,都要给出合适的理由,以理服人。是是非非,有理就行。所以一定要解释理由,但是不是强词夺理,要合理的理由,有理有据。

    结束语

    最后祝愿大家找到理想的工作!

  • 【转】传说中的敏捷开发?

    2010-03-07 16:10:45

    原文地址:

    http://www.huawei.com/cn/publications/view.do?id=5807&cid=11119&pid=87

    1.办公室大变样

    原来背对背而坐的开发人员,也转过身来,8、9个人环绕一张长椭圆桌而坐,每个敏捷小区四边的“敏捷墙”都设置了很多白板、柜子,柜子面板也可当白板使用,每日早上小组成员采用站会的形式快速对整体迭代计划进行回顾审视,沟通。

    办公位的变化,反映了敏捷关于“团队”的理念——“以激发团队潜能为手段创造更高价值”。其本质是为了触发大家沟通的主动性,营造团队追求最佳的氛围,更好激发起个人和团队的能力。要发自内心的转变,不要抵触,实际操作中并不一定要求彻底改变办公位。 

    2.工作模式的改变

    改变了既有的瀑布式软件开发模式。敏捷开发要求每个团队在敏捷三大理念(价值、团队、自适应)指导下,通过聚焦客户价值、开发过程可视化,管理轻量化以及迭代,并选择适合自己的业界优秀实践加以应用(如持续集成、开发测试拉通、迭代、可视化管理、自动化测试、站立会议等等),不断的迭代增量开发,以最终交付符合客户价值的产品。 

  • 【转】如何能得到一些国内或国外大公司的测试职位?

    2010-03-02 13:47:18

    精彩答案:

    会员 戒情人 :

      1. 业务。如果你在一个行业做了多年,对这个行业的业务非常熟悉了,这绝对是一个大优势。公司无论国内国外,无论大公司小公司,在招聘时都会注明有相关行业经验优先。行业经验不是一朝一夕就能得到的,是一个长时间的积累过程。你有相关的行业经验,工作就很容易上手,而且做出成绩。有些公司招人时,对有相关的行业经验这一条是必须条件。比如复杂业务的电信行业(当然不是每个公司都是)。

      2. 学历。出身很重要的。虽然很多公司都表明更看中能力,但其实他们还是很看重你的学历的。重点大学或者研究生、博士,更容易获得好公司的青睐。

      3. 技术。大公司做测试,不单单要求能做黑盒测试,如果你擅长自动化,擅长编码,就自然而然的增加了自己的优势。

      4. 英语。好的公司都是很看重英语能力的,因为很多帮助文档,技术文档都是英文的。你英文不好,公司不会相信你有很好的能力和潜力。

    ------------------------------我需要加强的地方:-----------------

    1.业务领域的资历不深,需要专注在某一个领域,以至精通于该领域的业务

    2.技术基础不够,需要继续学习oracle,linux系统,精通这些最基础的技术。在测试工具和测试架构方面尚待提高

    3.在于人沟通方面,增进与人沟通,协调人际关系的能力

    4.英语方面需更地道和娴熟

  • 敏捷开发&自动化测试

    2010-01-15 22:10:20

    jimmyseraph发表的一些关于敏捷开发和自动化测试言论。受教了

    1)为什么敏捷开发能应对需求的不断变化?因为它实现了小粒度交付,把最稳定的用户需求先做出来.测试也先测最稳定的。

    敏捷的前提条件:特性间的耦合性要弱,每个特性能独立交付能力。表象层(界面)与处理层解藕,有了界面就可以做测试。

    开发人员需要做到的:程序员要编写结构化的代码。“面向对象”、“抽象”、“虚函数、虚类”、“接口”、“mock”技术?这是一种趋势,程序语言一直在试图让函数、功能、特性更独立,更方便应对需求变更(我们都知道,接口设计是一个非常好的应对需求变更的技术)。

    测试人员要做到的:自动化测试也起到推动的作用,推动研发合理设计,让代码的可测性提高,同时也就自然而然提升了质量。自动化测试绝不仅仅是用LR或者QTP去录脚本,测试人员要对写测试脚本非常熟练,只会做功能层面的手工测试是没有发展前途的。

    2)自动化测试的缺点和优点:自动化测试薄弱的地方是对复杂场景的模拟,其优点是:对需求的覆盖比手工测试更全面,效率更高

    3)自动化测试的范畴:测试人员和开发人员都可以自动化测试,单元测试也可以自动化测试,如:VS2005开始就内嵌了这一块功能,方便开发人员随时写随时测。写一个自动化用例,写一小段代码运行一下,这就是代码和用例同时演进的TDD方式。

     

  • For the past 2009

    2010-01-09 14:11:17

    Havn't been here for long time. So shame for the past 2009, no much progress, worried of the future and job, and sad for the actuality most time, the worst was no peace heart. Terrible 2009.

    Most time i couldn't think clearly of myself, what's my plan? where do you want to go? what do you should do now? I was so eager for quick success with no hard working.

    I was lazy and pessimistic most time, I need a change fom now on. Life should not be throughn like my past, I should fill the progress with wish and happiness to make it a meaning experience. I want the people who loves being happy too.Wish the best me in 2010.

241/212>
Open Toolbar