欢迎来到博主的专栏——C语言进阶指南
博主id:reverie_ly
文章目录
- 字符串
- 字符串与字符数组
- 字符串与指针
- 常量字符串
- 字符串的输入与输出
- 字符串的输出
- 字符串的输入
- 实现存放字符串的数组
字符串
字符串是由一连串字符组成的字符数据,C语言中并没有给字符串设置一个字符串的数据类型。所以字符串通常都是存放在字符数组中或者由字符指针指向这个字符串
由一个字符为起始位置,‘\0’为结束标志的字符集合称为字符串,字符串的元素个数是字符数加上字符的结束标志’\0’.
以最常见的“hello,world”为例,该字符串的存储形式为
字符串与字符数组
由于C语言并没有给字符串设定一个数据类型。所以不能用变量的形式来存储字符串。但是可以将字符串中的每个字符单独的存放到字符数组上
char str[12]="hello,world";
或者
char str[12] = { 'h','e','l','l','o',',', 'w','o','r','l','d','\0' };
这两个字符数组的存储形式如下:
需要注意的一点是,字符串一定是由‘\0’结尾的字符集合,如果字符数组中的元素不足够存放‘\0’的话,那么这个字符数组不能当做字符串使用。
通常来说,字符数组的元素多于存放字符串中,除了‘\0’以外的字符的话,字符数组会自动在末尾加上‘\0’。
以下是字符数组不能存放‘\0’的情况。
char str1[11]={“hello,world”};
char str2[11] = { 'h','e','l','l','o',',', 'w','o','r','l','d' };
由于字符数组的元素个数不能放下\0,所以不会在字符数组中的字符串末尾加上\0.
在str中的字符集合不能当做字符串使用
字符串与指针
字符串除了可以使用数组存放以外,也可以使用指针来指向字符串。
当使用指针指向字符串的时候,内存会开辟一段空间专门存放这段字符串,指针指向的是字符串的首元素
char*p="hello,world";
注意当使用指针来指向字符串时,字符串一定会有\0,不需要像字符数组留出一个位置来存放
常量字符串
当使用指针指向字符串时,该字符串在内存开辟的空间是不可以修改的,所以我们将这种指针指向的字符串成为字符串常量。
int main()
{
char* p = "hello,world";
*(p + 2) = 'a';//error
return 0;
}
运行这段代码可以发现程序崩溃。
由于常量字符串是没有访问权限的,所以为了提高程序的安全性,常常使用const来限至指针的取值,避免出现修改常量字符串的情况
const char*p="hello,world";
限定以后就能放心使用指针p来指向常量字符串了。此时对指针p进行访问操作时编译器会发生警告,方便我们定位程序中的bug。
那么常量字符串与字符数组的字符串的区别在于
对于常量字符串来说,重点在于字符串而不是字符串常量的指针,对于同一个常量字符串,他们的不同指针指向的地址都是该字符串的第一个元素。
而字符组会开辟两组不一样的内存空间来存放元素,因此即使这两个字符组的元素一致。也不会存放在相同的地址。
上面的概念有些绕,我们以一个代码来分析。
int main()
{
char str1[] = "hello,world";
char str2[] = "hello,world";
char* pstr1 = "hello,world";
char* pstr2 = "hello,world";
if (str1 == str2)
printf("str1=str2\n");
else
printf("str1!=str2\n");
if (pstr1 == pstr2)
printf("pstr1=pstr2\n");
else
printf("pstr1!=pstr2\n");
return 0;
}
运行可以发现
那么也就是说用字符数组存储的字符串,是将字符串存放到字符数组中,所以即使存放的是相同的字符串,str1与str2也不会是相同的字符数组的字符串。
而用字符指针指向的字符串是常量字符串,而常量字符串是单独存放在内存的某一块当中的,当两个指针指向相同的常量字符串时,指向的都是同一个地方。
字符串的输入与输出
字符串的输出
在格式串中,字符串的格式转换是%s,所以当使用输入/输出函数来输入/输出字符串时,使用%s来进行转换
int main()
{
char str1[12] = "hello,world";
printf("%s", str1);//向屏幕输出字符hello,world
return 0;
}
需要注意的是,%s对应的参数必须是字符类型的指针,在前面也提到过,数组名可以作为指向数组中首元素的地址的指针使用,所以(“%s”,str1)的str1是字符串“hello,world”中字符‘h’的地址。
还记得前面提到的字符串结束标志‘\0’吗,此时‘\0’的作用就体现出来了,当我们将字符串进行输入与输出时,当输出/读取到‘\0’时,停止对字符串的输入/输出操作。
int main()
{
char str1[] = { "hello,world\0reverie_ly" };
printf("%s", str1);
return 0;
}
运行程序发现,对str1中的字符串只读取到了“hello,world”。
由此发现,对字符串进行输出时,如果输出到了\0,就会停止输出。
字符串的输入
与字符串的输出格式类似,但是读入字符串时,还会由于读取到了‘\n’而停止读入。
char str1[20];
scanf("%s",str1);
实现存放字符串的数组
如果想要将多个字符串组合到一个数组当中,那么二维数组是一个很好的选择。
int main()
{
char str1[4][20] = { {"hello,world"},
{"reverie"},
{"cowboybebop"},
{"C programing"}
};
for (int i = 0; i < 4; i++)
{
printf("%s\n", str1[i]);
}
return 0;
}
可以发现用二维数组来存放字符串有两个问题
(1)数组当中的字符个数被限定住了,想要存储更多字符的字符串,就需要创建一个更多元素的二维数组
(2)可以发现,二维数组中的数据是很难填满的,这就导致了二维字符数组存放字符串会造成内存空间的浪费
如果想解决这些问题,我们就需要声明一个数组元素可大可小,能存储任意字符串,而且数组中的元素可以不用对齐的二维数组。
但是很可惜,C语言并没有规定这种二维数组的声明。
那么我们只能用另外一种方式来将这些字符串存储在一个数组当中
回顾上一个文章提到的,指针数组使用存放指针的数组,在这个文章中也提到了字符串可以作为指向字符串元素的指针来使用,那么就可以将字符串当做指针,存放在指针数组当中。
char *pstr1[4] = { {"hello,world"},
{"reverie"},
{"cowboybebop"},
{"C programing"}
};
如此使用指针数组就能实现存放字符串时,既可以不限定字符串的元素个数,又可以节省内存空间。