初学者对C语言的爱恨情仇之神秘的字符串

前言

本文是针对对字符串有疑惑的初学者。例如:对C语言中的字符串并不了解,不太会使用。学过其他编程语言,现在转入了C语言,但是在C语言中使用字符串时不能像Java一样如愿以偿,自由自在的使用。那么就可以看本篇文章,本篇文章不会涉及太深的东西,太深的东西对于初学者会受不了的。

字符串是谁

说到字符串是谁,那么需要提一下字符是什么,没有字符就没有字符串。

像我们学的“每一个”英文字符(a,b,c…)都是属于字符,并且汉字、数字、标点符号都是属于一个字符;

像“我是谁,我在哪”这7个字符合起来就是一个字符串。那么串的话其实就是多个字符合在一起的结果。

经常听说字符串字面量,究竟是什么鬼?

经常听别人说字符串字面量,字面量的这是啥呢?

其实你一点也磨陌生,可能只是对这个名字陌生一些,你在学习Hello World的时候,其实就在用了。没错用双引号包含的“Hello World”就是字符串字面量。

printf("Hello World!");

执行结果:

Hello World!

我们想换行时,可以加个\n:

printf("Hello  \n   World!");

结果:

Hello  
   World!

字符串字面量如何存储的

例如字符串:"Hello World!"

你看着是一个字符串,实际上在存储的时候,是像数组一样,一个字符一个字符分开存的。

[“H”,“e”,“l”,“l”,“o”," “,“W”,“o”,“r”,“l”,“d”,”!","\0"];

在存储的时候,每个字符串的结尾是包含"\0",所以一般我们如果不知道一个字符串的长度如何遍历每个字符呢?那就可以使用"\0"条件来判断。

C语言字符数组与字符指针

我们可以利用char类型的数组,来定义和初始化字符串。

char str[12] = "I Love You!";
char *pStr = "I Love You!";

我们在打印的时候,需要使用%s来格式化数值:

printf("str=%s\n",str);
printf("pStr=%s\n",pStr);

打印结果:

str=I Love You!
pStr=I Love You!

也支持多种单个访问方式:

printf("*(str+2)=%c\n",*(str+2));
printf("*(pStr+2)=%c\n",*(pStr+2));

结果:

*(str+2)=L
*(pStr+2)=L

C语言中的字符串库

在Java中有String类型的jar包,在C语言中也有相应的字符串库。无论是Java中的jar包,还是C语言中的库。其实都是一些封装好的工具,以便给他人使用。

在实际开发中,我们掌握这些库的基本用法是必须的,可以大大的提高我们的工作效率。

在Linux中我们可以使用man命令来查看帮助手册。

例如:

man string

会出现下面这样的结果:
在这里插入图片描述

可以看到:
在这里插入图片描述

这些都是我现在这个Ubuntu系统中的string库中所提供的一些功能的函数。

在此我带着熟悉几个常用的函数。

我挑选了几个常用的,其实也就四种:统计字符串中的字符个数、字符串拼接、字符串比较、字符串拷贝/赋值。

SYNOPSIS
       #include <string.h>

       size_t strlen(const char *s);
              Return the length of the string s.

       char *strcat(char *dest, const char *src);
              Append the string src to the string dest, returning a pointer dest.
              
       char *strncat(char *dest, const char *src, size_t n);
              Append at most n bytes from the string src to the string dest, returning a pointer to dest.

       int strcmp(const char *s1, const char *s2);
              Compare the strings s1 with s2.

       int strncmp(const char *s1, const char *s2, size_t n);
              Compare at most n bytes of the strings s1 and s2.

       char *strcpy(char *dest, const char *src);
              Copy the string src to dest, returning a pointer to the start of dest.

       char *strncpy(char *dest, const char *src, size_t n);
              Copy at most n bytes from string src to dest, returning a pointer to the start of dest.

我们如何想使用的话,需要先include一下头文件:

本次使用的代码框架如下:

#include <stdio.h>
#include <string.h>

int main(void)
{
        return 0;
}

