LCC-win32与C编程简介(4)

1.5 给程序传递参数

  我们不能使用参数干涉上面那个hello程序的操作.我们没有办法通过参使程序显示别的字符串作为例子,我们只能通过修改代码: “hello\n”来达到目的.我们甚至于不能让程序不输入回车.
通常程序从它们的环境里获得参数.一个非常古老但行而有效的方法是通过命令行给程序传递参数,即:一系列程序可用的字符串.
让我们看看参数是怎样传递给程序的.[24]

#include <stdio.h>             (1)
int main(int argc,char *argv[])     (2)
{
int count;                   (3)
for (count=0;count < argc;count++) {   (4)
printf(                      
"Argument %d = %s\n",
count,
argv[count]);
}                           (5)
return 0;
}

  1)     我们再次包含stdio.h.
  2)     我们仍和上次一样使用“main”函数.这次使用的和上次一样是一个标准的“main”函数,只是这次我们传递了两个参数给程序:int argc 这是一个整型数据,在C里用“int”标识.它用于储存传递给程序的参数的个数.char *argv[] 这是一个指向字符的指针数组[25]用于指向用户输入的参数.如:我们从命令行调用我们的程序并使用参数“foo”和“bar”,则在argv[]数组里有:argv[0] 运行的程序的名称.
argv[1] 第一个参数,即: “foo”.
argv[2] 第二个参数,即: “bar”.
  我们使用一整型变量(argc)在内存里将用户输入的参数定位,用于控制我们当前要打印的参数.这是一个局部变量,即:一个只能用于一定范围的变量,在这个例子,这个变量只能在函数“main”中使用.[26]
  3)     我们使用“for”语句,即:一个循环控制结构. “for”语句有以下结构:
  ? 初始化.在循环开始前执行的语句.在这个例子,我们设置计数器为0.我们使用C语言的赋值操作符: “=”.这个语句的结构是:变量“=”值;
  ? 判断.每次循环前都要进行判断,决定循环是否中止.在这个例子我们判断count是否小于传给程序参数的个数,即:整数argc.
  ? 步长.每次循环后都要执行.这个例子我们使用自增表达式:counter++将计数器加1.这只是表达式counter=counter+1的简写.
  ? 注意,我们从0开始,当计数器等于循环次数的上限时停止.在C里,数组用于确定元素个数的下标n总是从0开始,直到n-1.[27]
  4)     我们再次使用printf在屏幕上打印字符.这次,我们传给printf下面的参数:
"Argument %d = ‘%s’\n"
count
argv[count]
  printf将扫描它的第一个参数.它从原样输出的文本里找出格式说明(格式说明用“%”和格式字符组成).我们在字符串里使用了两个格式说明:%d和%s.
  第一个, %d意为第一个由参数传入的输出项将在这个位置按10进制整数形式输出.这里即是字符串后的整型数据“count”,它的值将在这个位置输出.
  第二个, %s意为第二个由参数传入的输出项在这个位置按字符串形式输出.这里则是在数组argv[ ]里“count”位置的元素按字符串形式在相应位置输出.

5)     我们用一对花括号把语句括起来.这意味着迭代在这里结束.

现在我们准备运行这个程序.假定我们的程序源代码在文件“args.c”.按如下操作:
h:\lcc\projects\args> lcc args.c
h:\lcc\projects\args> lcclnk args.obj
我们先用Lcc编译程序将文本文件编译生成一个目标文件,然后用连接程序lcclnk将目标文件包含在一个可执行文件里.现在可以键入程序的名称运行程序了:[28]
h:\lcc\projects\args> args
Argument 0 = args
  我们没有使用参数,故只显示argv[0],即程序的名称,这里的例子是“args”.如果这样键入:
h:\lcc\projects\args> args.exe
Argument 0 = args.exe
或这样:
h:\lcc\projects\args> h:\lcc\projects\args.exe
Argument 0 = h:\lcc\projects\args.exe
  但没有程序的目标.这样就有趣了:
h:\lcc\projects\args> args foo bar zzz
Argument 0 = args
Argument 1 = foo
Argument 2 = bar
Argument 3 = zzz
  程序接受到3个参数,因此argc的值是4.则我们的变量计数将从0运行到argc-1,显示 4个参数:第0个,每1个,每2个等等.
1.5.1 循环控制结构
  上面介绍了“for”结构,但有必要在这里介绍和理解下面的几个循环控制语句.在C语言里有3个循环控制结构: “for”, “do”, 和 “while”.

1.5.1.1 for
  “for”结构有:
  ? 初始化部分,即:在循环开始前就执行的语句.
  ? 判断部分,即:每次循环开始前都要执行判断循环是否终止的语句.
  ? 步长部分,即:每次循环结束时都要执行的语句.通常循环计数器在这里增加或减少.
  表达方式为:
for(初始化表达式;判断表达式;步长) {
    语句块
  }
  在一个for语句里,你可以为for循环定义一个局部变量.这个变量的作用域在for语句结束时消失.如:

#include <stdio.h>
int main(void)
{
  for (int i = 0; i< 2;i++) {
  printf("outer i is %d\n",i);
  for (int i = 0;i<2;i++) {
  printf("i=%d\n",i);
}
}
  return 0;
}
The output of this program is:
outer i is 0
i=0
i=1
outer i is 1
i=0
i=1
  注意,在for里声明的‘i’标识也在for语句结束时其作用域消失,而下一个for语句里的‘i’是一个新的‘i’.把上面的例子作如下修改:
