浅析C语言中的数组及字符数组

 更新时间:2020年4月25日 17:37  点击:1300

我们来编写一个程序,以统计各个数字、空白符(包括空格符、制表符及换行符)以及所有其它字符出现的次数。这个程序的实用意义并不大,但我们可以通过该程序讨论 C 语言多方面的问题。

所有的输入字符可以分成 12 类,因此可以用一个数组存放各个数字出现的次数,这样比使用 10 个独立的变量更方便。下面是该程序的一种版本:

#include <stdio.h>
/* count digits, white space, others */
main()
{
 int c, i, nwhite, nother;
 int ndigit[10];
 nwhite = nother = 0;
 for (i = 0; i < 10; ++i)
 ndigit[i] = 0;
 while ((c = getchar()) != EOF)
 if (c >= '0' && c <= '9')
  ++ndigit[c-'0'];
 else if (c == ' ' || c == '\n' || c == '\t')
  ++nwhite;
 else
  ++nother;
 printf("digits =");
 for (i = 0; i < 10; ++i)
  printf(" %d", ndigit[i]);
 printf(", white space = %d, other = %d\n", nwhite, nother);
}

当把这段程序本身作为输入时,输出结果为: digits = 9 3 0 0 0 0 0 0 0 1, white space = 123, other = 345

该程序中的声明语句 int ndigit[10] 将变量 ndigit 声明为由 10 个整型数构成的数组。在 C 语言中,数组下标总是从 0 开始,因此该数组的 10 个元素分别为 ndigit[0]、ndiglt[1]、…、ndigit[9],这可以通过初始化和打印数组的两个 for 循环语句反映出来。

数组下标可以是任何整型表达式,包括整型变量(如 i)以及整型常量。

该程序的执行取决于数字的字符表示属性。例如,测试语句 if (c >= '0' && c <= '9') 用于判断 c 中的字符是否为数字。如果它是数字,那么该数字对应的数值是 c- '0' 。只有当'0'、'1'、…、'9'具有连续递增的值时,这种做法才可行。幸运的是,所有的字符集都是这样的。

由定义可知,char 类型的字符是小整型,因此 char 类型的变量和常量在算术表达式中等价于 int 类型的变量和常量。这样做既自然又方便,例如,c - '0'是一个整型表达式,如果存储在 c 中的字符是'0'~'9',其值将为 0~9,因此可以充当数组 ndigit 的合法下标。

判断一个字符是数字、空白符还是其它字符的功能可以由下列语句序列完成:

if (c >= '0' && c <= '9')
 ++ndigit[c-'0'];
else if (c == ' ' || c == '\n' || c == '\t')
 ++nwhite;
else
 ++nother;

程序中经常使用下列方式表示多路判定:
if (条件 1)
 语句 1
else if (条件 1)
 语句 2
 ...
 ...
else
 语句 n
在这种方式中,各条件从前往后依次求值,直到满足某个条件,然后执行对应的语句部分。这部分语句执行完成后,整个语句体执行结束(其中的任何语句都可以是括在花括号中的若干条语句)。如果所有条件都不满足,则执行位于最后一个 else 之后的语句(如果有的话)。类似于前面的单词计数程序,如果没有最后一个 else 及对应的语句,该语句体将不执行任何动作。在第一个 if 与最后一个 else 之间可以有 0 个或多个下列形式的语句序列:
else if (条件)
 语句
就程序设计风格而言,我们建议读者采用上面所示的缩进格式以体现该结构的层次关系,否则,如果每个 if 都比前一个 else 向里缩进一些距离,那么较长的判定序列就可能超出页面的右边界。

字符数组
字符数组是 C 语言中最常用的数组类型。下面我们通过编写一个程序,来说明字符数组以及操作字符数组的函数的用法。该程序读入一组文本行,并把最长的文本行打印出来。该算法的基本框架非常简单:
while (还有未处理的行)
if (该行比已处理的最长行还要长)
 保存该行为最长行
 保存该行的长度
打印最长的行
从上面的框架中很容易看出,程序很自然地分成了若干片断,分别用于读入新行、测试读入的行、保存该行,其余部分则控制这一过程。

