一、什么是字符串?
在 C 语言中,字符串实际上是使用空字符 \0 结尾的一维字符数组。因此,\0 是用于标记字符串的结束。
空字符(Null character)又称结束符,缩写 NULL,是一个数值为 0 的控制字符,\0 是转义字符,意思是告诉编译器,这不是字符 0,而是空字符。
二、字符串的输入和输出
#include <stdio.h>
int main()
{
//字符串的定义
char cdata1[] = "I am a student";
char cdata2[15] = {'I','\0','a','m','\0','a','\0','s','t','u','d','e','n','t','\0'};
char *p = "I am a student"//字符串常量,不允许被修改
/*字符数组的输入输出可以有两种方法。
(1)逐个字符输入输出。用格式符“%c”输入或输出一个字符
(2)将整个字符串一次输入或输出。用“%s”格式符,意思是对字符串(string)的输入输出*/
for(int i=0;i<15;i++){
printf("%c",cdata2[i]);
}
printf("\n%s",cdata1);
printf("\n%s",cdata2);//用%s输出cdata2,遇到空字符会提前结束打印
return 0;
}
/*运行结果
I am a student
I am a student
I*/
三、处理字符串的常见函数
1、puts函数
输出字符串的函数
一般形式 puts(str);
str -- 这是要被写入的C字符串。
自带换行符,其作用是将一个字符串(以'\0'结束的字符序列)输出到终端。
2、gets函数
输入字符串的函数
一般形式 gets(str);
str -- 这是指向一个字符数组的指针,该数组存储了C字符串。
其作用是从终端输入一个字符串到字符数组,并且得到一个函数值。该函数值是字符数组的起始地址。
3、strcat函数
字符串连接函数
一般形式 strcat(str1,str2);
其作用是把两个字符串连接起来:
将字符串str2连到字符串str1后面。函数调用后得到字符串str1的地址。
函数原型 char *strcat(char *dest, const char *src);
dest -- 指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串。
src -- 指向要追加的字符串,该字符串不会覆盖目标字符串。
//strcat函数使用方法
#include <stdio.h>
#include <string.h>
#include <assert.h>//assert的头文件
int main()
{
//char *strcat(char *dest, const char *src);函数原型
char str1[] = "Changcheng";
char str2[] = " Pao!";
strcat(str1,str2);
printf("%s",str1);
return 0;
}
/*运行结果:
Changcheng Pao!*/
//strcat的函数实现
char *myStrcat(char*dest,const char *src)
{
if(dest == NULL && src == NULL){//先判断两个字符串是否为空
return NULL;
}
char *bak = dest;//先将dest的地址备份
while(*dest != '\0'){//定位到dest的末尾
dest++;
}
while(*dest++ = *src++);//将src的内容复制到dest的末尾
*dest = '\0';//字符串以'\0'为结尾
return bak;//将dest原地址返回
}
char *myStrcat2(char*dest,const char *src)
{
assert(dest != NULL && src != NULL);//断言函数,如果为空函数则终止程序运行
char *bak = dest;//先将dest的地址备份
for(;*dest!='\0';dest++);//定位到dest的末尾
while(*dest++ = *src++);//将src的内容复制到dest的末尾
*dest = '\0';//字符串以'\0'为结尾
return bak;//将dest原地址返回
}
4、strcpy 和 strncpy函数
字符串复制函数
strcpy的一般形式 strcpy(str1,str2);
其作用是将字符串str2复制到字符串str1中
函数原型 char *strcpy(char *dest, const char *src)
dest -- 指向用于存储复制内容的目标数组。
src -- 要复制的字符串。
strncpy的一般形式 strncpy(str1,str2,n); 其作用是将字符串str2的前n个字符串复制到字符串str1中,当 str2的长度小于 n 时,str1的剩余部分将用空字节填充。
函数原型 char *strncpy(char *dest, const char *src, size_t n);
dest -- 指向用于存储复制内容的目标数组。
src -- 要复制的字符串。
n -- 要从源中复制的字符数。
//strcpy函数使用方法
#include <stdio.h>
#include <string.h>
#include <assert.h>//assert的头文件
int main()
{
char str1[12];
char str2[12];
char *p = "Sun Wukong";
strcpy(str1,p);//将p的值复制给str1
strncpy(str2,p,3);//将p的前三个值复制给str2
printf("str1的值是%s\n",str1);
printf("str2的值是%s\n",str2);
return 0;
}
/*运行结果:
str1的值是Sun Wukong
str2的值是Sun*/
//strcpy的函数实现
char *myStrcpy(char *dest, const char *src)
{
assert(dest!=NULL && src != NULL);//断言函数,如果两个字符串都为空,直接退出程序
char *bak = dest;
while(*src != '\0'){//将src空字符之前的数据复制给dest
*dest = *src;
*dest++;
*src++;
}
*dest = '\0';//字符串以'\0'为结尾
return bak;
}
char *myStrcpy2(char *dest, const char *src)
{
assert(dest!=NULL && src != NULL);//断言函数,如果两个字符串都为空,直接退出程序
char *bak = dest;
while(*src != '\0'){
*dest++ = *src++;
}
*dest = '\0';
return bak;
}
char *myStrcpy3(char *dest, const char *src)
{
assert(dest!=NULL && src != NULL);//断言函数,如果两个字符串都为空,直接退出程序
char *bak = dest;
while((*dest++ = *src++) != '\0');
*dest = '\0';
return bak;
}
//strncpy的函数实现
char *myStrncpy(char *dest, const char *src, size_t n)
{
assert(dest!=NULL && src != NULL);//断言函数,如果两个字符串都为空,直接退出程序
char *bak = dest;
while(*src != '\0' && n>0){//将src的前n个字符复制给dest
*dest++ = *src++;
n--;
}
*dest = '\0';
if(n>0){//src的长度小于n时,将src全部复制到dest中,n剩下的值全部赋0\给dest;
n--;
*dest = '\0';
}
return bak;
}
5、strcmp函数
字符串比较函数
一般形式 strcmp(str1,str2) 其作用为将字符串str1和str2比较
函数原型 int strncmp(const char *str1, const char *str2)
str1 -- 要进行比较的第一个字符串。
str2 -- 要进行比较的第二个字符串。
字符串比较的规则是:将两个字符串自左至右逐个字符相比(按ASCII码值大小比较),直到出现不同的字符或遇到'0'为止。
(1)如全部字符相同,则认为两个字符串相等;
(2)若出现不相同的字符,则以第1对不相同的字符的比较结果为准。例如:
"A"<"B" ,"a">"A","computer">"compare" ,"these">"that", "1A">"$20","CHINA">"CANADA","DOG"<"cat","Tsinghua">"TSINGHUA"
比较的结果由函数值带回:
(1)如果字符串str1=字符串str2,则函数值为0。
(2)如果字符串str1>字符串str2,则函数值为一个正整数。
(3)如果字符串str1<字符串str2,则函数值为一个负整数。
//strcmp函数使用方法
#include <stdio.h>
#include <string.h>
#include <assert.h>//assert的头文件
int main()
{
int a;
int b;
int c;
char str1[] = "app";
char str2[] = "app";
a = strcmp(str1,str2);
char str3[] = "hallo";
char str4[] = "hello";
b = strcmp(str3,str4);//a<e
char str5[] = "Dog";
char str6[] = "Dod";
c = strcmp(str3,str4);//g>d
printf("%d ",a);
printf("%d ",b);
printf("%d ",c);
}
/*运行结果
0 -1 1*/
//strcmp的函数实现
int myStrncmp(const char *str1, const char *str2)
{
int ret;
assert(str1!=NULL && str2 != NULL);//断言函数,如果两个字符串都为空,直接退出程序
while(*str1 && *str2 && (*str1 == *str2)){
str1++;
str2++;
}
ret = *str1 - *str2;
if(ret>0){
ret = 1;
}
if(ret<0){
ret = -1;
}
return ret;
}
//strcmp只能比较当字符串出现第一个字符不相等时的字符大小
//如果想完全比较两个字符串的大小可以将两个字符串的ASCII码全部加起来之后再比较
int myStrncmp(const char *str1, const char *str2)
{
int ret;
int cnt1 = 0;
int cnt2 = 0;
assert(str1!=NULL && str2 != NULL);//断言函数,如果两个字符串都为空,直接退出程序
while(*str1 && *str2 && (*str1 == *str2)){
str1++;
str2++;
}//先让两个字符串相等或者不为0的地址向后偏移
while(*str1){
cnt1 = cnt1 + *str1;
str1++;
}
while(*str2){
cnt2 = cnt2 + *str2;
str2++;
}
ret = cnt1 - cnt2;
if(ret>0){
ret = 1;
}
if(ret<0){
ret = -1;
}
return ret;
}
6、strstr函数
定位子字符串的函数
一般形式 strstr(str1,str2)
在str1中找str2出现的位置,返回str2的字符串在str1字符串第一次出现的位置,不包含终止符 '\0'。如果没有找到或者str2不是str1的一部分,则返回null指针。
函数原型 char *strstr(const char *haystack, const char *needle);
haystack -- 要被检索的 C 字符串。
needle -- 在 haystack 字符串内要搜索的小字符串。
//strstr函数使用方法
#include <stdio.h>
#include <string.h>
#include <assert.h>//assert的头文件
int main()
{
char str1[] = "hello word!";
char str2[] = "wo";
char* ret = strstr(str1,str2);
if (ret == NULL)
printf("找不到!\n");
else
printf("%s\n", ret);
return 0;
}
/*运行结果
word!*/
//strstr函数实现
char *myStrstr( char *str1, char *str2)
{
assert(str1!=NULL && str2 != NULL);//断言,先处理空字符
char *s1 = str1;//遍历指向str1的字符串
char *s2 = str2;//遍历指向str2的字符串
char *p;
p = str1;//记录开始遍历的位置
while(*p){
s1 = p;//让s1指向p偏移的位置
s2 = str2;//让s2重新指向第一个字符位置
while(*s1 && *s2 && (*s1 == *s2)){//遍历str1和str2相等的字符
s1++;
s2++;
}
if(*s2 == '\0'){//如果找到str2所有的字符,返回该位置的指针
return p;
}
p++;
}
return NULL;
}
7、strlen函数和sizeof关键字
sizeof() 和 strlen() 在 C 语言中两个非常常用,它们都与计算内存大小有关,但是它们的作用是不同的。
1、strlen:这个函数用于计算字符串(char数组)中字符的数量,不包括结束符'\0'。它返回的是一个整数,表示实际字符的数量。
2、sizeof:这是一个运算符,用于获取数据类型或变量在内存中占用的字节数。它可以用于任何数据类型,如基本类型、结构体、数组等,返回的是一个整数。
sizeof() 和 strlen() 的主要区别在于:
sizeof() 是一个关键字、运算符,而 strlen() 是一个函数。
sizeof() 计算的是变量或类型所占用的内存字节数,而 strlen() 计算的是字符串中字符的个数。
sizeof() 可以用于任何类型的数据,而 strlen() 只能用于以空字符 '\0' 结尾的字符串。
sizeof() 计算字符串的长度,包含末尾的 '\0',strlen() 计算字符串的长度,不包含字符串末尾的 '\0'。
总结来说:
sizeof关心的是内存占用空间的大小,计算的是实际长度
strlen关注的是字符数组的内容长度,计算的是有效长度
int main()
{
//sizeof和strlen的区别
//sizeof计算的是数组的实际长度,strlen计算的是数组的有效长度
char cdata[128] = "hello";
void (*ptest)();
ptest = test;
printf("sizeof:%d\n",sizeof(cdata));//sizeof计算得出cdata[]的大小是 128
printf("strlen:%d\n",strlen(cdata));//strlen计算得出cdata[]的大小是 5
char *p = "hello";
//*p是一个char *,sizeof来计算的时候,得出的是计算机用多少字节表示一个地址
printf("sizeof:p %d\n",sizeof(p)); //sizeof 8
printf("strlen:p %d\n",strlen(p)); //strlen计算得出p的大小是 5
printf("sizeof:char * %d\n",sizeof(char *));//char *的大小是 8
printf("sizeof:int * %d\n",sizeof(int *)); //int *的大小是 8
printf("sizeof:char %d\n",sizeof(char )); //char 的大小是 1
printf("sizeof:ptest %d\n",sizeof(ptest)); //ptest的大小是 8
return 0;
}
/*运行结果
sizeof:128
strlen:5
sizeof:p 8
strlen:p 5
sizeof:char * 8
sizeof:int * 8
sizeof:char 1
sizeof:ptest 8
*/