前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >初学者对C语言的爱恨情仇之神秘的字符串

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

作者头像
手撕代码八百里
发布2021-08-05 10:08:28
7050
发布2021-08-05 10:08:28
举报
文章被收录于专栏:猿计划

文章目录

  • 前言
  • 字符串是谁
  • 经常听说字符串字面量,究竟是什么鬼?
  • 字符串字面量如何存储的
  • C语言字符数组与字符指针
  • C语言中的字符串库
    • 1、strlen函数
    • 2、strcat 和 strncat函数
    • 3、strcmp 和 strncmp函数
    • 4、strcpy 和 strncpy函数

前言

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

字符串是谁

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

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

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

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

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

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

代码语言:javascript
复制
printf("Hello World!");

执行结果:

代码语言:javascript
复制
Hello World!

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

代码语言:javascript
复制
printf("Hello  \n   World!");

结果:

代码语言:javascript
复制
Hello  
   World!

字符串字面量如何存储的

例如字符串:"Hello World!"

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

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

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

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

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

代码语言:javascript
复制
char str[12] = "I Love You!";
char *pStr = "I Love You!";

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

代码语言:javascript
复制
printf("str=%s\n",str);
printf("pStr=%s\n",pStr);

打印结果:

代码语言:javascript
复制
str=I Love You!
pStr=I Love You!

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

代码语言:javascript
复制
printf("*(str+2)=%c\n",*(str+2));
printf("*(pStr+2)=%c\n",*(pStr+2));

结果:

代码语言:javascript
复制
*(str+2)=L
*(pStr+2)=L

C语言中的字符串库

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

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

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

例如:

代码语言:javascript
复制
man string

会出现下面这样的结果:

在这里插入图片描述
在这里插入图片描述

可以看到:

在这里插入图片描述
在这里插入图片描述

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

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

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

代码语言:javascript
复制
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一下头文件:

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

代码语言:javascript
复制
#include <stdio.h>
#include <string.h>

int main(void)
{
        return 0;
}

1、strlen函数

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

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

在这里插入图片描述
在这里插入图片描述

解释的非常详细。

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

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

代码语言:javascript
复制
#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;
}

结果:

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

代码语言:javascript
复制
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$ 

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

代码语言:javascript
复制
	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);

打印结果:

代码语言:javascript
复制
str len:11 
str2 len:11 
str3 len:26 

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

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

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

2、strcat 和 strncat函数

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

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

代码语言:javascript
复制
SYNOPSIS
       #include <string.h>

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

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

还有很详细的说文。

代码语言:javascript
复制
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中进行返回。

实验代码:

代码语言:javascript
复制
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$

执行结果:

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

代码语言:javascript
复制
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来指定拼接的大小。

代码语言:javascript
复制
strcat(a,b);

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

代码语言:javascript
复制
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$ 

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

代码语言:javascript
复制
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”留出空间。

代码语言:javascript
复制
strncat(str1,str2,sizeof(str1) - strlen(str1) - 1);

3、strcmp 和 strncmp函数

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

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

代码语言:javascript
复制
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.

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

原型如下:

代码语言:javascript
复制
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; 当然了<=和>=运算符也是可以使用的。

代码语言:javascript
复制
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.

实验代码:

代码语言:javascript
复制
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$ 

实验结果:

代码语言:javascript
复制
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来查看帮助手册。

也有很详细的说明:

代码语言:javascript
复制
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.

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

代码语言:javascript
复制
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$ 

实验结果:

代码语言:javascript
复制
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中,直接覆盖了。

代码语言:javascript
复制
strcpy(str1,str2);

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

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

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

代码语言:javascript
复制
char str3[10];

假设到了该赋值的地方:

代码语言:javascript
复制
str3 = "zhenghui";

这个地方会执行错误的。

可以看下执行结果:

代码语言:javascript
复制
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来解决:

代码语言:javascript
复制
strcpy(str3,"zhenghui");

执行就没问题了。

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/08/02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 前言
  • 字符串是谁
  • 经常听说字符串字面量,究竟是什么鬼?
  • 字符串字面量如何存储的
  • C语言字符数组与字符指针
  • C语言中的字符串库
    • 1、strlen函数
      • 2、strcat 和 strncat函数
        • 3、strcmp 和 strncmp函数
          • 4、strcpy 和 strncpy函数
          相关产品与服务
          对象存储
          对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档