1、strlen函数

从函数的名字上也不难看出,这个是跟字符串和长度有关系的函数。

如果第一次使用的话,可以使用:man strlen来查看这个函数的使用说明。

在这里插入图片描述

解释的非常详细。

可以看到strlen()函数在计算传入的字符串s的时候是不计算结束符"\0"的。

返回值是传入字符串s的字节数/字符格式。

#include <stdio.h>
#include <string.h>

int main(void)
{
        char str[12] = "I Love You!";
        char *pStr = "I Love You!";


        printf("str=%s\n",str);
        printf("pStr=%s\n",pStr);

        int strLen = strlen(str);
        int pStrLen = strlen(pStr);

        printf("str len:%d \n",strLen);
        printf("pStr len:%d \n",pStrLen);

        return 0;
}

结果:

可以看到无论是字符数组还是字符指针,都是可以统计出来有多少个字符的

zhenghui@zhlinux:~/桌面/code/string$ 
zhenghui@zhlinux:~/桌面/code/string$ make strtest && ./strtest 
cc     strtest.c   -o strtest
str=I Love You!
pStr=I Love You!
str len:11 
pStr len:11 
zhenghui@zhlinux:~/桌面/code/string$ 

计算时到底有没有跟数组的大小有关系?

	char str[12] = "I Love You!";
	char str2[100] = "I Love You!";
	char str3[100] = "I        Love      You!   ";
	
	int strLen = strlen(str);
	int strLen2 = strlen(str2);
	int strLen3 = strlen(str3);



	printf("str len:%d \n",strLen);
	printf("str2 len:%d \n",strLen2);
	printf("str3 len:%d \n",strLen3);

打印结果:

str len:11 
str2 len:11 
str3 len:26 

可以看到str2和str统计的数量是一样的。

从上面结果来看,数组的大小并不决定这个字符串的长度。

strlen函数只统计“\0”结尾之前的字数,而且不算“\0”这个字符。

2、strcat 和 strncat函数

不了解strcat函数可以直接在linux的命令行中输入:man strcat

就可以看到有两个相关的函数:

SYNOPSIS
       #include <string.h>

       char *strcat(char *dest, const char *src);

       char *strncat(char *dest, const char *src, size_t n);

还有很详细的说文。

The  strcat()  function  appends  the src string to the dest string, overwriting the terminating null byte
       ('\0') at the end of dest, and then adds a terminating null byte.  The strings may not  overlap,  and  the
       dest  string  must have enough space for the result.  If dest is not large enough, program behavior is un‐
       predictable; buffer overruns are a favorite avenue for attacking secure programs.

这个strcat函数是用来拼接字符串的,分别传入dest和src字符串,最终把src拼接到dest中进行返回。

实验代码:

zhenghui@zhlinux:~/桌面/code/string$ 
zhenghui@zhlinux:~/桌面/code/string$ cat strcatTest.c 
#include <stdio.h>
#include <string.h>

int main(void)
{
	char str1[12] = " I ";
	char str2[100] = " Love ";
	char *pStr = " You!iiiiii ";


	int sl = strlen(str1);
	printf("str1 len :%d \n",sl);

	printf("str1=%s\n",str1);
	printf("str2=%s\n",str2);
	printf("pStr=%s\n",pStr);

	strcat(str1,str2);
	strcat(str1,pStr);

	printf("#####################\n");
	printf("str1 :%s \n",str1);
	sl = strlen(str1);
	printf("str1 len :%d \n",sl);

	return 0;
}
zhenghui@zhlinux:~/桌面/code/string$

执行结果:

用法很简单,就是传入两个需要拼接的字符串即可

zhenghui@zhlinux:~/桌面/code/string$ make strcatTest && ./strcatTest
cc     strcatTest.c   -o strcatTest
str1 len :3 
str1= I 
str2= Love 
pStr= You!iiiiii 
#####################
str1 : I  Love  You!iiiiii  
str1 len :21 
zhenghui@zhlinux:~/桌面/code/string$ 

相比较来说,strncat比strcat安全一些。