因为这种划分方式比较合理,所以可以按照这种方式编写程序。首先,我们编写一个独立的函数 getline,它读取输入的下一行。我们尽量保持该函数在其它场台也有用。至少 getline 函数应该在读到文件末尾时返回一个信号;更为有用的设计是它能够在读入文本行时返回该行的长度,而在遇到文件结束符时返回 0。由于 0 不是有效的行长度,因此可以作为标志文件结束的返回值。每一行至少包括一个字符,只包含换行符的行,其长度为 1。

当发现某个新读入的行比以前读入的最长行还要长时,就需要把该行保存起来。也就是说,我们需要用另一个函数 copy 把新行复制到一个安全的位置。

最后,我们需要在主函数 main 中控制 getline 和 copy 这两个函数。以下便是我们编写的程序:

#include <stdio.h>
#define MAXLINE 1000 /* maximum input line length */
int getline(char line[], int maxline);
void copy(char to[], char from[]);

/* print the longest input line */
main()
{
 int len;
 int max;
 /* current line length */
 /* maximum length seen so far */
 char line[MAXLINE]; /* current input line */
 char longest[MAXLINE]; /* longest line saved here */
 max = 0;
 while ((len = getline(line, MAXLINE)) > 0)
 if (len > max) {
 max = len;
 copy(longest, line);
 }
 if (max > 0) /* there was a line */
 printf("%s", longest);
 return 0;
}

