0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

周立功《程序设计与数据结构》:字符串函数

AGk5_ZLG_zhiyua 来源:未知 作者:电子大兵 2017-09-05 09:18 次阅读

本文为程序设计基础,本文为1.8.2 字符串常量第三点:字符串函数。

>>>>

1.字符串函数

标准C提供了一个操作字符串的接口string.h,其中的很多函数是有特殊用途的,下面将详细介绍通过string.h导出的最重要的函数原型。

strlen()函数

strlen()函数用于统计字符串的长度,其函数原型如下:

size_t strlen(const char *s);

//前置条件:s是一个以null结尾的字符串

//后置条件:返回值为s中的字符个数(不包括null字符)

下面的函数可以缩短字符串的长度,其中用到了strlen()。即:

1 void fit(char *string, unsigned int size)

2 {

3 if(strlen(string) > size)

4 strlen[size] = '\0';

5 }

由于该函数要改变字符串,因此函数在声明形参string时没有使用const限定符。当然,也可以调用strlen(s)确定字符串s的长度,或用if语句比较两个字符串是否相等。即:

if(strcmp(s1, s2) == 0) …

strcat()函数

用于拼接字符串的strcat()函数接受两个字符串作为参数,其函数原型如下:

char *strcat(char *s1, char const *s2);

//前置条件:s2是一个以null结尾的字符串,s1数组的末尾还有足够的空间容纳s2的一个副本

//后置条件:s2被连接到s1中,且返回值是一个指针,该指针指向s1数组的第一个字符

该函数将第2个字符串的备份附加在第1个字符串末尾,s2字符串的第1个字符将覆盖s1字符串末尾的空字符,并将拼接后的新字符串作为第1个字符串返回,第2个字符串不变。strcat()函数的类型是char *(即指向char的指针),strcat()函数返回第1个参数,即拼接第2个字符串后的第1个字符串的地址。

由于strcat()函数无法检查第1个数组是否能够容纳第2个字符串,如果分配给第1个数组的空间不够大,那么多出来的字符溢出到相邻存储单元时就会出问题,当然也可以用strlen()查看第1个数组的长度。注意,要给拼接后的字符串长度加1才够空间存放末尾的空字符。或者用strncat(),该函数的第3个参数指定了添加的最大字符数,其函数原型如下:

char *strncat(char *s1, char const *s2, size_t n);

该函数将s2字符串中的n个字符拷贝到s1字符串末尾,s2字符串中的第1个字符将覆盖s1字符串末尾的空字符。不会拷贝s2字符串中的空字符和其后的字符,并在拷贝字符的末尾添加一个空字符,该函数返回s1。

strcmp()函数和strncmp()函数

strcmp()函数要比较的是字符串的内容,不是字符串的地址,其函数原型如下:

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

//前置条件:s1和s2都是以null结尾的字符串

//后置条件:返回值为0,表示s1=s2;

// 返回值小于0,表示s1在词典顺序上位于s2之前;

// 返回值大于0,表示s1在词典顺序上位于s2之后

如果s1字符串在机器排序序列中位于s2字符串的后面,该函数返回一个正数;如果两个字符串相等,则返回0;如果s1字符串在机器排序序列中位于s2字符串的前面,则返回一个负数。strcmp()函数比较的是字符串("hello")不是字符('q'),所以其参数应该是字符串。由于char的类型实际上是整数类型,因此可以使用关系运算符比较字符。如果两个字符串开始的几个字符都相同会怎样?strcmp()会依次比较每个字符,直到发现第1对不同的字符为止,然后返回相应的值。比如,"apples"和"apple"只有最后一对字符不一样("apples"的s和"apple"的空字符),由于空字符在ASCII中排第1,字符s一定在它后面,所以strcmp()返回一个正数。

最后一个例子,strcmp()比较所有的字符,不只是字母。与其说该函数按字母顺序进行比较,还不如说是按机器排序序列进行比较,即根据字符的数值(ASCII值)进行比较,在ASCII中,大写字母在小写字母前面,因此strcmp("Z", "a")返回的是负值。

在大多数情况下,strcmp()返回的具体值并不重要,只在意该值是0还是非0,即比较两个值是否相等,或按字母排序字符串,此时需要知道比较的结果是正、负或0。假设word是存储在char类型数组中的字符串,ch是char类型的变量。即:

if(strcmp(word, "hello") == 0) puts("bye")

if(ch == 'q' ) puts("bye")

尽管如此,不要使用ch或'q'作为strcmp()的参数。

strcmp()比较两个字符串中的字符,直到发现不同的字符为止,这一过程可能会持续到字符串的末尾。而strcmp()在比较两个字符串时,可以比较字符不同的地方,也可以只比较第3个参数指定的字符数。其函数原型如下:

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