例如:

如果a的空间是有限的,b的长度又很大。那么就会超出了a的大小。
那么为了安全,就可以使用strncat来指定拼接的大小。

strcat(a,b);

为了安全,我们可以使用strncat:

zhenghui@zhlinux:~/桌面/code/string$ 
zhenghui@zhlinux:~/桌面/code/string$ 
zhenghui@zhlinux:~/桌面/code/string$ cat strcatTest.c 
#include <stdio.h>
#include <string.h>

int main(void)
{
	char str1[12] = " I ";
	char str2[100] = " Love ";
	char *pStr = " You!iiiiii ";


	int sl = strlen(str1);
	printf("str1 len :%d \n",sl);

	printf("str1=%s\n",str1);
	printf("str2=%s\n",str2);
	printf("pStr=%s\n",pStr);

	//strcat(str1,str2);
	//strcat(str1,pStr);
	
	strncat(str1,str2,sizeof(str1) - strlen(str1) - 1);
	strncat(str1,pStr,sizeof(str1) - strlen(str1) - 1);

	printf("#####################\n");
	printf("str1 :%s \n",str1);
	sl = strlen(str1);
	printf("str1 len :%d \n",sl);

	return 0;
}
zhenghui@zhlinux:~/桌面/code/string$ 

可以看到结果也是正常的:

zhenghui@zhlinux:~/桌面/code/string$ make strcatTest && ./strcatTest
cc     strcatTest.c   -o strcatTest
str1 len :3 
str1= I 
str2= Love 
pStr= You!iiiiii 
#####################
str1 : I  Love  Y 
str1 len :11 
zhenghui@zhlinux:~/桌面/code/string$ 

我们使用sizeof(str1) - strlen(str1)就可以计算出str1所剩余的空间,-1是为了给“\0”留出空间。

strncat(str1,str2,sizeof(str1) - strlen(str1) - 1);

3、strcmp 和 strncmp函数

在C语言日常开发中,strcmp是非常常用的,我们做字符串比较,两个字符串是否相等,我们直接调用这个函数就可以很好的解决这个难题。

我们仍然可以使用:man strcmp来查看帮助手册:

SYNOPSIS
       #include <string.h>

       int strcmp(const char *s1, const char *s2);

       int strncmp(const char *s1, const char *s2, size_t n);

DESCRIPTION
       The strcmp() function compares the two strings s1 and s2.  The locale is not taken into account (for a lo‐
       cale-aware comparison, see strcoll(3)).  It returns an integer less than, equal to, or greater  than  zero
       if s1 is found, respectively, to be less than, to match, or be greater than s2.

       The strncmp() function is similar, except it compares only the first (at most) n bytes of s1 and s2.

RETURN VALUE
       The strcmp() and strncmp() functions return an integer less than, equal to, or greater than zero if s1 (or
       the first n bytes thereof) is found, respectively, to be less than, to match, or be greater than s2.

这是用来比较两个字符串的。

原型如下:

SYNOPSIS
       #include <string.h>

       int strcmp(const char *s1, const char *s2);

       int strncmp(const char *s1, const char *s2, size_t n);

我们需要传递两个字符串s1和s2;

返回值是:

返回值是一个大于、小于或等于0的值。
如果strcmp(s1,s2)==0:说明s1和s2相等;
如果strcmp(s1,s2) > 0:说明s1 > s2;
如果strcmp(s1,s2) < 0:说明s1 < s2;
当然了<=和>=运算符也是可以使用的。

RETURN VALUE
       The strcmp() and strncmp() functions return an integer less than, equal to, or greater than zero if s1 (or
       the first n bytes thereof) is found, respectively, to be less than, to match, or be greater than s2.

实验代码:

zhenghui@zhlinux:~/桌面/code/string$ cat strcmpTest.c 
#include <stdio.h>
#include <string.h>

