看到标题, 有不少朋友会想: 字符数组不也是数组吗? 为什么要单独拿出来讲哩? 莫非它是朵奇葩?
哈哈, 确实, 一起来认识一下这朵数组界的奇葩吧!
一, 字符数组的定义, 引用, 初始化
大家好!我是字符数组,看我的名字就知道啦,我是由字符型元素构成哒! 我的定义方式和元素引用方式和一般数组相同哦,我们可是一家人哦! |
char line [80];
这是定义了一个长度为 80 的一维字符数组.
char m [2] [3];
这是定义了一个 2 行 3 列的二维字符数组.
printf ("%c", line [2]);
这是在应用数组元素.
so easy!
字符的初始化方法可以分为两种:
(1) 将字符逐个赋给数组中的每个元素;
char c [5] = {'c', 'h', 'i', 'n', 'a'};
这是把 5 个字符分别赋给 c [0] ~ c [4] 这 5 个元素中.
(2) 直接用字符串常量给数组赋初值.
char c [6] = "china";
看到这个例子, 又有好奇的小伙伴发问了: china 这不只有 5 个字符吗? 为啥前面写着 6 ?
实验检验真知, 让我们把 5 和 6 都运行一下:
当括号里面写成 5 时, 程序就会被报错!
当括号里面写成 6 时, 程序就会正常!
有些小伙伴的头上是不是出现了许多问号呢?
先别着急, 下面小编就会把谜底揭开.
敲黑板! 我们要知道: 无论用以上哪种方法进行初始化, 如果提供的字符个数大于数组长度, 系统就会进行语法错误处理, 比如上面的情况; 如果提供的字符个数小于数组长度, 则只会给前面几个元素赋值, 剩下的自动设置为 0, 即 '\0'.
给你吃个栗子:
char a [10] = {'c', 'h', 'i', 'n', 'a'}
这里我们定义了 10 个长度, 但只给 5 个元素赋值, 那么这个数组的状态就会是:
c | h | i | n | a | \0 | \0 | \0 | \0 | \0 |
二, 字符串和字符串结束的标志
现在就是揭示谜底的时候啦!
首先我们区分一下 "字符常量" 和 "字符串常量":
字符常量 < span style="color: #cc99ff;" ztid="135" ow="102" oh="18">(一颗山楂)
| 字符串常量(简称:字符串)(一串糖葫芦) |
用 < span style="color: #cc99ff;" ztid="142" ow="48" oh="18"> 单引号 括起来 | 用 < span style="color: #cc99ff;" ztid="145" ow="48" oh="18"> 双引号 括起来 |
一 < span style="color: #cc99ff;" ztid="149" ow="16" oh="18"> 个 字符 | 一 < span style="color: #cc99ff;" ztid="152" ow="16" oh="18"> 串 字符 |
不必 有结束字符 '\0' | 要有 结束字符 '\0' |
回到前面:
char c [6] = "china"
这里的 "china" 就是一个字符串,
C 语言约定用'\0'作为字符串的结束标志, 它占内存空间. 这里的 "china" 的有效长度为 5 , 但实际上还有第 6 个字符'\0'.
也就是说, 当遇到'\0'时, 表示字符串结束, 由它前面的字符组成字符串.
在程序中, 常用'\0'来判断字符串是否结束, 因此所定义的字符数组长度应该大于字符串的实际长度, 这样才足以存放相应的字符串, 这就是前面为什么写 6 而不是 5 的原因, 当然, 写 7 也是没有问题的.
注意:'\0'是代表 ASCII 码值为 0 的字符, 是一个不可显示的字符, 表示一个 "空字符", 也就是说它什么也没有, 只是一个可供识别的标志.
三, 字符数组的输入和输出
首先说下赋值语句, 注意, 赋值 ≠ 初始化!
和整型数组等一样, 字符数组是不能用赋值语句整体赋值, 如下代码是错误的!!!
- char str [12];
- str [12] = "the string";
对于一般数组而言, 输入和输出的时候只能对数组元素一个一个进行;
而对于字符数组, 就显得神通广大了, 它不仅可以逐个输入输出, 还可以整体输入输出!
(1) 逐个字符输入 / 输出
1 使用 scanf 进行输入, 使用 printf 进行输出, 这个时候, 要使用格式符 "%c";
- for (i = 0; i <10; i++)
- scanf ("%c", &str [i]); // 逐个输入
- for (i = 0; i < 10; i++)
- printf ("%c", str [i]); // 逐个输出
注意: 输入的时候不要丢掉 "&" 哦!
2使用 getchar() 和 putchar() 函数.
- for (i = 0; i < 10; i++)
- str [i] = getchar (); // 逐个输入
- for (i = 0; i < 10; i++)
- putchar (str [i]); // 逐个输出
(2) 字符串整体输入输出
1使用 scanf 进行输入, 使用 printf 进行输出, 这个时候, 要使用格式符 "%s";
- char str [6];
- scanf ("%s", str) // 整体输入
- printf ("%s", str) // 整体输出
注意: scanf 中的 str 代表 str 这个字符数组的首地址, 因此不加 "&"! 输入时系统会自动在字符串结尾加上结束符 '\0'.
也可以同时输入多个字符串, 这个时候输入的时候要用空格或者回车符号分隔开.
2 用字符串处理函数 gets() 进行字符串整串的输入, puts() 进行字符串整串的输出
这种方法我们待会儿再讲.
对于字符数组的输入和输出, 应当指出的是:
(1)输出字符不包括'\0';
(2)用格式符 "%s" 时, 输出项应该是数组名, 不是数组元素;
(3)当数组长度大于字符串实际长度时, 也只能输出到'\0'结束;
(4)如果数组中包含一个以上的'\0'时, 遇到第一个'\0'时结束输出, 比如:
四, 字符串函数
C 语言有一批字符串处理函数, 其中 gets() 和 puts() 函数包含在头文件 < stdio.h > 中, 其余的包含在 < string.h > 中.
下面, 小编来介绍一下常用的 8 个字符串函数.
(1)整行输入函数 gets()
一般形式: gets(字符数组), 例如:
gets (str);
执行这个语句时, gets 函数从键盘读入一串字符, 直至遇到换行符'\n'为止;
字符串输入后, 系统会自动用'\0'置于字符串的尾部, 以替代换行符.
(2)整行输出函数 puts()
一般形式: puts(字符数组), 例如:
- char str [] = "string";
- puts (str);
这个函数的作用是将字符串中的内容显示在屏幕上, 直到遇到第一个字符串结束符'\0'时. 停止输出并自动换行.
用 puts 函数输出的字符串中可以出现转义字符, 用于实现某种格式的控制. 例如:
(3)字符串长度函数 strlen()
一般形式: strlen(字符数组), 例如:
- char str[]="string";
- strlen (str);
- strlen ("string");
该函数用于统计字符串开始到'\0'的有效长度.
(4)字符串连接函数 strcat()
一般形式: strcat(字符数组 1, 字符数组 2), 例如:
- char str1 [15]= "I am";
- char str2 [] = "student";
- strcat (str1, atr2);
这个函数的作用是将字符数组 2 连接在字符数组 1 上, 就像嫁接一样.
连接前后的情况如下:
连接前 | 连接后 | |
str1 | I am \0\0\0\0\0\0\0\0\0\0 | I am student\0\0\0 |
str2 | student\0 | student\0 |
注意: 字符数组 1 的长度要足够大哦!
(5)字符串复制函数 strcpy()
一般形式: strcpy(字符数组 1, 字符数组 2), 例如:
- char str[10];
- strcpy (str, "china");
我们前面讲到, 不能用赋值语句对数组整体赋值, 那赋值的时候可以一个一个对元素赋值, 但是这种方法很是繁琐, 而这里的 strcpy 函数可以轻松搞定.
比如上面这段代码, 就把 str 中的前 5 个字符赋值为了 "china".
这里要说明一下:
在向字符数组 1 中复制 (或者 "赋值") 时, 字符数组 2 中的结束标志'\0'也被复制过去了, 比如:
复制前 | 复制后 | |
str1 | abcdefg\0 | &&&\0 efg\0 |
srr2 | &&&\0 | &&&\0 |
复制后的 str1 中出现了两个'\0', 则用 "printf("%s", str1)" 和 "puts(str1)" 输出时, 只会输出 "&&&".
(6)字符串比较函数 strcmp()
一般形式: strcmp(字符数组 1, 字符数组 2)
这里的比较是比较什么呢? 长度?
No!
它的规则是:
对两个字符串自左向右逐个字符进行比较 -- 按 ASCII 码值大小比较, 直到出现不同字符或者遇到'\0'为止.
注意: 这里比较 是 ASCII 码值!
如果全部字符都相同, 则认为相等;
若出现不同的字符, 则以第一个不同的字符的比较结果为准;
● 如果字符串 1 = 字符串 2, 函数值为 0;
● 如果字符串 1> 字符串 2, 函数值为一正数;
● 如果字符串 1 <字符串 2, 函数值为 一负数;
想看清晰的戳这里>> https://www.bilibili.com/video/BV1764y1M78v/
(7)字符串中的大写字母换成小写字母函数 strlwr()
strlwr 中的 "lwr" 是 lowercase(小写)的缩写, 运用很简单, 如图:
(8)字符串中的大写字母换成小写字母函数 strupr()
strupr 中的 "upr" 是 uppercase(大写)的缩写.
学完这 8 中字符串处理函数, 是不是感觉站在了巨人的肩膀上, 不过我们也要自己尝试编写这几种函数哦.
五, 二维的字符数组
上面我们只介绍了数组中只有一个字符串的情况, 那如果想存储多个字符串呢?
用一个双引号 " " 括起来的字符串可以被当做一个一维数组,
而多个字符串, 也就是多个一维数组, 就需要二维数组来存放.
因此, 一个 m*n 的二维字符数组可以存放 m 个字符串, 其中每个字符串的长度不超过 n-1(要保留一个位置存放'\0').
比如:
c | h | i | n | a | \0 | \0 | \0 | \0 | \0 |
a | b | c | \0 | \0 | \0 | \0 | \0 | \0 | \0 |
好啦, 吃了这么多干货, 是不是有些渴呢? 下面我们用所学的知识编写一个小程序:
问题描述: 一个公司有若干员工. 编写一个程序, 实现如下功能: 输入一个职工的姓名, 要求查询职工是否属于该公司, 并输出相应的信息.
小编思路:
1, 首先建立二维字符数组 w[100][10], 用于存放公司中所有职工的名字, 每个职工的员工名字都是一个一维数组; 同时建立一个一维字符数组 name[10], 用于存放要查找的对象姓名;
2, 接着来一个循环, 将公司职工的姓名进行输入;
3, 再来一个循环, 进行多次查询的操作;
4, 在查询中, 将要查询的姓名与二维字符数组中的姓名用字符串函数 strcmp 一个一个作比较, 如果循环后结果为 0, 则是公司职工, 否则不是.
5, 在这个程序中, 因为要多次输入, 因此每次输入前用 fflush(stdin)来清除缓冲区的内容(每次输入后的回车符存储在缓冲区).
代码展示:
- #include "stdio.h"
- #include "string.h"
- main ()
- {
- char w [100][10];
- int n = 1, i = 0, j, m;
- char name[10];
- printf("请输入该公司所有员工的姓名:\n");
- while (n == 1)
- {
- printf("%d:", i+1);
- fflush(stdin);
- gets(w[i]);
- printf("如果要继续输入, 请输入数字 1:");
- fflush(stdin);
- scanf ("%d", &n);
- i++;
- }
- n = 1;
- while (n == 1)
- {
- printf("请输入要查询的姓名:");
- fflush(stdin);
- gets(name);
- for (j = 0; j < i; j++)
- {
- m = strcmp(name, w[j]);
- if (m ==0)
- {
- break;
- }
- }
- if (m == 0) printf("该职工属于该公司!");
- else printf("该职工不属于该公司!");
- printf("如果要继续查询, 请输入数字 1:");
- fflush(stdin);
- scanf ("%d", &n);
- }
- }
本次的分享就到这里啦, 欢迎小伙伴前来交流!
预告: C 语言字符数组应用举例
- 2020-04-28
- 16:55:04
来源: https://www.cnblogs.com/zhugesiying/p/dsy.html