strcpy()函数

strcpy()函数有两个属性,第一,strcpy()的返回值类型为char *,该函数返回的是第1个参数的值,即一个字符的地址。第二,第1个参数不必指向数组的开始,这个属性可用于拷贝数组的一部分。注意,strcpy()将源字符串中的空字符也拷贝在内。

如果pts1和pts2都是指向字符串的指针,那么下面语句拷贝的是字符串的地址,而不是字符串本身。即:

pts2 = pts1;

如果希望拷贝整个字符串,可以使用strcpy()函数。其函数原型如下:

char *strcpy(char *s1, char const *s2);

//前置条件:s2是一个以null结尾的字符串,s1数组有足够的空间容纳s2的一个副本

//后置条件:s2被复制到s1,且返回值是一个指针,该指针指向s1数组的第一个字符

该函数将s2指向的字符串(包括空字符)拷贝至s1指向的位置,返回s1。即strcpy()接受2个字符串指针作为参数,可以将指向源字符串的第2个指针声明为指针、数组名或字符串常量,而指向源字符串副本的第1个指针应指向一个数据对象,比如,数组,且对象要有足够的空间存储字符串的副本,通常将拷贝出来的字符串称为目标字符串。注意,声明数组将分配存储数据的空间,而声明指针只分配存储一个地址的空间。

strncpy()函数

strcpy()和strcat()都有同样的问题,它们不能检查目标空间是否能容纳源字符串的副本,因此拷贝字符串使用strncpy()更安全,该函数的第3个参数指明可拷贝的最大字符数。其函数原型如下:

char *strncpy(char *s1, char const *s2, size_t n);

该函数将s2指向的字符串拷贝至s1指向的位置,拷贝的字符不超过n,其返回值为s1。该函数不会拷贝空字符后面的字符,如果源字符串中的字符数少于n,则目标字符串就以拷贝的空字符结尾。如果源字符串有n个或超过n个字符,就不拷贝空字符,所以拷贝的副本中不一定有空字符。基于此,一般会将n设置比目标数组大小少1,然后将数组最后一个元素设置为空字符。

这样做的目的将确保存储的是一个字符串,如果目标空间能够容纳源字符串的副本,那么从源字符串拷贝的空字符便是该副本的结尾;如果目标空间装不下副本,则将副本最后一个元素设置为空字符。

尽管C语言允许将字符串作为一个字符数组或一个指向字符的指针,但是从更抽象的角度理解字符串将会更有意义。如果你想访问字符串中的单个字符,则需要注意它的表现形式。如果将字符串当作一个整体来看待的话,那么就可以忽略其表现的细节,而写出更容易理解的程序。比如:

typedef char *striing;

其目的是强调字符串是一个在概念上完全不同的类型,虽然string与char *类型完全相同,但它们传递的信息却是不同的。如果将一个变量定义为char *类型,其底层的表示方法是指针;如果将一个变量定义为string类型,就会将该字符串作为整体看待。这样一来,在声明函数的形参时,无论是将字符串作为数组、指针或抽象数据类型,它们都是可以互换的,其声明方法如下:

int strlen(string cStr);

int strlen(char cStr[]);

int strlen(char *cStr);

虽然标准C提供的string.h接口提供了一系列的字符串操作函数,它允许在函数调用时将字符串作为一个整体对待,但这些函数同样要求我们了解底层的表示,即函数将分配内存的任务留给了用户,特别是检测缓冲区溢出的条件。当使用这个接口时,用户要为每个字符串的存储负责。这种分配方式不仅增加了程序员的负担,也间接使得编码中的错误增多了。

溢出问题

使用gets()函数从标准输入读入字符串容易导致缓冲区溢出,而误用strcpy()和strcat()同样如此。因为使用某些函数可能造成攻击者用格式化字符串攻击的方法访问内存,甚至能够注入代码,所以C11版本加入了strcat_s()和strcpy_s()函数,如果发生缓冲区溢出,它们会返回错误。printf()、fprintf()和snprintf()这些函数都接受格式化字符串作为参数,避免这类攻击的一种简单方法是不要将用户提供的格式化字符串传给这些函数。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 字符串
    +关注

    关注

    1

    文章

    577

    浏览量

    20485
  • C语言编程
    +关注

    关注

    6

    文章

    90

    浏览量

    21092
  • 数据结构
    +关注

    关注

    3

    文章

    573

    浏览量

    40088
  • 程序设计
    +关注

    关注

    3

    文章

    261

    浏览量

    30365
  • 周立功
    +关注

    关注

    38

    文章

    130

    浏览量

    37578

原文标题:周立功:字符真正价值在于形成字符序列——字符串函数

