字符数组
在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 = 56; //正确,这里的65是ASCII码,char的值有两种表示形式,一种是字符,一种是字符对应的ASCII码
char d = "A";//错误,用双引号包裹的内容是常量字符串(没有变量字符串)
char e = '王';//错误,ASCII中不包含中文字符,中文字符使用的是如GBK、UTF-8等编码,实际上都超过了1个字节
语法
一维数组:
char 数组名[数组容量]
二维数组:
char 数组名[行容量][列容量]
字符数组的语法就是我们之前所学的一维数组和二维数组的语法,只不过数据类型是char而已。
注意:
如果我们的char数组初始化的时候,没有完全初始化值的时候,使用\0
进行填充。大家要注意,这里的\0
只是起到一个占位或者标识的作用,我们是无法通过printf等打印输出到控制台的(不支持输出)。
比如:
char c[8] = {'h','g','i','u'} //部分初始化
char c[8] = {'h','g','i','u','\0','\0','\0','\0'}:
案例
案例1
-
需求:输出一个字符序列(I LOVE YOU)
-
代码
/************************************************************************* > File Name: demo04.c > Author: 小刘 > Description: > Created Time: 2025年05月16日 星期五 22时20分12秒 ************************************************************************/ #include <stdio.h> int main(int argc,char *argv[]) { // 创建一个数组,用来存储 I LOVE YOU,ASCII中对应的空格为 ' ',其对应的ASCII码是 32 char arr[] = {'I',' ','L','O','V','E',32,'Y','O','U'}; // 计算数组的大小 int len = sizeof(arr) / sizeof(arr[0]); // 使用for循环遍历数组 for (int i = 0; i < len; i++) printf("%c",arr[i]); printf("\n"); return 0; }
案例2
-
需求:输出一个用字符
*
组成的菱形图案 -
代码:
/************************************************************************* > File Name: demo05.c > Author: 小刘 > Description: 打印一个菱形 > Created Time: 2025年05月13日 星期二 13时09分28秒 ************************************************************************/ #include <stdio.h> int main(int argc,char *argv[]) { //创建一个二维数组,存放空菱形 int arr[5][5] = { ' ',' ','*',' ',' ', ' ','*',' ','*',' ', '*',' ',' ',' ','*', ' ','*',' ','*',' ', ' ',' ','*',' ',' ', }; //计算行数和列数 int row = sizeof(arr) / sizeof(arr[0]); int col = sizeof(arr[0]) / sizeof(arr[0][0]); for(int i = 0;i < row ;i++) { for(int j = 0;j < col ;j++)printf("%c",arr[i][j]);printf("\n"); } printf("\n"); return 0; }
注意
- 如果定义时,不初始化,元素值不确定(针对局部定义的数组)
char arr1[2];//如果这个数组是定义在函数中的,此时元素的值是随机的
char arr2[5]= {'a','b','c'}; //此时属于不完全初始化,未初始化完的元素使用\θ填充
-
如果提供的字符个数大于数组长度,则按照语法错误处理(会报警告,但是能编译通过);如果字符个数小于数组长度,后面的元素自动补
\0
char arr1[2] = {'h','e','e'}; //编译通过,但是会报警告,不建议写 char arr2[3] = {'a'}; //正确的,未初始化的元素使用’\θ”填充
-
如果提供的字符个数与数组长度相同,可以省略数组长度,系统会自动确定元素个数,适合字符较多时。
char arr1[] = {'b','u'}; //正确,根据初始化元素,由系统自动计算元素个数
字符串的结束标志
说明
-
C 语言规定,字符串以字符
\0
,作为结束标志。 -
编译系统对字符串常量自动加一个
\0
作为结束的标志。比如char *name = "TOM"
,实际上存储为{‘t’,‘o’,‘m’,‘\0’} -
程序中往往通过判断
\0
来检测字符是否结束。举例:while(arr[i]! = ‘\0’){…} -
\0
的ASCII码是0,不是一个可显示可输出的字符,是“空操作符”,它什么都不做,不会增加有效字符,仅仅用作一个工程判别的标志或者在字符数组中占位。char a[] = {'h','i'}; //遍历hi char a[] = {'h','i','\0'}; //遍历hi char a[] = "hello"; //遍历hello\0 字符串常量,在内存中,默认加了一个\0字符作用结尾标志
字符串的多样表示
我们的char 数组的形式一个一个输出每一个字符;也可以以字符串的形式整体输出。
-
演示
/************************************************************************* > File Name: demo07.c > Author: 小刘 > Description: > Created Time: 2025年05月17日 星期六 16时56分20秒 ************************************************************************/ #include <stdio.h> int main(int argc,char *argv[]) { // 字符串的第1种表示: char s1[] = {'h','e','l','l','o',' ','w','o','r','l','d','\0'}; // 字符串的第2种表示: char s2[] = {"hello world"}; // "" 包裹的字符串一般默认有一个\0,所以不需要我们手动添加 // 字符串的第3种表示: char s3[] = "hello world"; // 计算字符串所占的字节数 printf("s1=%d,s2=%d,s3=%d\n", sizeof(s1), sizeof(s2), sizeof(s3)); //s1=12,s2=12,s3=12 // 字符串输出第1种方式: 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; }
-
运行结果:
注意:
- 字符串的长度与字符数组的长度不一定形同。
char *name = "hello"; //数组长度:6,字符串长度:5
-
利用字符串常量可以对字符数组进行初始化,但不能用字符串常量对字符数组赋值。
// 正确演示:利用字符串常量给字符数组初始化 char arr1[] = "hello"; // 错误演示:利用字符串常量给字符数组赋值 char arr2[6]; arr2 = "hello"; // 可以理解为,数组是一个常量
字符串的基础操作
在用格式化说明符%s进行输入输出,其输入输出项均为数组名。但是在输入时,相邻两个字符串之间要用空格分隔,系统将自动在字符串后加\0
。在输出时,遇到结束符\0
作为输出结束标志。
对于字符串的操作,我们需要使用到一些系统提供的API函数。
字符串输入
scsnf
语法:
scanf("%s",数组名);
注意:数组名对应的数组只能是char类型,从控制台输入字符串之后,默认为追加\0
案例:
#include <stdio.h>
int main(int argc,char *argv[])
{
// 创建一个字符数组,用来存储姓名
char name[20]; // 初始化的时候,数组容量可以省略,char name[] = {..},如果只是声明,数组容量不能省略
// 计算数组容量
int len = sizeof(name) / sizeof(name[0]);
printf("请输入您的名字:\n");
// scanf("%s",name);// 数组本身没有空间,它的内存空间其实就是其元素空间,C语言规定数组名指向第一个元素的首地址
fgets(name,len,stdin);
printf("您的姓名是:%s\n",name);
return 0;
}
注意:采用scanf进行字符串输入,要求字符串中不能有空格,否则字符串遇到空格就会结束。
fgets
语法:
fget (数组名,数组容量,stdin);
功能:
从键盘录入一个字符串常量到字符数组,返回字符数组的地址(首地址,默认返回的地址,一 般用12位16进制数表示)
说明:
采用fgets进行字符串输入,可获取所有输入的字符串,包含\n,在实际的字符串处理时,我们 可能需要手动处理\n
#include <stdio.h>
int main(int argc,char *argv[])
{
// 创建一个字符数组,用来存储姓名
char name[20]; // 初始化的时候,数组容量可以省略,char name[] = {..},如果只是声明,数组容量不能省略
// 计算数组容量
int len = sizeof(name) / sizeof(name[0]);
printf("请输入您的名字:\n");
// scanf("%s",name);// 数组本身没有空间,它的内存空间其实就是其元素空间,C语言规定数组名指向第一个元素的首地址
fgets(name,len,stdin);
printf("您的姓名是:%s\n",name);
return 0;
}
注意:
① 如果输入的字符串不包括空格或换行,可以使用scanf或者fgets
② 如果输入的字符串包括空格或换行,只能使用fgets
gets危险的【C11移出】
语法:
gets(数组名);
功能:
从键盘录入一个字符串常量到字符数组,返回字符数组的地址(首地址,默认返回的地址,一 般用12位16进制数表示)
说明:
采用gets进行字符串输入,可获取所有输入的字符串,包含 \n ,在实际的字符串处理时,我 们可能需要处理 \n
#include <stdio.h>
int main(int argc,char *argv[])
{
// 创建一个字符数组,用来存储姓名
char name[20];
printf("请输入您的名字:\n");
scanf("%s",name);// 数组本身没有空间,它的内存空间其实就是其元素空间,C语言规定数组名指向的就是首地址
printf("您的姓名是%s\n",name);
return 0;
}
字符串输出
printf
语法:
printf("%s",数组名);
案例:
#include <stdio.h>
int main(int argc,char *argv[])
{
// 创建一个字符数组,用来存储姓名
char name[20];
printf("请输入您的名字:\n");
scanf("%s",name);// 数组本身没有空间,它的内存空间其实就是其元素空间,C语言规定数组名指向的就是首地址
printf("您的姓名是%s\n",name);
return 0;
}
fputs
语法:
注意:采用scanf进行字符串输入的时候不能采用空格,否则遇到空格会结束
语法:
fputs(数组名,stdout);
功能:
输出一个字符串
说明:
字符串可以包含转义字符(以\
开头的字符)
案例:
#include <stdio.h>
int main(int argc,char *argv[])
{
char arr[] = "hi lucy\trun!\n";
// 第1种输出
printf("%s",arr);
// 第2种输出
fputs(arr,stdout);
return 0;
}
puts危险的【C11移出】
语法:
puts(数组名称);
功能:
输出一个字符串
说明:
字符串可以包含转义字符
案例:
#include <stdio.h>
int main(int argc,char *argv[])
{
// 创建一个数组,用来存放人的名字
char name[20];
printf("请输入您的名字:\n");
// gets、fgets和scanf只能多选一
gets(name);
// 输出
puts(name);// 标准的输出
return 0;
}
字符串转数值【扩展】
-
strtol
long strtol(const char *str, char **endptr, int base);
将字符串转换为长整型数。
参数说明:
str
:指向要转换的字符串的指针。endptr
:一个指向字符指针的指针。如果提供了这个参数,并且转换成功,*endptr
将被 设置为指向第一个未转换字符的指针。如果endptr
是NULL
,则不使用它。base
:用于指定转换的基数。它可以是 2 到 36 之间的值,或者是特殊值 0。如果base
是 0,则函数会根据字符串的前缀(如 “0x” 或 “0X” 表示十六进制,“0” 表示八进制,否则默 认为十进制)来自动确定基数。
-
strtoul
unsigned long strtoul(const char *str, char **endptr, int base);
将字符串转换为无符号长整型数。
-
strtod
double strtod(const char *str, char **endptr);
将字符串转换为双精度浮点数。
-
atoi
int atoi(const char *str);
将字符串转换为整型数(不推荐使用,建议使用
strtol
)。 -
atol
long atol(const char *str);
将字符串转换为整型数(不推荐使用,建议使用
strtol
)。 -
atof
long atof(const char *str);
将字符串转换为整型数(不推荐使用,建议使用
strtol
)。
案例:
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
printf("%lo,%ld,%lx\n",strtol("12",NULL,8),strtol("12",NULL,10),strtol("12",NULL,16));
printf("%lo,%ld,%lx\n",strtol("012",NULL,0),strtol("12",NULL,10),strtol("0x12",NULL,0));
int a = 10;
printf("%p,%lx\n",&a,&a);
return 0;
}
main()
{
int a=2,b=-1,c=2;
if(a<b)
if(b<0) c=0;
else c+=1;
printf("%d\n",c);
}
关于单字符的输入:
- scanf(“%c”,…)
- getchar();
关于单字符的输出:
- printf(“%c”,…);
- putchar();