字符数组
再C语言中支持字符串常量,不支持字符串变量。如果想要实现类似的字符串变量,C语言提供了两种实现方式:
-
字符数组:
char name[] = "哪吒";
-
字符指针
char *name = "哪吒";
概念
元素类型位char(字符型)的数组叫做字符数组。字符数组本质上是为了存储字符串数据(注意,C语言中字符是字节字符(1字符=1字节,C语言中没有字节这个表示法,我们一般使用char表示字节:1char = 8bit))。
硬件中存放数据以bit(位)为单位,系统对于内存的操作以char(字节)为单位。系统为内存以1个字节为单位进行编号(编号是内存地址)
实验
char a = 'A'; // 正确 字符
char b = '1'; // 正确 字符
char c = 1; // 正确 ASCII码
char d = '\\n'; // 正确 只要其对应的ASCII码的范围在0~127之间,都属于字符
char e = "A"; // 错误 双引号括起来的内容叫做字符串常量
char f = '和'; // 错误 char类型仅占1个字节,而中文字符(如GBK/UTF-8 编码)至少占2字节/3字节,无法用单个char存储;且中文的编码值超出0~127
语法
一维数组:
char 数组名[数组容量];
二维数组:
char 数组名[行容量][列容量];
字符数组的语法于之前学的数组语法区别仅在于数据类型是char而已。
注意:所有类型数组初始化都可用0填充。字符串char数组初始化时,没有完全初始化的时候,使用\\0或者0填充(\\0仅起到一个占位或者标识的作用,无法通过printf等打印输出到控制台的)。
示例
char c[8] = {'h','e','l','l','o'};
// 一维的字符数组的初始化,未初始化部分补\\0 或者 0 等价与下面写法
char c[8] = {'h','e','l','l','o','\\0','\\0','\\0'};
案例
案例1:输出一个字符序列:I LOVE YOU
-
代码
#include <stdio.h>
// 输出一个字符序列:I LOVE YOU
void test1()
{
// 创建一个数组,用来存储 I LOVE YOU 空格' ' 也是字符,对应的ASCII是32
char arr[] = {'I',' ','L','O','V','E', 32 ,'Y','O','U'};
// 计算数组的容量
int len = sizeof(arr) / sizeof(arr[0]);
// 遍历数组
for (int i = 0; i < len; i++) printf("%c",arr[i]); printf("\\n");
return 0;
} -
结果
I LOVE YOU
案例2:输出一个用字符*组成的空菱形图案
-
代码
#include <stdio.h>
// 一维数组:输出一个字符序列:I LOVE YOU
void test1()
{
// 创建一个数组,用来存储 I LOVE YOU 空格' ' 也是字符,对应的ASCII是32
char arr[] = {'I',' ','L','O','V','E', 32 ,'Y','O','U'};
// 计算数组的容量
int len = sizeof(arr) / sizeof(arr[0]);
// 遍历数组
for (int i = 0; i < len; i++) printf("%c",arr[i]); printf("\\n");
}
// 二维数组:输出一个用字符`*`组成的空菱形图案
void test2()
{
// 创建一个二维的字符数组,存放菱形
char arr[5][5] = {
{' ',' ','*',' ',' '},
{' ','*',' ','*',' '},
{'*',' ',' ',' ','*'},
{' ','*',' ','*',' '},
{' ',' ','*',' ',' '}
};
// 计算行和列的容量
int row_len = sizeof(arr) / sizeof(arr[0]);
int col_len = sizeof(arr[0]) / sizeof(arr[0][0]);
// 遍历数组
for (int i = 0; i < row_len; i++)
{
for (int j = 0; j < col_len; j++) printf("%c",arr[i][j]); printf("\\n");
}
printf("\\n");
return 0;
} -
结果
*
* *
* *
* *
*
注意:
-
如果定义时不初始化,元素值不确定(局部作用域)
char arr1[2]; // 此时,这个数组中元素的值是随机值(垃圾值)
char arr2[3] = {'a','b','c'}; // 完全初始化(元素个数与数组容量一致)
char arr3[3] = {'a'}; // 部分初始化,未初始化元素补'\\0'
char arr4[3] = {}; // 此时所有的元素使用 \\0 填充
char arr5[3] = {0}; // 此时所有的元素使用 \\0 填充 '\\0' == 0
char arr6[3] = {'\\0'} // 等价于上面写法 -
如果提供的字符个数大于数组长度,则按照语法错误处理(会报警告,但是能编译通过);如果字符个数小于数组长度,后面的元素自动补\\0。
char arr1[2] = {'h','e','e'};//错误:初始化元素个数超过数组容量,属于未定义行为(UB),编译会报警告,严谨编写此类代码。
char arr1[3] = {'a'};//正确:部分初始化,未初始化部分自动补 \\0 -
如果提供的字符个数与数组容量相同,可以省略数组容量,系统会自动确定元素的个数,适合字符较多时。
char arr1[] = {'b','c','i'};//正确,更具初始化的元素,由系统自动计算元素个数。
字符串结束标志
说明:
-
C语言规定字符串常量以\\0作为结束标志
-
编译系统对字符串常量自动添加一个\\0作为结束标志。char *name = "tom",实际存储为{'t','o','m','\\0'}。
-
程序中往往通过判断\\0来检测字符串是否结束。
-
\\0的ASCII码时0,不是一个可显示可输出的字符,是“空操作符”。不会增加有效字符,仅仅用作给工程判别的标志或者在数组中占位。
char a1[] = {'h','i'};
printf("%c%c",a1[0],a1[1]); // 输出:hi
printf("%s",a1); // 错误,因无`\\0`会越界访问,属于未定义行为(可能输出乱码/崩溃)
char a2[] = {'h','i','\\0'};
printf("%s", a2); // 输出:hi sizeof(a2) 返回3字节
char c[] = "hello";
printf("%s",c); // 输出:hello sizeof(c) 返回6字节
字符数组的多样表示:
char数组可以以数组的形式一个一个输出每个字符;也可以以字符串形式整体输出。
#include <stdio.h>
int main()
{
// 方式1:手动逐个字符初始化,需手动添加`\\0`(否则不是合法字符串)
char s1[] = {'h','e','l','l','o',' ','w','o','r','l','d','\\0'}; // 字符串必须 \\0结束
// 方式2/3:字符串常量初始化(推荐),编译器自动加`\\0`(以下两种写法等价)
char s2[] = "hello world"; // 最简写法
char s3[] = {"hello world"};// 与s2等价,多一层{}无意义,不推荐
// 字符串的第1种输出:
printf("s1=%Lu,s2=%Lu,s3=%Lu\\n", sizeof(s1), sizeof(s2), sizeof(s3)); // s1=12,s2=12,s3=12
// 计算数组大小
int len = sizeof(s3) / sizeof(s3[0]);
// 遍历
for (int i = 0; i < len; i++)
{
// 过滤 \\0
if (s1[i] == 0 || s2[i] == '\\0' || s3[i] == 0) continue;
printf("%c,%c,%c\\n",s1[i],s2[i],s3[i]);
}
printf("\\n");
// 字符串的第2种输出:
printf("%s,%s,%s\\n", s1, s2, s3);
printf("\\n");
return 0;
}
结果:
s1=12,s2=12,s3=12
h,h,h
e,e,e
l,l,l
l,l,l
o,o,o
, ,
w,w,w
o,o,o
r,r,r
l,l,l
d,d,d
hello world,hello world,hello world
注意:
-
字符串的长度不一定等于字符数组的长度
示例:
char name[] = "hello";
解释:
-
数组长度(sizeof(name)):6,包含'h'/'e'/'l'/'l'/'o'/'\\0'
-
字符串长度(strlen(name)):5,仅统计\\0之前的有效字符,需包含<string.h>头文件
-
-
利用字符串常量可以对字符串数组进行初始化,但不能用字符串常量来对字符数组赋值。(因为C语言规定数组名是常量,无法通过数组名进行赋值)


