字符串是有序字符的集合,C语言中没有字符串的概念,C语言中通过特殊的字符数组模拟字符串,C语言中的字符串是以‘\0’结尾的字符数组,双引号引用的单个或者多个字符是一种特殊的字面量,存储于程序的全局只读存储区,本质为字符数组,可以看成作是常量指针,也就是说这个字符数组在程序运行中是不能被改变的,编译器自动在结尾上加上‘\0’字符,要注意的是字符串字面量至少包含一个‘\0’字符,空字符并不是指什么字符都没有,是指只包含一个反斜杠字符,在指定字符串数组大小时,要确保数组元素的个数至少比字符串长度多1(为了容纳空字符).所有未被使用的元素都被初始化为0(0指的是char形式的空字符,不是数字字符0)
char *p1 = “hyy”,char p2[] = "hyy"这两种方式有什么区别
通常字符串作为可执行文件的一部分存储在数据段中,当把程序载入内存时,也载入了程序的字符串,字符串存储在静态存储区中,但是,程序开始运行时才会为数组分配内存,此时,才将字符串拷贝到数组中,注意,此时字符串有两个剧本,一个是在静态内存中的字符串字面量,另一个是存储在数组p2中的字符串
此后,编译器便把数组名p2识别为该数组首元素地址(&p2[0])的别名。这里关键要理解,在数组形式中,p2是地址常量.不能更改p2,如果 改变了p2,则意味着改变了数组的存储位置(即地址)。可以进行类似 p2+1这样的操作,标识数组的下一个元素。但是不允许进行++p2这样的操作,递增运算符只能用于变量名前(或概括地说,只能用于可修改的左 值),不能用于常量
指针形式(*p1)也使得编译器为字符串在静态存储区预留4个元素的 空间。另外,一旦开始执行程序,它会为指针变量p1留出一个储存位置,并把字符串的地址储存在指针变量中。该变量最初指向该字符串的首字符,但是它的值可以改变。因此,可以使用递增运算符。例如,++p1将指向第 2 个字符(o)。
总之,初始化数组把静态存储区的字符串拷贝到数组中,而初始化指针 只把字符串的地址拷贝给指针。
代码:
#include <stdio.h>
int main(int argc,char *argv[])
{
char a = “ccc”[0];
char b = *(“123”+1);
char c = *"";
printf(“a=%c\n”,a);
printf(“b=%c\n”,b);
printf(“c=%c\n”,c);
}
结果:
sice@sice:~$ ./a.out
a=c
b=2
c=0
这个程序验证的是字符串字面量本质是存储于只读存储区的数组,我们先看a, 这里的"ccc"其实是一个没有名字的字符数组,后面的[0]表示的是这个字符数组的第一个元素,我们看b,"123"其实也是没有名字的字符数组,+1表示指针运算,所以是第二个元素2,最后一个c是空字符,所以只打印0
字符串的长度就是字符串所包含字符的个数,字符串长度指的是第一个’\0’字符前出现的字符个数,函数strlen用返回字符串的长度
代码:
#include <stdio.h>
#include <string.h>
int main(int argc,char **argv)
{
char a[]=“helloworld”;
char b[]=“helloworld\0china”;
printf("%d\n",strlen(a));
printf("%d\n",strlen(b));
return 0;
}
结果:
sice@sice:~$ ./a.out
10
10
这就是我们说的’\0’,所有的字符串函数都依赖这个’\0’,只以第一个’\0’作为结束符
案例分析1
#include <stdio.h>
int main()
{
char buf[10]={0};
char src[] = “hello %s”;
snprintf(buf,sizeof(buf),src);
printf(“buf = %s\n”,buf);
return 0;
}
结果:
sice@sice:~$ ./a.out
buf = hello ��
为什么会出现这种结果呢,这个是snprintf函数的特性导致的,该函数本身是可变参数函数,当函数只有3个参数时,如果第三个参数没有包含格式化信息,函数调用没有问题;相反,如果第三个参数包含了格式化信息,但缺少后续对应参数,则程序行为不确定,我们这里的字符串有带"%s"所以缺少了对应参数,修改为
snprintf(buf,sizeof(buf),src,“yyy”);
结果为
sice@sice:~$ ./a.out
buf = hello yyy
案例分析2
#include <stdio.h>
#include <string.h>
int main()
{
#define S1 “D.T.Software”
#define S2 “D.T.Software”
if( S1 == S2 )
{
printf("Equal\n");
}
else
{
printf("Non Equal\n");
}
if( strcmp(S1, S2) == 0 )
{
printf("Equal\n");
}
else
{
printf("Non Equal\n");
}
return 0;
}
结果:
sice@sice:~$ ./a.out
Equal
Equal
strcmp比较的是字符串的内容是否一模一样,显而易见的是Equal,这点不存在疑问,第一个比较为什么会为真呢,明明是占用不同的内存空间,这其实是gcc编译的优化而已,当它发现第一个宏和第二个宏的字符数组内容一致时,就将其映射到同一个无名数组,在其他平台下并不会Equal,跟平台有关,这个例子告诉我们字符串的比较一定要用strcmp函数完成
以上内容部分参考狄泰软件学院