在我们学习当中,总会听到字符数组和字符串这样的名词,那么,字符数组是怎样定义的?字符串又是怎样定义的?
一、定义以及初始化方式
1、字符数组:用来存放字符类型数据的数组
2、字符串:以""号包括的字符/序列。字符串的的结尾标志是'\0',也就是说只要有'\0'的都是字符串。
下面通过一些例子来认识一下。
char arr[10] = {'a','b','c'};//字符串(它的升序部分均为'\0')
char brr[] = {'a','b','c'};//字符数组
char crr[10] = {"abc"};//字符串(字符数组特有的初始化方式)
char drr[10] = "abc";//字符串(字符数组特有的初始化方式)
char err[] = "abc";//字符串(字符数组特有的初始化方式)
char frr[10] = " ";//字符串(字符数组特有的初始化方式)
二、关于字符串的操作
字符串拷贝、连接、比较、求有效长度等函数在字符串的库函数当中是存在的,但我们可以通过写出这些函数了解其原理。
1、字符串拷贝(多种方式操作)
拷贝也就是将一个字符串复制到另一个字符串中,在此函数中要注意,被复制的字符串长度和复制的字符串长度,防止越界操作。
/*
void Mystrcpy1(char *des,char *src)
{
int i;
for(i=0;*(src+i)!='\0';i++)
{
*(des+i) = *(src+i);
}
*(des+i) = '\0';
}
*/
/*
void Mystrcpy2(char *des,char *src)
{
int i;
for(i=0;src[i]!='\0';i++)
{
des[i] = src[i];
}
des[i] = '\0';
}
*/
/*
void Mystrcpy3(char *des,char *src)
{
assert(des != NULL && src != NULL);
while(*src != '\0')
{
*des = *src;
des++;
src++;
}
*des = '\0';
}
*/
/*
void Mystrcpy4(char *des,char *src)//++和*的优先级一样,按照运算法则,从右向左运算。
{
assert(des != NULL && src != NULL);
while(*src != '\0')
{
//*des++ = *src++;
*(des++)=*(src++);//等价
}
*des = '\0';
}
*/
/*
void Mystrcpy5(char *des,char *src)
{
assert(des != NULL && src != NULL);
if(des == NULL && src == NULL)
{
return ;
}
while(*des++ = *src++);//当为'\0'时,while为0,循环为假,循环结束
*des = '\0';
}
*/
/*
char *Mystrcpy6(char *des,char *src)
//返回值的目的:支持链式表达
//返回目标字符串的首地址
{
char *p = des;//保存首地址
while(*des++ = *src++);//当为'\0'时,while为0,循环为假,循环结束
return p;
}
*/
2、字符串连接
连接函数,即将一个字符串连接到另一个字符串中。同样,注意不能越界操作。
/*
char *Mystrcat(char *des,const char *src)
{
assert(des!=NULL && src!=NULL);
if(des==NULL || src==NULL)
{
return des;
}
char *p = des;
while(*des != '\0')
{
des++;
}
while(*des++ = *src++);
return p;
}
*/
3、字符串比较
字符串的比较是按照ASSCII码顺序比较两个数组中的字符。
/*
int Mystrcmp(const char *des,const char *src)
{
assert(des);
assert(src);
int gap;
while((gap=*des-*src)==0 && *src!='\0')
{
des++;
src++;
}
return gap;
}
*/
4、求有效长度
/*
int Mystrlen(const char *des)
{
assert(des != NULL);
if(des == NULL)
{
return 0;
}
int len = 0;
for(int i = 0;des[i] != '\0';i++)
{
len++;
}
return len;
}
*/
三、区分字符串常量和字符数组
在上述有关字符串的操作函数当中,多次提到越界的问题。
那么,我们就来讨论造成字符串函数崩溃存在的原因并区分哪些是字符串常量哪些是字符数组。
1、区分字符串常量和字符数组
首先,看以下的例子:
char *str1 = "abcde";(1)
char str2[] = "abcde";(2)
str1是一个指针,它保存的应该是常量"abcde"区的地址。因此(1)占4个字节,并且它是一个字符串常量
str2是一个字符数组,有'\0',因此也是字符串。
因此,若对于str1有如下的操作:
str1[0] = 'x' ;<==> *(str1) = 'x';<写入错误>
这一语句语法上是没有问题的。但是由于*str1为指向长两只,不允许改动,出现写入位置冲突,程序会崩溃。
但对于str2就可以做 str2[0] = 'x';操作。
总结:
(1)字符串常量:不可以修改
(2)字符数组:自己定义,可以修改
2、字符串函数的崩溃原因
strcpy(str1,"xya");//常量,写入错误
strcpy(str2."Hello World");//越界操作
总结:
崩溃的两大原因:(1)试图修改字符串常量的值
(2)越界