文章出处:【微信号:ZLG_zhiyuan,微信公众号:ZLG致远电子】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    程序设计数据结构立功数十年心血力作

    为了将实际开发过程中总结的有价值的技术应用分享给大家,立功及其团队整理出《程序设计数据结构》这本书,其内容如同培训讲师的教案,是
    发表于 05-26 10:06 29次阅读

    立功程序设计数据结构”:深度解剖动态分布内存的free()函数与realloc()函数

    立功教授数年之心血之作《程序设计数据结构》,书本内容公开后,在电子行业掀起一片学习热潮。
    的头像 发表于 08-25 14:22 1.5w次阅读

    立功教你学C语言编程与程序设计:这样写函数指针数组最好用

    立功教授数年之心血之作《程序设计数据结构》以及《面向AMetal框架与接口的编程(上)》,电子版已无偿性分享到电子工程师与高校群体,在公众号回复【编程】即可在线阅读。
    的头像 发表于 08-31 14:06 6850次阅读
    <b class='flag-5'>周</b><b class='flag-5'>立功</b>教你学C语言编程与<b class='flag-5'>程序设计</b>:这样写<b class='flag-5'>函数</b>指针数组最好用

    新书创作谈:立功教授数十年之心血力作《程序设计数据结构

    ` 近日,立功教授公开了数十年之心血力作《程序设计数据结构》,此书在4月28日落笔,电子版已无偿性分享到电子工程师与高校群体,在致远电子公众号后台回复关键字【
    发表于 05-15 18:04

    【完整资料】《程序设计数据结构立功数十年心血力作

    ,是立功和团队的读书笔记和程序设计实践的心得。《程序设计数据结构》重点阐述了三大方向内容。C语言学习中的痛点:针对当前工程师在C语言学习
    发表于 05-16 16:43

    程序设计数据结构》【完整资料】分享!

    现象,甚至成为一位阅读程序者。 为了将实际开发过程中总结的有价值的技术应用分享给大家,立功及其团队整理出《程序设计数据结构》这本书,其内
    发表于 08-31 16:20

    字符串函数测试学习工程

    字符串函数测试学习工程
    发表于 07-01 16:38 6次下载

    新书创作谈:立功教授数十年之心血力作《程序设计数据结构

    近日,立功教授公开了数十年之心血力作《程序设计数据结构》,此书在4月28日落笔,电子版已无偿性分享到电子工程师与高校群体,在致远电子公众号后台回复关键字【
    发表于 05-08 09:32 2006次阅读

    程序设计数据结构》——框架与重用

    立功教授数年之心血之作《程序设计数据结构》以及《面向AMetal框架与接口的编程(上)》,电子版已无偿性分享到电子工程师与高校群体,在公众号回复【编程】即可在线阅读。书本内容公开后
    的头像 发表于 10-10 10:55 5461次阅读
    《<b class='flag-5'>程序设计</b>与<b class='flag-5'>数据结构</b>》——框架与重用

    基于STM32单片机发送字符串函数

    最近由于要调试一个SMS发送短信的模块,该模块需要发送一系列AT指令,且需要字符串发送,但是STM32官方给的usart.c中并没有直接发送字符串函数,因此写了一个发送字符串
    发表于 01-04 15:05 4867次阅读

    LabVIEW的常用字符串操作教程免费下载

    字符串操作与信息的保存和显示密不可分,而字符串操作运用也是LabⅥEW程序设计的一个难点,因此熟练使用字符串操作函数是使用LabⅥEW进行编
    发表于 08-21 14:51 26次下载
    LabVIEW的常用<b class='flag-5'>字符串</b>操作教程免费下载

    字符串函数重写练习

    字符串函数重写练习:字符串比较、字符串拼接、字符串查找、字符串拷贝、内存比较、内存拷贝、内存初始
    的头像 发表于 05-05 15:02 1962次阅读

    MySQL替换字符串函数REPLACE

    MySQL是目前非常流行的开源数据库管理系统之一,它具有强大的功能和性能。其中之一的字符串函数REPLACE,可以用于替换字符串中的指定字符
    的头像 发表于 11-30 10:44 1475次阅读

    oracle中拼接字符串函数

    在Oracle中,我们可以使用 CONCAT 函数来拼接字符串。CONCAT 函数接受两个参数,它将这两个参数连接起来并返回相应的字符串结果。 语法示例: CONCAT(string1
    的头像 发表于 12-06 09:49 2803次阅读

    labview中常用的字符串函数有哪些?

    ) : 功能:该函数用于返回字符串所包含的字符个数。 应用场景:常用于需要计算字符串长度的场景,如文件命名、数据处理等。 连接
    的头像 发表于 09-04 15:43 508次阅读