C 语言:一维字符型数组
本文系统介绍了C语言中一维字符型数组的核心概念与使用方法。重点包括:数组定义与初始化(需包含'\0')、存储特性(连续空间与'\0'标识)、字符串输入输出函数(scanf/gets/printf/puts)以及string.h库函数(strlen/strcpy/strcat/strcmp)。特别强调了常见错误如忘记'\0'、数组越界、错误比较字符串等问题,并提供了遍历、统计长度等实用技巧。正确使用
一、一维字符型数组的基本概念
一维字符型数组是元素类型为 char(或 unsigned char)、仅需一个下标即可访问的数组,专门用于存储字符数据或字符串。其核心特点如下:
- 元素类型固定:所有元素均为 char 类型(占 1 字节),存储字符对应的 ASCII 码值。
- 字符串结尾标识:C 语言规定,字符串必须以特殊字符
'\0'(ASCII 码值为 0)结尾,用于标记字符串的结束位置。 - 存储连续有序:数组元素在内存中占用连续存储空间,按下标顺序依次存储。
二、一维字符型数组的定义与初始化
2.1 数组定义
定义格式:char 数组名[元素个数];
- 数组名:遵循 C 语言变量命名规则(字母、数字、下划线组成,不能以数字开头,不与关键字冲突)。
- 元素个数:必须为常量(如 32、100),且需大于等于要存储的字符串长度(包含结尾的
'\0')。
// 定义一个可存储31个字符+1个'\0'的字符数组(最多存31个有效字符)
char str1[32];
// 定义无符号字符数组(值域0-255,适用于扩展ASCII码)
unsigned char str2[100];
2.2 数组初始化
字符数组的初始化分为「单个字符初始化」和「字符串直接初始化」,核心是确保字符串末尾有'\0'(否则无法被字符串函数识别)。初始化≠赋值,数组定义后不能整体赋值,只能逐个元素修改。
1. 全部初始化(推荐)
显式为所有元素赋值,包含'\0',确保字符串完整性。
// 方式1:单个字符列表初始化(最后一个元素必须是'\0')
char str[6] = {'h', 'e', 'l', 'l', 'o', '\0'};
// 方式2:字符串常量初始化(编译器自动在末尾添加'\0')
char str[6] = "hello";
// 方式3:省略大括号的字符串初始化(等价于方式2)
char str[6] = "hello";
2. 局部初始化
仅为部分元素赋值,未赋值的元素自动初始化为 0(即'\0'),无需手动添加结尾标识。
// 前3个元素为'h','e','l',后3个元素自动为'\0'
char str[6] = {'h', 'e', 'l'};
// 等价于上面,编译器自动补'\0'
char str[6] = "hel";
// 数组所有元素初始化为'\0'(常用清空数组技巧)
char str[6] = {0};
3. 默认初始化(谨慎使用)
省略元素个数,编译器根据初始化列表长度(包含自动添加的'\0')推断数组长度。
// 数组长度为6('h','e','l','l','o'+'\0')
char str[] = "hello";
// 等价于上面
char str[] = {'h', 'e', 'l', 'l', 'o', '\0'};
注意:默认初始化虽简洁,但如果后续需要扩展字符串(如拼接),可能因数组长度不足导致内存溢出,建议显式指定足够大的数组长度。
常见错误示例
char str[6] = {0};
// 错误:数组不能整体赋值(初始化仅在定义时有效)
str = "hello";
// 错误:下标越界(str[6]超出数组范围0-5)
str[6] = "hello";
三、一维字符型数组的存储特性
3.1 空间大小计算
字符数组所占内存空间大小 = 数组元素个数(每个元素占 1 字节),与存储的字符串长度无关。
// 数组长度为32,所占空间为32字节
char str[32] = "hello";
// 结果:32(数组总空间)
printf("数组所占空间:%zu字节\n", sizeof(str));
3.2 核心存储规则
- 连续性:数组元素在内存中连续存储,例如
str[0]的地址为0x100,则str[1]为0x101,以此类推。 - 有序性:字符按赋值顺序依次存储,字符串的实际长度是从数组开头到第一个
'\0'的字符个数(不包含'\0')。 '\0'的关键作用:若数组中无'\0',字符串函数(如printf("%s")、strlen)会继续向后访问内存,导致乱码或内存越界。
// 无'\0',字符串函数无法识别结尾,会输出乱码
char str1[5] = {'h', 'e', 'l', 'l', 'o'};
// 有'\0',正确输出"hello"
char str2[6] = {'h', 'e', 'l', 'l', 'o', '\0'};
// 输出乱码(无'\0')
printf("str1: %s\n", str1);
// 输出"hello"(有'\0')
printf("str2: %s\n", str2);
四、字符串的输入与输出
字符数组存储字符串后,需通过专门的输入输出函数操作,常用函数包括printf、puts(输出)和scanf、gets(输入)。
4.1 字符串输出
1. printf("%s", 数组名)
- 功能:从数组开头打印字符,直到遇到
'\0'为止(不打印'\0')。 - 示例:
char str[32] = "hello world";
// 输出:hello world(自动识别'\0'结尾)
printf("输出字符串:%s\n", str);
2. puts(数组名)
- 功能:与
printf("%s")类似,但会自动在结尾添加换行符'\n'。 - 示例:
char str[32] = "hello world";
// 输出:hello world(后接换行)
puts(str);
4.2 字符串输入
1. scanf("%s", 数组名)
- 功能:从终端接收字符串,遇到空格、制表符
'\t'或换行符'\n'时停止,并自动在数组末尾添加'\0'。 - 注意:
- 数组名无需加
&(数组名本质是数组首元素地址)。 - 无法接收带空格的字符串(如 "hello world" 会被拆分为 "hello")。
- 数组名无需加
- 示例:
char str[32] = {0};
printf("请输入字符串:");
// 输入"hello world",实际只接收"hello"
scanf("%s", str);
// 输出:hello
printf("你输入的是:%s\n", str);
2. gets(数组名)
- 功能:从终端接收一行字符串,可接收带空格的内容,遇到换行符
'\n'时停止,并自动丢弃'\n',在数组末尾添加'\0'。 - 示例:
char str[32] = {0};
printf("请输入字符串:");
// 输入"hello world",完整接收
gets(str);
// 输出:hello world
printf("你输入的是:%s\n", str);
注意:gets函数存在安全隐患(若输入字符串长度超过数组容量,会导致内存溢出),C11 标准已弃用,推荐使用更安全的fgets函数(后续扩展)。
五、字符串常用库函数(string.h)
C 语言提供了string.h头文件,包含一系列字符串操作函数,需先导入头文件#include <string.h>才能使用。以下是最常用的 4 个函数:
5.1 strlen:获取字符串长度
- 功能:计算从数组开头到第一个
'\0'的字符个数(不包含'\0')。 - 原型:
size_t strlen(const char *str); - 示例:
#include <stdio.h>
#include <string.h>
int main(void) {
char str[32] = "hello";
// 结果:5('h'/'e'/'l'/'l'/'o'共5个字符)
size_t len = strlen(str);
// 结果:32(数组总空间)
size_t size = sizeof(str);
printf("字符串长度:%zu\n", len);
printf("数组所占空间:%zu字节\n", size);
return 0;
}
注意:strlen返回值类型为size_t(无符号整数),避免与 int 类型直接比较。
5.2 strcpy:字符串拷贝
- 功能:将源字符串(第二个参数)完整拷贝到目标数组(第一个参数),包括
'\0'。 - 原型:
char *strcpy(char *dest, const char *src); - 注意:
- 目标数组
dest必须有足够空间存储源字符串(包括'\0'),否则会内存溢出。 - 源字符串
src必须以'\0'结尾。
- 目标数组
- 示例:
#include <stdio.h>
#include <string.h>
int main(void) {
char src[32] = "hello world";
char dest[32] = {0};
// 将src拷贝到dest
strcpy(dest, src);
// 输出:dest: hello world
printf("dest: %s\n", dest);
return 0;
}
5.3 strcat:字符串拼接
- 功能:将源字符串(第二个参数)拼接到目标字符串(第一个参数)的末尾,源字符串的
'\0'覆盖目标字符串原来的'\0'。 - 原型:
char *strcat(char *dest, const char *src); - 注意:
- 目标数组
dest必须有足够空间存储拼接后的字符串(目标字符串长度 + 源字符串长度 + 1 个'\0')。 - 目标字符串和源字符串都必须以
'\0'结尾。
- 目标数组
- 示例:
#include <stdio.h>
#include <string.h>
int main(void) {
char dest[32] = "hello ";
char src[32] = "world";
// 拼接后dest为"hello world"
strcat(dest, src);
// 输出:hello world
printf("拼接结果:%s\n", dest);
return 0;
}
5.4 strcmp:字符串比较
- 功能:按 ASCII 码值逐字符比较两个字符串,直到遇到不同字符或
'\0'。 - 原型:
int strcmp(const char *str1, const char *str2); - 返回值规则:
- 若
str1 == str2,返回 0; - 若
str1 > str2(第一个不同字符的 ASCII 码更大),返回大于 0 的值; - 若
str1 < str2,返回小于 0 的值。
- 若
- 示例:
#include <stdio.h>
#include <string.h>
int main(void) {
char str1[] = "apple";
char str2[] = "banana";
char str3[] = "apple";
// 结果:-1('a'的ASCII码小于'b')
int cmp1 = strcmp(str1, str2);
// 结果:0(两字符串完全相同)
int cmp2 = strcmp(str1, str3);
printf("str1 vs str2: %d\n", cmp1);
printf("str1 vs str3: %d\n", cmp2);
return 0;
}
注意:不可用==直接比较字符串(==比较的是数组地址,而非字符串内容),必须用strcmp。
六、一维字符型数组实战技巧
6.1 遍历字符串(逐个字符访问)
通过下标遍历数组,直到遇到'\0'为止:
#include <stdio.h>
int main(void) {
char str[] = "hello";
int i = 0;
// 遍历到'\0'结束
while (str[i] != '\0') {
// 依次输出'h' 'e' 'l' 'l' 'o'
printf("%c ", str[i]);
i++;
}
printf("\n");
return 0;
}
6.2 手动统计字符串长度(不使用strlen)
利用'\0'结尾的特性,遍历计数:
c
运行
#include <stdio.h>
int main(void) {
char str[] = "hello world";
int len = 0;
// 遇到'\0'停止计数
while (str[len] != '\0') {
len++;
}
// 输出:11
printf("字符串长度:%d\n", len);
return 0;
}
6.3 字符串清空(全部置为'\0')
char str[32] = "hello";
// 方式1:逐个赋值(适用于任意长度)
int i;
for (i = 0; i < sizeof(str); i++) {
str[i] = '\0';
}
// 方式2:利用初始化(仅适用于定义时或整体清空)
char str[32] = {0};
七、常见问题与注意事项
- 忘记添加
'\0':导致字符串函数识别异常,输出乱码。解决方案:初始化时显式添加或使用字符串常量初始化(编译器自动补'\0')。 - 数组长度不足:拷贝或拼接字符串时,目标数组空间不够导致内存溢出。解决方案:定义数组时预留足够空间(如 32、1024 字节),避免硬编码过小的长度。
- 使用
scanf("%s")接收带空格的字符串:导致输入被截断。解决方案:使用gets(简单但不安全)或fgets(推荐,需处理换行符)。 - 用
==比较字符串:错误认为"abc" == "abc"为真,实际比较的是数组地址。解决方案:必须使用strcmp函数。
更多推荐


所有评论(0)