字符串数组

来源:互联网 发布:网络用语和谐 编辑:程序博客网 时间:2024/05/29 04:53

1. char *str[] = {"a", "bbbb"} 比char str[][5] = {"a", "bbbb"} 更省内存

2. int main(int argc, char *argv[])命令行参数的使用

===============================================================================

13.7 字符串数组

现在来看一个在使用字符串时经常遇到的问题:存储字符串数组的最佳方式是什么?最明显的解决方案是创建二维的字符数组,然后按照每行一个字符串的方式把字符串存储到数组中。考虑下面的例子:

char planets[][8] = {"Mercury", "Venus", "Earth",

                         "Mars", "Jupiter", "Saturn",

                         "Uranus", "Neptune", "Pluto");

虽然允许省略planets数组中行的个数(因为这个数很容易从初始化式中元素数量求出),但是C语言要求说明列的个数。下面是数组可能的形式:


不是所有的字符串都足够填满数组的一整行,所以C语言用空字符来填补。因为只有3个行星名字达到8个字符的长度要求(包括末尾的空字符),所以这样的数组有一点浪费空间。remind.c程序(13.5节)就是这种浪费的代表,它把提醒信息按行存储到二维字符数组中,且为每条提醒信息都分配了60个字符的空间。在示例中,提醒信息的长度范围是在14个字符到33个字符之间,所以浪费的空间数量相当可观。

          因为大部分字符串集都是长短字符串的混合,所以这些例子所暴露的低效性是在处理字符串时经常遇到的问题。我们需要的是参差不齐的数组(ragged array),即数组的每一行有不同的长度。C语言本身不提供这种“参差不齐的数组类型”,但它确实提供了模拟这种数组类型的工具。秘诀就是建立一个特殊的数组,这个数组的元素都是指向字符串的指针。

下面是planets数组的另外一种写法,这次看成是指向字符串的指针的数组:

char *planets[] = {"Mercury", "Venus", "Earth",

                        "Mars", "Jupi ter", "Saturn",

                        "Uranus", "Neptune", "Pluto");

改动不是很大,只是简单去掉了一对方括号,并且在planets前加了一个星号。但是这对planets存储方式产生的影响却很大:


planets的每一个元素都指向以空字符结尾的字符串的指针。虽然必须为planets数组中的指针分配空间,但是字符串中不再有任何浪费的字符。

          为了访问其中一个行星名字,只需要给出planets数组的下标。访问行星名字中的字符的方式和访问二维数组元素的方式相同,这都要感谢指针和数组之间的紧密关系。例如,为了在planets数组中搜寻以字母M开头的字符串,可以使用下面的循环:

for (i = 0; i < 9; i++)

if (planets [i] [0] == 'M')

    printf("%s begins with M\n", planets[i]);

13.7.1 命令行参数命令行参数

在运行程序时,会经常需要提供一些信息——文件名或者是改变程序行为的开关。考虑UNIX的ls命令。如果我们按如下显示方式运行ls

ls

将会显示当前目录中的文件名。(对应的DOS命令是dir。)但是如果替换成

ls –l

那么ls会显示一个“很长的”(详细的)文件列表,包括显示每个文件的大小、文件的所有者、文件最后改动的日期和时间等。为了进一步改变ls的行为,可以指定只显示一个文件的详细信息:

ls –l remind.c

ls将会显示文件名为remind.c的详细信息。

不仅是操作系统命令,所有程序都有命令行信息。为了能够访问这些命令行参数(command-line argument)(标准中称为程序参数),必须把main函数定义为含有两个参数的函数,这两个参数通常命名为argc和argv:

main(int argc, char *argv[])

{

...

}

argc(“参数计数”)是命令行参数的数量(包括程序名本身)。argv(“参数向量”)是指向命令行参数的指针数组,这些命令行参数以字符串的形式存储。argv[0]指向程序名,而从argv[1]到argv[argc-1]则指向余下的命令行参数。

argv有一个附加元素,即argv[argc],这个元素始终是一个空指针。空指针是一种不指向任何内容的特殊指针。后面的章中会讨论空指针(字符串数组&main参数使用17.1.2节)。但是目前只需要知道宏NULL代表空指针就够了。

如果用户输入了下列命令行:

ls –l remind.c

那么argc将为3,argv[0]将指向含有程序名的字符串,argv[1]将指向字符串"-l",argv[2]将指向字符串"remind.c",而argv[3]将为空指针:


这幅图没有详细说明程序名,因为在不同的操作系统上程序名可能会包括路径或其他信息。如果程序名不可用,那么argv[0]会指向空字符串。

因为argv是指针数组,所以已经知道访问命令行参数的方法了。典型做法是,期望有命令行参数的程序将会设置循环来按顺序检查每一个参数。设定这种循环的方法之一就是使用整型变量作为argv数组的索引。例如,下面的循环每行一条地显示命令行参数:

int i;

for (i=1; i<argc; i++)

printf("%s\n", argv[i]);

另一种方法是构造一个指向argv[1]的指针,然后对指针重复进行自增操作来逐个访问数组余下的元素。因为数组的最后一个元素始终是空指针,所以循环可以在找到数组中第一个空指针时停止:

char **p;

for (p = &argv[1]; *p != NULL; p++)

printf("%s\n", *p);

因为p是指向字符指针的指针,所以必须小心使用。把p设为&argv[1]是很有意义的,因为argv[1]是一个指向字符的指针,所以&argv[1]就是指向指针的指针了;因为*p和NULL都是指针,所以测试*p!= NULL是没有问题的;对p进行自增操作看起来也是对的因为p指向数组元素,所以对它进行自增操作将使p指向下一个元素;显示*p的语句也是合理的,因为*p是一个指向字符的指针。

13.7.2 程序:核对行星的名字

下一个程序planet.c举例说明了访问命令行参数的方法。设计此程序的目的是为了测试一系列字符串,从而找出哪些字符串是行星的名字。程序执行时,用户将把测试的字符串放置在命令行中:

planet Jupiter venus Earth fred

程序会指出每个字符串是否是行星的名字。如果是,程序还将显示行星的编号(把最靠近太阳的行星编号为1):

jupiter is planet 5

venus is not a planet

Earch is planet 3

fred is not a planet

注意,除非字符串的首字母大写并且其余字母小写,否则程序不会认为字符串是行星的名字。

planet.c

 

#include <stdio.h>

#include <string.h>

#define NUM_PLANETS 9

main(int argc, char *argv[])

{

char *planets[] = {"Mercury", "Venus", "Earth",

                         "Mars", "Jupiter", "Saturn",

                         "Uranus", "Neptune", "Pluto"};

int i, j;

for (i = 1; i < argc; i++) {

    for (j = 0; j < NUM_PLANETS; j++)

      if (strcmp(argv[i], planets[j]) == 0) {

         printf("%s is planet %d\n", argv[i], j+1);

        break;

      }

    if (j == NUM_PLANETS)

      printf("%s is not a planet\n", argv[i]);

}

return 0;

}

程序会依次访问每个命令行参数,把它与planets数组中的字符串进行比较,直到找到匹配的名字或者到了数组的末尾才停止。程序中最有趣的部分是调用strcmp函数,此函数的参数是argv[i](指向命令行参数的指针)和planets[j](指向行星名的指针)。

来自:http://blog.sina.com.cn/s/blog_7c50857d0100yidx.html