/* getline: read a line into s, return length */
int getline(char s[],int lim)
{
 int c, i;
 for (i=0; i < lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
 s[i] = c;
 if (c == '\n') {
 s[i] = c;
 ++i;
 }
 s[i] = '\0';
 return i;
}

/* copy: copy 'from' into 'to'; assume to is big enough */
void copy(char to[], char from[])
{
 int i;
 i = 0;
 while ((to[i] = from[i]) != '\0')
 ++i;
}
</stdio.h>

程序的开始对 getline 和 copy 这两个函数进行了声明,这里假定它们都存放在同一个文件中。

main 与 getline 之间通过一对参数及一个返回值进行数据交换。在 getline 函数中,两个参数是通过程序行。

int getline(char s[], int lim)

声明的,它把第一个参数 s 声明为数组,把第二个参数 lim 声明为整型,声明中提供数组大小的目的是留出存储空间。在 getline 函数中没有必要指明数组 s 的长度,这是因为该数组的大小是在 main 函数中设置的。如同 power 函数一样,getline 函数使用了一个 return语句将值返回给其调用者。上述程序行也声明了 getline 数的返回值类型为 int。由于函数的默认返回值类型为 int,因此这里的 int 可以省略。

有些函数返回有用的值,而有些函数(如 copy)仅用于执行一些动作,并不返回值。copy 函数的返回值类型为 void,它显式说明该函数不返回任何值。

getline 函数把字符'\0'(即空字符,其值为 0)插入到它创建的数组的末尾,以标记字符串的结束。这一约定已被 C 语言采用:当在 C 语言程序中出现类似于

"hello\0"

的字符串常量时,它将以字符数组的形式存储,数组的各元素分别存储字符串的各个字符,并以'\0'标志字符串的结束。

printf 函数中的格式规范%s 规定,对应的参数必须是以这种形式表示的字符串。copy 函数的实现正是依赖于输入参数由'\0'结束这一事实,它将'\0'拷贝到输出参数中。 也就是说,空字符'\0'不是普通文本的一部分。

值得一提的是,即使是上述这样很小的程序,在传递参数时也会遇到一些麻烦的设计问题。例如,当读入的行长度大于允许的最大值时,main 函数应该如何处理,getline 函数的执行是安全的,无论是否到达换行符字符,当数组满时它将停止读字符。main 函数可以通过测试行的长度以及检查返回的最后一个字符来判定当前行是否太长,然后再根据具体的情况处理。为了简化程序,我们在这里不考虑这个问题。

调用 getline 函数的程序无法预先知道输入行的长度,因此 getline 函数需要检查是否溢出。另一方面,调用 copy 函数的程序知道(也可以找出)字符串的长度,因此该函数不需要进行错误检查。

[!--infotagslink--]

相关文章

  • C语言实现放烟花的程序

    这篇文章主要为大家详细介绍了C语言实现放烟花的程序,有音乐播放,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-23
  • C语言中的字符(char)详细讲解

    本篇文章主要介绍C语言中char的知识,并附有代码实例,以便大家在学习的时候更好的理解,有需要的可以看一下...2020-04-25
  • php中eval()函数操作数组的方法

    在php中eval是一个函数并且不能直接禁用了,但eval函数又相当的危险了经常会出现一些问题了,今天我们就一起来看看eval函数对数组的操作 例子, <?php $data="array...2016-11-25
  • Python 图片转数组,二进制互转操作

    这篇文章主要介绍了Python 图片转数组,二进制互转操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-09
  • 详解如何将c语言文件打包成exe可执行程序

    这篇文章主要介绍了详解如何将c语言文件打包成exe可执行程序,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-25
  • php数组操作 键名比较 差集 交集赋值

    本文章提供在量的数据中级操作实例有如对键名比较计算数组的差集 计算差集 给指定数组中插入一个元素 反转数组 交集赋值新的数组实例。 //定义回调函数 funct...2016-11-25
  • C#二维数组基本用法实例

    这篇文章主要介绍了C#二维数组基本用法,以实例形式分析了C#中二维数组的定义、初始化、遍历及打印等用法,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • php curl模拟post请求和提交多维数组的示例代码

    下面一段代码给大家介绍php curl模拟post请求的示例代码,具体代码如下: <&#63;php$uri = "http://www.cnblogs.com/test.php";//这里换成自己的服务器的地址// 参数数组$data = array ( 'name' => 'tanteng'// 'passwor...2015-11-24
  • C#数组的常用操作方法小结

    Array数组在C#中同样是最基本的数据结构,下面为大家C#数组的常用操作方法小结,皆为细小的代码段,欢迎收看收藏...2020-06-25
  • C# 拷贝数组的几种方法(总结)

    下面小编就为大家带来一篇C# 拷贝数组的几种方法(总结)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25
  • PHP 二维数组根据某个字段排序的具体实现

    本文记录的要实现的功能类似于 MySQL 中的 ORDER BY,上个项目中有遇到这样的一个需求。 要求:从两个不同的表中获取各自的4条数据,然后整合(array_merge)成一个数组,再根据数据的创建时间降序排序取前4条。 遇到这个...2014-06-07
  • C语言中free函数的使用详解

    free函数是释放之前某一次malloc函数申请的空间,而且只是释放空间,并不改变指针的值。下面我们就来详细探讨下...2020-04-25
  • C#实现字符串转换成字节数组的简单实现方法

    这篇文章主要介绍了C#实现字符串转换成字节数组的简单实现方法,仅一行代码即可搞定,非常简单实用,需要的朋友可以参考下...2020-06-25
  • C语言中计算正弦的相关函数总结

    这篇文章主要介绍了C语言中计算正弦的相关函数总结,包括正弦和双曲线正弦以及反正弦的函数,需要的朋友可以参考下...2020-04-25
  • 详解C语言中的rename()函数和remove()函数的使用方法

    这篇文章主要介绍了详解C语言中的rename()函数和remove()函数的使用方法,是C语言入门学习中的基础知识,需要的朋友可以参考下...2020-04-25
  • c#将字节数组转成易读的字符串的实现

    这篇文章主要介绍了c#将字节数组转成易读的字符串的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-25
  • C#读取文件所有行到数组的方法

    这篇文章主要介绍了C#读取文件所有行到数组的方法,涉及C#针对文件及数组的相关操作技巧,需要的朋友可以参考下...2020-06-25
  • 将二维数组转为一维数组的2种方法

    如何将下面的二维数组转为一维数组。复制代码 代码如下:$msg = array(  array(    'id'=>'45',    'name'=>'jack'  ),  array(    'id'=>'34',    'name'=>'mary'  ),  array(    'id...2014-05-31
  • C语言中求和、计算平均值、方差和标准差的实例

    这篇文章主要介绍了C语言中求和、计算平均值、方差和标准差的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-12-10
  • php中数组写入文件方法

    在php中为我们提供了一个函数var_export 他可以直接将php代码入到一个文件中哦。 代码如下 复制代码 var_export($times,true);后面不加tru...2016-11-25