一、引言
在我们的生活中,有很多一长串的字符需要集中处理,比如说姓名、省份证号……
这时,我们就需要引入一个新的概念---字符串。
"hello world!"
这种由双引号引起来的一串字符称为字符串字面值,或者简称字符串。
注:用单引号引起的是一个字符,不能用一个单引号引两个及以上的字符。
'a'; // 字符a ' '; // 字符空格 'ab'; // err "abcdef"; // 字符串(由双引号引起的一串字符)
二、字符串的定义和存储
在C语言中,整型我们用int类型来开辟空间进行存储,字符类型我们又使用到了char,那么有没有一种类型可以存储字符串呢?
答案是没有的,C语言中没有一种类型可以直接存储字符串。
因为char是一个字节,只能存放一个字符。这时我们可以借助数组,数组是在内存中开辟一块连续的存储空间来进行存储多个数据类型相同的数据元素,所以通过字符数组我们可以存储字符串。
char arr[] = "hello world!";
上面代码就是采用了字符数组的方式来存储字符串。
1.字符串存储隐藏的'\0'
字符串的结束标志是一个'\0'的转义字符,在计算字符串长度的时候'\0'是结束标志,不算作字符串内容。'\0'被隐藏起来了。
因此上面的字符数组在内存中开辟了13Byte的存储空间(字符串字面值+隐藏的'\0')。
char arr[] = "hello world!";
// 在内存中字符串实际存储
'h'、'e'、'l'、'l'、'o'、' '、'w'、'o'、'r'、'l'、'd'、'!'、'\0'
下面我们通过几个例子来看一下'\0'对字符串的影响。
// 例子1
int main()
{
char ch1[] = "abcdef";
printf("%s", ch1); // %s打印字符串
return 0;
}
打印结果为abcdef,ch1字符数组中末尾有隐藏的'\0'结束标志,开辟了7个字节的空间,因此可以正常打印。
// 例子2
int main()
{
char ch2[] = { 'a','b','c','d','e','f' };
printf("%s", ch2);
return 0;
}
打印结果为abcdef后面跟上一堆乱码,就是因为ch2字符数组中没有'\0'结束标志,开辟了6个字节的空间。
// 例子3
int main()
{
char ch2[] = { 'a','b','c','d','e','f','\0' };
printf("%s", ch2);
return 0;
}
在例子2的基础上加上'\0',开辟了7个字节的空间,我们发现打印结果为abcdef,所以%s打印字符串时,直至遇到字符串结束标志'\0'时停止打印。
三、字符串的打印
1.%s方式进行打印
%d是整型十进制输入输出格式,%f打印单精度浮点数,%lf打印双精度浮点数,%c打印单个字符,%x打印十六进制数字。
那么,%s则是打印字符串的格式,遇到字符串结束标志'\0'停止打印。
int main()
{
char arr[] = "hello world!";
printf("%s\n", arr);
return 0;
}
2.循环方式进行打印
int main()
{
char arr[] = "hello world!";
for(int i = 0; i <= (sizeof(arr) / sizeof(char) - 2); i++)
{
printf("%c",arr[i]);
}
return 0;
}
①sizeof(arr)计算字符数组所占空间大小,sizeof(char)计算字符数组中每个字符元素的大小,二者相除sizeof(arr) / sizeof(char) 可以得到字符数组存储字符的个数。
②由于数组下标与元素位序有1的位差,并且最后一个字符'\0'不需要打印,所以sizeof(arr) / sizeof(char) - 2可以得到最后一个字符的数组下标。
四、字符串的长度
在C语言中,求字符串的长度需要借助strlen()函数,需要包含string.h的头文件。
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "hello world!";
printf("%d\n", strlen(arr));
return 0;
}
最终输出的结果是12,注意空格也算一个字符。
那么,如果字符串的定义采用下面的方式定义呢?
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = { 'h','e','l','l','o',' ','w','o','r','l','d','!' };
printf("%d\n", strlen(arr));
return 0;
}
我们此时却发现,打印的结果竟然是随机值。
这是因为字符串的结束标志是一个'\0'的转义字符。在计算字符串长度的时候'\0'是结束标志,不算作字符串内容。
第一个代码在'!'后面隐藏了'\0',当算长度时读到隐藏的'\0'停止计算(不统计'\0'),故而结果为12。
第二个代码是数组的常规初始化,'!'后面并没有'\0'转义字符,当算长度时未读到'\0',故一直往下统计直至遇到'\0',因此产生的输出结果为随机值。
在第二个代码的基础上稍作修改,就能计算正确的长度,我们只需要在末尾加上'\0'的转义字符就可以了。如下代码:
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = { 'h','e','l','l','o',' ','w','o','r','l','d','!','\0' };
printf("%d\n", strlen(arr));
return 0;
}
五、字符数组的大小
计算数组类型的大小我们需要借助sizeof关键字,单位为字节。
int main()
{
char arr[] = "hello world!";
printf("%d\n", sizeof(arr));
return 0;
}
上面代码由于字符串隐藏了'\0',而'\0'在数组中也开辟占用了一块存储空间,所以上面代码输出的结果为13。
int main()
{
char arr[] = { 'h','e','l','l','o',' ','w','o','r','l','d','!' };
printf("%d\n", sizeof(arr));
return 0;
}
上面代码由于该字符数组末位没有'\0',所以最后数组大小计算为12。
int main()
{
char arr[] = { 'h','e','l','l','o',' ','w','o','r','l','d','!','\0' };
printf("%d\n", sizeof(arr));
return 0;
}
上面代码由于该字符数组末位有'\0',所以最后数组大小计算为13。
六、区分sizeof()和strlen()
sizeof()和strlen()二者之间并没有必然的联系。
sizeof是C语言常见32个关键字之一,是计算类型或者变量所占内存空间的大小(单位为字节)。
strlen是库函数,需要包含string.h的头文件,是用来计算字符串的长度,遇到'\0'停止计算(结果不包含'\0'在内)。
下面,我通过一个代码来进行演示
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "dengfenglai";
char arr2[] = { 'd','e','n','g','f','e','n','g','l','a','i' };
char arr3[] = { 'd','e','n','g','f','e','n','g','l','a','i','\0' };
printf("%d\n", strlen(arr1)); // 11
printf("%d\n", strlen(arr2)); // 随机值
printf("%d\n", strlen(arr3)); // 11
printf("%d\n", sizeof(arr1)); // 12
printf("%d\n", sizeof(arr2)); // 11
printf("%d\n", sizeof(arr3)); // 12
return 0;
}
通过上面代码以及注释里面的答案,可以帮助我们更好地理解。