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

我们来编写一个程序,以统计各个数字、空白符(包括空格符、制表符及换行符)以及所有其它字符出现的次数。这个程序的实用意义并不大,但我们可以通过该程序讨论 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 函数的程序知道(也可以找出)字符串的长度,因此该函数不需要进行错误检查。

(0)

相关推荐

  • C语言中交换int型变量的值及转换为字符数组的方法

    不使用其他变量交换两个整型的值: #include <stdio.h> void main(){ int a = 3; int b = 4; a = a ^ b;//使用异或交换 b = b ^ a; a = a ^ b; printf("%d, %d\n", a, b); a = a - b;//使用加减交换 b = a + b; a = b - a; printf("%d, %d\n", a, b); a ^= b ^= a ^= b; printf

  • 在C语言中比较两个字符串是否相等的方法

    C语言strcmp()函数:比较字符串(区分大小写) 头文件:#include <string.h> strcmp() 用来比较字符串(区分大小写),其原型为: int strcmp(const char *s1, const char *s2); [参数]s1, s2 为需要比较的两个字符串. 字符串大小的比较是以ASCII 码表上的顺序来决定,此顺序亦为字符的值.strcmp()首先将s1 第一个字符值减去s2 第一个字符值,若差值为0 则再继续比较下个字符,若差值不为0 则将差值返回.例

  • c语言字符数组与字符串的使用详解

    1.字符数组的定义与初始化字符数组的初始化,最容易理解的方式就是逐个字符赋给数组中各元素.char str[10]={ 'I',' ','a','m',' ','h','a','p','p','y'};即把10个字符分别赋给str[0]到str[9]10个元素如果花括号中提供的字符个数大于数组长度,则按语法错误处理:若小于数组长度,则只将这些字符数组中前面那些元素,其余的元素自动定为空字符(即 '\0' ). 2.字符数组与字符串在c语言中,将字符串作为字符数组来处理.(c++中不是)在实际应用

  • C语言实现字符串匹配KMP算法

    字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"? 下面的的KMP算法的解释步骤 1. 首先,字符串"BBC ABCDAB ABCDABCDABDE"的第一个字符与搜索词"ABCDABD"的第一个字符,进行比较.因为B与A不匹配,所以搜索词后移一位. 2. 因为B与A不匹配,搜索词再往后移. 3. 就这样,直到字符

  • C语言中查找字符在字符串中出现的位置的方法

    C语言strchr()函数:查找某字符在字符串中首次出现的位置 头文件:#include <string.h> strchr() 用来查找某字符在字符串中首次出现的位置,其原型为: char * strchr (const char *str, int c); [参数]str 为要查找的字符串,c 为要查找的字符. strchr() 将会找出 str 字符串中第一次出现的字符 c 的地址,然后将该地址返回. 注意:字符串 str 的结束标志 NUL 也会被纳入检索范围,所以 str 的组后一个

  • C语言字符串操作总结大全(超详细)

    1)字符串操作 strcpy(p, p1) 复制字符串 strncpy(p, p1, n) 复制指定长度字符串 strcat(p, p1) 附加字符串 strncat(p, p1, n) 附加指定长度字符串 strlen(p) 取字符串长度 strcmp(p, p1) 比较字符串 strcasecmp忽略大小写比较字符串strncmp(p, p1, n) 比较指定长度字符串 strchr(p, c) 在字符串中查找指定字符 strrchr(p, c) 在字符串中反向查找 strstr(p, p1

  • C语言实现输入一个字符串后打印出该字符串中字符的所有排列

    本文实例讲述了C语言实现输入一个字符串后打印出该字符串中字符的所有排列的方法,属于数学里的排列问题.是一个很实用的算法技巧.分享给大家供大家参考.具体实现方法如下: 例如输入字符串abc,则输出由字符a.b.c所能排列出来的所有字符串abc.acb.bac.bca.cab和cba. C语言实现代码如下: /* * Copyright (c) 2011 alexingcool. All Rights Reserved. */ #include <iostream> #include <al

  • 一波C语言字符数组实用技巧集锦

    字符数组倒序 #include <stdio.h> void daoxu(char str[]){ int i; char temp; for(i = 0; i < strlen(str) / 2 ; i ++){ temp = str[i]; str[i] = str[strlen(str) - i-1]; str[strlen(str) - i-1] = temp; } } 单词计数    int wordCount(char str[]){ int i; int count = 0

  • C语言之从字符数组中删除特定的字符

    从字符数组中删除特定的字符,即输入要删除的指定字符,利用for循环找到非指定字符,将非指定字符输出即可.以下为具体的实现方法: #include<stdio.h> int main() { char str[100],c; int j,k; printf("please input a string:"); gets(str); printf("\nEnter a character:"); c=getchar(); for(j=k=0;str[j]!=

  • c语言标准库中字符转换函数和数字转换函数

    字符转换为数字: #include<stdlib.h> atoi();将字符转换为整型   例:char ch1;int i=atoi(ch1); atol();将字符转化为长整型  例:char ch2;long l=atol(ch2); atof();将字符转化为浮点型  例:char ch3;float f=atof(ch3); strtod(); 将字符串转化为双精度类型  例:string str1:double d=strtod(str1); strtol(); 将字符串转化为长整

  • C语言实现将字符串转换为数字的方法

    本文实例讲述了C语言实现将字符串转换为数字的方法.分享给大家供大家参考.具体实现方法如下: C语言提供了几个标准库函数,可以将字符串转换为任意类型(整型.长整型.浮点型等)的数字.以下是用atoi()函数将字符串转换为整数的一个例子: 复制代码 代码如下: # include <stdio. h> # include <stdlib. h> void main (void) ; void main (void) {     int num;     char * str = &qu

随机推荐