热门标签 | HotTags
当前位置:  开发笔记 > 开发工具 > 正文

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

这篇文章主要介绍了C语言中的数组及字符数组,是C语言入门学习中的基础知识,需要的朋友可以参考下

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

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

#include 
/* 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 
#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 

程序的开始对 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 函数的程序知道(也可以找出)字符串的长度,因此该函数不需要进行错误检查。


推荐阅读
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 生成对抗式网络GAN及其衍生CGAN、DCGAN、WGAN、LSGAN、BEGAN介绍
    一、GAN原理介绍学习GAN的第一篇论文当然由是IanGoodfellow于2014年发表的GenerativeAdversarialNetworks(论文下载链接arxiv:[h ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 无线认证设置故障排除方法及注意事项
    本文介绍了解决无线认证设置故障的方法和注意事项,包括检查无线路由器工作状态、关闭手机休眠状态下的网络设置、重启路由器、更改认证类型、恢复出厂设置和手机网络设置等。通过这些方法,可以解决无线认证设置可能出现的问题,确保无线网络正常连接和上网。同时,还提供了一些注意事项,以便用户在进行无线认证设置时能够正确操作。 ... [详细]
  • 本文详细介绍了相机防抖的设置方法和使用技巧,包括索尼防抖设置、VR和Stabilizer档位的选择、机身菜单设置等。同时解释了相机防抖的原理,包括电子防抖和光学防抖的区别,以及它们对画质细节的影响。此外,还提到了一些运动相机的防抖方法,如大疆的Osmo Action的Rock Steady技术。通过本文,你将更好地理解相机防抖的重要性和使用技巧,提高拍摄体验。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了新款奇骏的两个让人上瘾的功能,分别是智能互联系统和BOSE音响。通过对新款奇骏的配置和功能进行评测,探讨了这两个新增功能的使用体验和优势。此外,还介绍了新款奇骏的其他配置和改进,如增加的座椅和驾驶辅助系统,以及内饰的舒适性提升。对于喜欢音响的消费者来说,BOSE音响的升级也是一个亮点。最后,文章提到了BOSE音响的数字还原能力,以及7座版无法配备BOSE音响的原因。 ... [详细]
  • 本文介绍了adg架构设置在企业数据治理中的应用。随着信息技术的发展,企业IT系统的快速发展使得数据成为企业业务增长的新动力,但同时也带来了数据冗余、数据难发现、效率低下、资源消耗等问题。本文讨论了企业面临的几类尖锐问题,并提出了解决方案,包括确保库表结构与系统测试版本一致、避免数据冗余、快速定位问题等。此外,本文还探讨了adg架构在大版本升级、上云服务和微服务治理方面的应用。通过本文的介绍,读者可以了解到adg架构设置的重要性及其在企业数据治理中的应用。 ... [详细]
  • 禁止程序接收鼠标事件的工具_VNC Viewer for Mac(远程桌面工具)免费版
    VNCViewerforMac是一款运行在Mac平台上的远程桌面工具,vncviewermac版可以帮助您使用Mac的键盘和鼠标来控制远程计算机,操作简 ... [详细]
  • 本文介绍了游戏开发中的人工智能技术,包括定性行为和非定性行为的分类。定性行为是指特定且可预测的行为,而非定性行为则具有一定程度的不确定性。其中,追逐算法是定性行为的具体实例。 ... [详细]
  • JavaScript设计模式之策略模式(Strategy Pattern)的优势及应用
    本文介绍了JavaScript设计模式之策略模式(Strategy Pattern)的定义和优势,策略模式可以避免代码中的多重判断条件,体现了开放-封闭原则。同时,策略模式的应用可以使系统的算法重复利用,避免复制粘贴。然而,策略模式也会增加策略类的数量,违反最少知识原则,需要了解各种策略类才能更好地应用于业务中。本文还以员工年终奖的计算为例,说明了策略模式的应用场景和实现方式。 ... [详细]
author-avatar
6易0k醉人也s易
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有