#include <stdio.h>
int main(void)
{
  for (int i = 0; i< 2;i++) {     1
  printf("outer i is %d\n",i); 2
  int i = 87;
  for (int i = 0;i<2;i++) {     4
  printf("i=%d\n",i);           5
}                     6
}                     7
return 0;               8
}

  在循环的最里面将有三个标识名称为: ‘i’.
  ? 第一个‘i’是外面的‘i’.其作用域为第1行至第7行.
  ? 第二个‘i’(87)是一个复合语句里的一个局部标识,作用域从第1行至第7行. 在复合语句里常常定义局部变量.
  ? 第三个‘i’是在第二个for语句里声明的.其作用域为第4行至第6行.
  注意,相同名称的标识在重叠的作用域里,外面的标识将被里面的标识屏蔽.这也是你在C语言里所期望的.

1.5.1.2 while
“while”结构则相对比较简单.它由单一的判断决定循环体是否结束循环.没有初始化部分,也没有步长部分.

表现形式:
while (判断表达式) {
    语句块
  }
  任何一个“for”循环可以转换成一个“while”循环:
初始化表达式
  while (判断表达式) {
    语句块
    步长
  }

1.5.1.3 do
  一个“do”结构只是while结构的另一种表现方式.但循环体在判断前执行一次,也就是说其循环体至少执行一次.它的表现形式是:
do {
    语句块
  } while (判断表达式);
  “continue”关键字用在循环语句中,作用为结束本次循环,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判断.循环正常的继续进行,只是夹在关键字与循环体末之间的语句被忽略.

1.5.2 基本数据类型
    Lcc-win32内部定义如下的C语言数据类型[29]:所有类型都是ANSI C语言的一部分.只有类型_Complex则例外,它只出现在大部分的C语言编译程序中,但出现在全部的Windows编译程序里.[30]
类型      大小      描述
_Bool*      1      逻辑型,不是0就是1
char      1      字符型. 有两个修饰符: signed(有符号) 和 unsigned(无符号).
short      2      16位的短整型. signed 和 unsigned.
int      4      32位整型. signed 和 unsigned.
long      4      和int相同
long long      8      64位整型. signed 和 unsigned.
float      4      单精度浮点型. (约 7 位有效位)
double      8      双精度浮点型. (约15位有效位)
long double      12      扩展精度浮点型. (约20位有效位)
flat_Complex
double_Complex
long
double_Complex
     8
16
24      复数.每一个_Complex由两部分组成:实数与虚部分.每个部分是一个浮点数.使用它们前需包含<complex.h>.

*实际上布尔类型(Boolean type)应该是: “bool”,但为了与已经使用了的代码相兼容,现在还没有这种类型的命名标准.如果你想使用bool,你要包含头文件“stdbool.h”.

      这些都是Lcc-win32的基本数据类型.还存在其它的一些数据类型.要使用它们要包含相应的头文件,它们没有“内建”在编译程序里.它们是使用编译程序的一个允许定义属你自已的数据类型这一选项的功能来构造的.
类型      头文件      大小      描述
qfloat      qfloat.h      56      350位浮点数
bignum      bignum.h      可变      扩展精度数字

1.5.3 小结
  1)     通常函数接受参数,并返回结果.函数的类型可以在声明或定义函数时在函数名称前面声明.
  2)     “main”函数可以从它的调用环境获得参数.
  3)     在我们使用标识符前都在向编译程序声明类型.

[24] 这里我们只描述Lcc-win32里两种传递参数方法中的ANSI C标准的方式.在Windows系统,有另一个可选择的入口,名为:WinMain,但它的参数与这里描述的有所不同.详情可参考本教程的Windows编程相关章节.
[25] 这就意味着你接受的是一个保存参数字符串的数组的起始地址.在该指针数组的第一个元素我们可以找到一个整数,其为程序名字字符串在内存中的起始地址.关于其中的细节我们将在与指针处理相关的章节描述.
[26] 局部函数如此声明(和其它变量的声明一样):
<type> 标识符;
如:
int a;
double b;
char c;
数组的声明使用同样的方式,只是多了一个用方括号括起来的代表数组大小的数字:
int a[23];
double b[45];
char c[890];
[27] 一个初学者常犯的错误是循环计数从1开始到它的值与上限相等.当然,如果你不用数组的下标作为循环控制这没有什么不妥,但在若是使用下标访问数组(通常是这种情况)时则会让程序在循环里访问无效的内存空间.
[28] 当编译时会发生操作在Lcc-win32的技术文档里有详细描述.在新的Lcc-win32版本里,你可以用编译程序‘lc.exe’,它将自动调用连接程序.
[29] 在大多数的编译器里char/short/int/long类型的大小可以在不同的机器间相适应.一些嵌入式系统的编译器不支持浮点.很多编译器不支持新类型_Bool,long long和long double.据我所知,在所有的Windows环境的32位编译程序,类型 char/short/int/long/float/double是与之相同的.
[30] Microsoft Visual C把“long double”作为double来处理,并将类型long long称为: “_int64”.为与Visual C兼容,Lcc-win32认为_int64与类型long long同意义.

 

作者:Vitamin C   更新日期:2004-12-23
来源:c-sea.net   浏览次数:

相关文章

相关评论   发表评论