C和指针 (pointers on C)——第九章:字符串、字符和字节(上)

第九章字符串、字符和字节

这一块在初学的时候很容易被大家忽视,但字符串作为一种重要的数据类型,没有在C中显式的说明。这样看起来C++定义了string的数据类型实在是带来了不少福音。

如果想用C玩OJ或者数据结构与算法的话,这一章需要仔细阅读,因为这是你仅有能用到的字符串处理的标准库。

总结:

C的字符串标准库使用需要声明"string.h"。

strlen用于计算一个字符串的长度,它的返回值是一个无符号的整数。后面会说可能存在的问题。

strcpy函数把一个字符串从一个位置赋值到另一个位置。

strcat函数把一个字符串的一份拷贝添加到另一个字符串的后面。

strcmp函数对两个字符串进行词典序的比较。它的返回值提示第一个字符串是大于、小于还是等于。

strncpy/strncat/strncmp对应不受限制的版本,它们可以完美判断是否操作溢出。另外还要加一个长度参数。

strncpy长度指定了多少个字符被写入到目标字符数组中。

strncat长度制定了从源字符串赋值的最大数目,结尾包含‘\0‘。

strcmp长度制定了比较的数目。

关于查找的字符串:

strchr查找一个字符串中的某个字符第一次出现的位置。

strrchr同上,但是返回最后一次出现的位置。

strpbrk在一个字符串查找一个指定字符集中任意字符(不是子串!是任意一个字符!)第一次出现的位置。

strstr是查找子串第一次出现的位置。

在这里我不想涉及到高级查找函数,功能太诡异。

strerror把一个错误代码作为它的参数,返回一个指向字符串的指针,该字符串用于描述这个错误。

关于测试和转换字符的函数:

用它们的意义在于,代码的移植性可以大大提高。

toupper把一个小写字母换成大写字母。

tolower把一个大写字母换成小写字母。

iscntrl检查是不是一个控制字符。

...很多这样的。。。它们会返回一个整型值,表示真或假。

关于内存操作:

memxxx函数提供类似字符串的操作,但是遇到NUL时候不会停止操作。同时会包括一个长度参数。

memmove/memcpy赋值指定长度字节数

memcmp比较

memchr查找一个特定值

memset将一个序列初始化为一个特定的值。

警告:

1、应该使用有符号数的表达式使用strlen函数。

因为strlen在定义的时候返回值为size_t,这是一个无符号数,所以:

if(strlen(x) >= strlen(y))...

if(strlen(x) - strlen(y) >=0)...

这两个是可能不相同的,前者会像预想的那样正常工作,但是后者不能表达一个负数值。

最好将strlen返回值强制转换为int 。

2、在表达式中混有有符号数和无符号数。

同上。

3、使用strcpy函数把一个长字符串赋值到一个较短的数组中,导致溢出。

如果太长,strcpy不会考虑溢出问题,它的操作结果将是覆盖后面的内存空间。

4、使用strcat函数把一个字符串添加到一个数组中,导致数组溢出。

同上。

5、把strcmp函数的返回值1和-1进行比较,或者当做布尔值比较。

这是一种不好的风格,最好的的方法是与0进行比较。

if(strcmp(a,b))这样就是结果很可能a,b是相等的,但是返回一个假。

6、使用并非以NUL字符截尾的字符序列作为以上函数的传递值。

比如strcmp、strlen这些函数都是在找NUL作为终止的条件,如果没有个NUL,返回值将会不确定。

7、使用strncpy函数产生不易NUL字节结尾的字符串。

在使用strncpy函数后,如果复制的长度超过剩余长度,虽然不会溢出,但是它的结果不会以NUL结尾。

8、把strncpy函数和strxxx族函数混用。

呵呵的警告。

编程提示:

1、不要试图自己编写功能相同的函数来取代库函数。

库函数有时候用汇编来写的,从而有最大速度。如果想改进效率,还是看看你的其他代码吧。

2、使用字符分类和转换函数可以提高函数的移植性。

时间: 2024-09-30 06:45:01

C和指针 (pointers on C)——第九章:字符串、字符和字节(上)的相关文章

Java学习笔记—第九章 字符串String

第九章 字符串String Java中使用String类来创建一个字符串变量,字符串变量是类类型变量,是一个对象.声明字符串的语法格式如下:String s; 创建字符串:通过String类提供的构造方法可创建字符串,有以下几种方式: (1)创建字符串对象时直接赋值,例如: String s1 = "hello"; String s2 = new String("hello"); (2)由一个字符串创建另一个字符串,例如: String s1 = "hel