int main(void)
{
	char str1[12] = "abc";
	char *str2 = "ABC";

	printf("str1=%s\n",str1);
	printf("str2=%s\n",str2);

	printf("#####################\n");
	
	int res1 = strcmp(str1,str2);
	printf("strcmp(str1,str2) :%d \n",res1);

	int res2 = strcmp(str2,str1);
	printf("strcmp(str2,str1) :%d \n",res2);

	if(res1 > 0)
	{
		printf("res1:%s > %s \n",str1,str2);
	}

	if(res2 < 0)
	{
		printf("res2:%s < %s \n",str2,str1);
	}


	return 0;
}
zhenghui@zhlinux:~/桌面/code/string$ 

实验结果:

zhenghui@zhlinux:~/桌面/code/string$ make strcmpTest && ./strcmpTest
make: “strcmpTest”已是最新。
str1=abc
str2=ABC
#####################
strcmp(str1,str2) :32 
strcmp(str2,str1) :-32 
res1:abc > ABC 
res2:ABC < abc 
zhenghui@zhlinux:~/桌面/code/string$ 

4、strcpy 和 strncpy函数

从字面上看,看着就很想copy拷贝。

没错,这个就是拷贝的功能。

同样,我们使用:man strcpy来查看帮助手册。

也有很详细的说明:

SYNOPSIS
       #include <string.h>

       char *strcpy(char *dest, const char *src);

       char *strncpy(char *dest, const char *src, size_t n);

DESCRIPTION
       The  strcpy() function copies the string pointed to by src, including the terminating null byte ('\0'), to
       the buffer pointed to by dest.  The strings may not overlap, and the destination string dest must be large
       enough to receive the copy.  Beware of buffer overruns!  (See BUGS.)

       The strncpy() function is similar, except that at most n bytes of src are copied.  Warning: If there is no
       null byte among the first n bytes of src, the string placed in dest will not be null-terminated.

       If the length of src is less than n, strncpy() writes additional null bytes to dest to ensure that a total
       of n bytes are written.

废话不多说,直接上代码:

zhenghui@zhlinux:~/桌面/code/string$ 
zhenghui@zhlinux:~/桌面/code/string$ cat strcpyTest.c 
#include <stdio.h>
#include <string.h>

int main(void)
{
	char str1[12] = " abc aowmdi9";
	char *str2 = " ABC 9999";

	printf("str1=%s\n",str1);
	printf("str2=%s\n",str2);

	printf("#####################\n");
	
	strcpy(str1,str2);


	printf("strcpy(str1,str2):%s \n",str1);


	return 0;
}
zhenghui@zhlinux:~/桌面/code/string$ 

实验结果:

zhenghui@zhlinux:~/桌面/code/string$ make strcpyTest && ./strcpyTest
make: “strcpyTest”已是最新。
str1= abc aowmdi9
str2= ABC 9999
#####################
strcpy(str1,str2): ABC 9999 
zhenghui@zhlinux:~/桌面/code/string$ 

通过下面代码可以看出,直接把str2的内容拷贝到了str1中,直接覆盖了。

strcpy(str1,str2);

重点:其实strcpy是用来解决我们不能用赋值运算符来赋值的操作的问题

那么什么时候,不能用“=”号来赋值呢?

例如:
我们定义一个数组,一开始不赋值,然后等我们业务逻辑到达的时候,再赋值:

char str3[10];

假设到了该赋值的地方:

str3 = "zhenghui";

这个地方会执行错误的。

可以看下执行结果:

zhenghui@zhlinux:~/桌面/code/string$ make strcpyTest && ./strcpyTest
cc     strcpyTest.c   -o strcpyTest
strcpyTest.c: In function ‘main’:
strcpyTest.c:11:7: error: assignment to expression with array type
   11 |  str3 = "zhenghui";//错误
      |       ^
make: *** [<内置>:strcpyTest] 错误 1
zhenghui@zhlinux:~/桌面/code/string$ 

像这种特殊的赋值,我们可以利用strcpy来解决:

strcpy(str3,"zhenghui");

执行就没问题了。

如果带参数n的话,就是用来限制copy的数据值的多少,也是为了安全才有的。

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TrueDei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值