《汇编语言 基于x86处理器》第九章字符串与数组部分的代码

? 书中第九章的程序,主要讲了 ● 代码,Irvine32 中的字符串库函数代码范例 1 INCLUDE Irvine32.inc 2 3 .data 4 str1 BYTE "abcde////", 0 5 str2 BYTE "ABCDE", 0 6 msg0 BYTE "Upper case: ", 0 7 msg1 BYTE "str1 == str2", 0 8 msg2 BYTE "str1 < s

《C与指针》第九章练习

本章问题 1.C语言缺少显示的字符串数据类型,这是一个优点还是一个缺点? answer: (这个问题存在争论(尽管我有一个结论))目前这个方法的优点是字符数组的效率和访问的灵活性,它的缺点是有可能引起错误,数组溢出,下标越界,不能改变任何用于保存字符串的数组的长度等.我的结论是从现代的面向对象的奇数引出的,字符串类毫无例外的包括了完整的错误检查,用于字符串的动态内存分配和其他一些防护措施,这些措施都会造成效率上的损失,但是,如果程序无法运行,效率再高也没有什么意义,况且,现在软件项目的规模比设计

第九章心得体会

通过第九章的学习,我学到了如下知识点: 第九章:硬件抽象层:HAL 9.1为什么要在Android中加入HAL 1.HAL并不是Linux内核的一部分,而是位于Android的系统运行库层 2.为Android加入HAL主要目的:统一硬件的调用借口,解决了GPL的版权问题,针对一些特殊的要求. 9.2Android HAL架构 9.3为LED驱动增加HAL 1.编写一款支持HAL的Linux驱动程序的步骤 第一步:编写Linux驱动 Linux驱动代码要尽量的简洁,尽可能将业务逻辑放到HAL L

操作系统思考 第九章 线程

第九章 线程 作者:Allen B. Downey 原文:Chapter 9 Threads 译者:飞龙 协议:CC BY-NC-SA 4.0 当我在2.3节提到线程的时候,我说过线程就是一种进程.现在我会更仔细地解释它. 当你创建进程时,操作系统会创建一块新的地址空间,它包含text段.static段.和堆区.它也会创建新的"执行线程",这包括程序计数器和其它硬件状态,以及运行时栈. 我们目前为止看到的进程都是"单线程"的,也就是说每个地址空间中只运行一个执行线程

第九章随笔

  第九章: 一.Google为android加入HAL主要有如下目的:     1.统一硬件的调用接口,HAL有标准的调用接口,屏蔽Linux繁杂接口:     2.解决GPL版本问题:     3.对于有些硬件,可能需要访问一些用户空间的资源,或在内核空间不方便完成的工作以及特殊需求,可利用HAL辅助完成: 二.编写一款支持HAL的linux驱动程序步骤: 1.编写linux驱动(尽量简洁,尽量将业务逻辑放倒HAL library): 2.编写HAL Library: 3.编写service

第九章 C语言在嵌入式中的应用

上章回顾 编码的规范和程序版式 版权管理和申明 头文件结构和作用 程序命名 程序注释和代码布局规范 assert断言函数的应用 与0或NULL值的比较 内存的分配和释放细节,避免内存泄露 常量特性 [email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git 第九章 第九章 C语言在嵌入式中的应用 C语言在嵌入式中的应用 [email protecte

第九章 虚拟存储器

第九章 虚拟存储器 虚拟存储器是计算机系统最重要的概念之一,它是对主存的一个抽象 物理和虚拟寻址 计算机系统的主存被组织成一个由M个连续的字节大小的单元组成的数组,每字节都有一个唯一的物理地址PA. 根据物理地址寻址的是物理寻址. 虚拟存储器被组织为一个由存放在磁盘上的N个连续的字节大小的单元组成的数组. 使用虚拟寻址时,CPU通过生成一个虚拟地址VA来访问主存,这个虚拟地址在被送到存储器之前先转换成适当的物理地址(这个过程叫做地址翻译,相关硬件为存储器管理单元MMU) 虚拟存储器作为缓存的工具

第九章 引用

第九章 引用 1.  什么是引用? 引用就是别名.int &ra=a;此处的&不是取址运算符,而是引用运算符 3.  引用就是别名常量 4.  引用对象 只能 int &ra=a;// 注意定义引用时要对其初始化 int &ra; ra=a;  //这样是错误的,引用就像常量,只能初始化不能赋值 对象也可以定义一个引用,但是类不能,因为它没有具体的内存地址 5.  空引用 6.  按值传递 按值传递(传递的是副本)≠按地址传递()≠按别名传递(有什么不同?) 9.1.利用指