当前位置: 首页 > news >正文

电子商务网站建设素材网站设计制作服务好态度好

电子商务网站建设素材,网站设计制作服务好态度好,345诛仙网站是谁做的,教育网站开发需求说明书文章目录 第23章 库对数值和字符数据的支持23.1 float.h: 浮点类型的特性23.2 limits.h: 整数类型的大小23.3 math.h: 数学计算(C89)23.3.1 错误23.3.2 三角函数23.3.3 双曲函数23.3.4 指数函数和对数函数23.3.5 幂函数23.3.6 就近舍入、绝对值函数和取… 文章目录 第23章 库对数值和字符数据的支持23.1 float.h: 浮点类型的特性23.2 limits.h: 整数类型的大小23.3 math.h: 数学计算(C89)23.3.1 错误23.3.2 三角函数23.3.3 双曲函数23.3.4 指数函数和对数函数23.3.5 幂函数23.3.6 就近舍入、绝对值函数和取余函数 23.4 math.h: 数学计算(C99)23.4.1 IEEE浮点标准23.4.2 类型23.4.3 宏23.4.4 错误23.4.5 函数23.4.6 分类宏23.4.7 三角函数23.4.8 双曲函数23.4.9 指数函数和对数函数23.4.10 幂函数和绝对值函数23.4.11 误差函数和伽马函数23.4.12 就近舍入函数23.4.13 取余函数23.4.14 操作函数23.4.15 最大值函数、最小值函数和正差函数23.4.16 浮点乘加23.4.17 比较宏 23.5 ctype.h: 字符处理23.5.1 字符分类函数23.5.2 字符大小写映射函数 23.6 string.h: 字符串处理23.6.1 复制函数23.6.2 拼接函数23.6.3 比较函数23.6.4 搜索函数23.6.5 其他函数 问与答写在最后 第23章 库对数值和字符数据的支持 ——与计算机过长时间的接触会把数学家变成书记员也会把书记员变成数学家。 本章会介绍5个函数库的头这5个头提供了对数值、字符和字符串的支持。23.1节和23.2节分别介绍了float.h和limits.h头它们包含了用于描述数值和字符类型特性的宏。23.3节和23.4节描述math.h头它提供了数学函数。23.3节讨论C89版本的math.h头而23.4节则讲述C99中新增的内容因为内容很多所以将分别介绍。23.5节和23.6节分别讨论ctype.h和string.h头这两个头分别提供了字符函数和字符串函数。 C99增加了几个也能处理数、字符和字符串的头。wchar.h和wctype.h头在第25章中讨论。第27章讨论complex.h、fenv.h、inttypes.h、stdint.h和tgmath.h。 23.1 float.h: 浮点类型的特性 float.h中提供了用来定义float、double和long double类型的范围及精度的宏。在float.h中没有类型和函数的定义。 有两个宏对所有浮点类型适用。FLT_ROUNDS表示当前浮点加法的舍入方向23.4节。表23-1列出了FLT_ROUNDS的可能值。对于表中没有给出的值舍入行为由实现定义。 表23-1 舍入方向 取值含义-1不确定-0趋零截尾-1向最近的整数舍入-2向正无穷方向舍入-3向负无穷方向舍入 与float.h中的其他宏表示常量表达式不同FLT_ROUNDS的值在执行期间可以改变。fesetround函数允许程序改变当前的舍入方向。另一个宏FLT_RADIX指定了指数表示中的基数它的最小值为2表明二进制表示。 其他宏用来描述具体类型的特性这里会用一系列的表格来描述。根据宏是针对float、double还是long double类型每个宏都会以FLT、DBL或LDBL开头。C标准对这些宏给出了相当详细的定义因此这里的介绍会更注重通俗易懂不追求十分精确。依据C标准表中列出了部分宏的最大值和最小值。 表23-2列出了定义每种浮点类型的有效数字个数的宏: 表23-2 float.h中的有效数字宏 宏名取值宏的描述FLT_MANT_DIG有效数字的个数基数FLT_RADIXDBL_MANT_DIGLDBL_MANT_DIGFLT_DIG≥6有效数字的个数十进制DBL_DIG≥10LDBL_DIG≥10 表23-3列出了与指数相关的宏: 表23-3 float.h中的指数宏 宏名取值宏的描述FLT_MIN_EXPFLT_RADIX的最小负的次幂DBL_MIN_EXPLDBL_MIN_EXPFLT_MIN_10_EXP≤-3710的最小负的次幂DBL_MIN_10_EXP≤-37LDBL_MIN_10_EXP≤-37FLT_MAX_EXPFLT_RADIX的最大次幂DBL_MAX_EXPLDBL_MAX_EXPFLT_MAX_10_EXP≥3710的最大次幂DBL_MAX_10_EXP≥37LDBL_MAX_10_EXP≥37 表23-4列出的宏描述了最大值、最接近0的值以及两个连续的数之间的最小差值: 表23-4 float.h中的最大值、最小值和差值宏 宏名取值宏的描述FLT_MAX≥10^37最大的有限值DBL_MAX≥10^37LDBL_MAX≥10^37FLT_MIN≤10^-37最小的正值DBL_MIN≤10^-37LDBL_MIN≤10^-37FLT_EPSILON≤10^-5两个数之间可表示的最小差值DBL_EPSILON≤10^-9LDBL_EPSILON≤10^-9 C99提供了另外两个宏DECIMAL_DIG和FLT_EVAL_METHOD。DECIMAL_DIG表示所支持的最大浮点类型的有效数字个数以10为基数。FLT_EVAL_METHOD的值说明具体的实现中是否用到了超出实际需要的范围和精度的浮点运算。例如如果该宏的值为0那么对两个float类型的值相加就按照正常的方法进行但如果该宏的值为1在执行加法之前需要先把float类型的值转换为double类型的值。表23-5列出了FLT_EVAL_METHOD可能的取值。表中没有给出的负值表示由实现定义的行为。 表23-5 求值方法 取值含义-1不确定0根据类型的范围和精度对所有运算和常量求值1根据double类型的范围和精度对所有float类型和double类型的运算和常量求值2根据long double类型的范围和精度对所有类型的运算和常量求值 float.h中定义的大多数宏只有数值分析领域的专家才会感兴趣因此这可能是标准库中最不常用的头。 23.2 limits.h: 整数类型的大小 limits.h中提供了用于定义每种整数类型包括字符类型取值范围的宏。在limits.h中没有声明类型或函数。 limits.h中的一组宏用于字符类型char、signed char和unsigned char。表23-6列举了这些宏以及它们的最大值或最小值。 表23-6 limits.h中的字符类型宏 宏名取值宏的描述CHAR_BIT≥8每个字符包含位的位数SCHAR_MIN≤-127最小的signed char类型值SCHAR_MAX≥127最大的signed char类型值UCHAR_MAX≥255最大的unsigned char类型值CHAR_MIN①最小的char类型值CHAR_MAX②最大的char类型值MB_LEN_MAX≥1多字节字符最多包含的字节数 ①如果char类型被当作有符号类型则CHAR_MIN与SCHAR_MIN相等否则CHAR_MIN为0。 ②根据char类型被当作有符号类型还是无符号类型CHAR_MAX分别与SCHAR_MAX或UCHAR_MAX相等。 其他在limits.h中定义的宏针对整数类型short int、unsigned short int、int、unsigned int、long int以及unsigned long int。表23-7列举了这些宏以及它们的最大值或最小值并给出了计算各个值的公式。注意!!C99及之后的标准提供了三个宏来描述long long int类型的特性: 表23-7 limits.h中整数类型的宏 宏名取值公式宏的描述SHRT_MIN≤-32767-(2^15-1)最小的short int类型值SHRT_MAX≥327672^15-1最大的shor tint类型值USHRT_MAX≥655352^16-1最大的unsigned short int类型值INT_MIN≤-32767-(2^15-1)最小的int类型值INT_MAX≥327672^15-1最大的int类型值UINT_MAX≥655352^16-1最大的unsigned int类型值LONG_MIN≤-2147483647-(2^31-1)最小的long int类型值LONG_MAX≥21474836472^31-1最大的long int类型值ULONG_MAX≥42929672952^32-1最大的unsigned long int类型值LLONG_MIN①≤-9223372036854775807-(2^63-1)最小的long long int类型值LLONG_MAX①≥92233720368547758072^63-1最大的long long int类型值ULLONG_MAX①≥184467440737095516152^64-1最大的unsigned long long int类型值 ①仅C99及之后的标准才有。 limits.h中定义的宏在查看编译器是否支持特定大小的整数时十分方便。例如如果要判断int类型是否可以用来存储像100000一样大的数可以使用下面的预处理指令 #if INT_MAX 100000 #error int type is too small #endif如果int类型不适用#error指令14.5节会导致预处理器显示一条出错消息。 进一步讲可以使用limits.h中的宏来帮助程序选择正确的类型定义。假设Quantity类型的变量必须可以存储像100000一样大的整数。如果INT_MAX至少为100000就可以将Quantity定义为int否则要定义为long int #if INT_MAX 100000 typedef int Quantity; #else typedef long int Quantity; #endif 23.3 math.h: 数学计算(C89) C89的math.h中定义的函数包含下面5种类型 三角函数双曲函数指数和对数函数幂函数就近舍入函数、绝对值函数和取余函数。 C99在这5种类型中增加了许多函数并且新增了一些其他类型的数学函数。C99中对math.h所做的改动很大下一节将专门讨论相关内容。 在深入讨论math.h提供的函数之前先来简单地了解一下这些函数是如何处理错误的。 23.3.1 错误 math.h中的函数对错误的处理方式与其他库函数不同。当发生错误时math.h中的大多数函数会将一个错误码存储到[在errno.h24.2节中声明的]一个名为errno的特殊变量中。此外一旦函数的返回值大于double类型的最大取值math.h中的函数会返回一个特殊的值这个值由HUGE_VAL宏定义这个宏在math.h中定义。HUGE_VAL是double类型的但不一定是普通的数。IEEE浮点运算标准定义了一个值叫“无穷数”23.4节,这个值是HUGE_VAL的一个合理的选择。 math.h中的函数检查下面两种错误: 定义域错误。函数的实参超出了函数的定义域。当定义域错误发生时函数的返回值是由实现定义的同时EDOM“定义域错误”会被存储到errno中。在math.h的某些实现中当定义域错误发生时函数会返回一个特殊的值NaN“非数”。取值范围错误。函数的返回值超出了double类型的取值范围。如果返回值的绝对值过大上溢出函数会根据正确结果的符号返回正的或负的HUGE_VAL。此外值ERANGE“取值范围错误”会被存储到errno中。如果返回值的绝对值太小下溢出函数返回零一些实现可能也会将ERANGE存储到errno中。 本节不讨论取余时可能发生的错误。附录D中的函数描述会解释导致每种错误的情况。 23.3.2 三角函数 double acos(double x); double asin(double x); double atan(double x); double atan2(double y, double x); double cos(double x); double sin(double x); double tan(double x); cos、sin和tan函数分别用来计算余弦、正弦和正切。假定PI被定义为3.14159265那么以PI/4为参数调用cos、sin和tan函数会产生如下的结果 cos(PI/4) ⇒ 0.707107 sin(PI/4) ⇒ 0.707107 tan(PI/4) ⇒ 1.0 //注意!!传递给 cos、sin和tan函数的实参是以弧度表示的而不是以角度表示的。acos、asin和atan函数分别用来计算反余弦、反正弦和反正切 acos(1.0) ⇒ 0.0 asin(1.0) ⇒ 1.5708 atan(1.0) ⇒ 0.785398对cos函数的计算结果直接调用acos函数不一定会得到最初传递给cos函数的值因为acos函数始终返回一个0~π的值。asin函数与atan函数会返回-π/2~π/2的值。 atan2函数用来计算y/x的反正切值其中y是函数的第一个参数x是第二个参数。atan2函数的返回值在-π~π范围内。调用atan(x)与调用atan2(x,1.0)等价。 23.3.3 双曲函数 double cosh(double x); double sinh(double x); double tanh(double x); cosh、sinh和tanh函数分别用来计算双曲余弦、双曲正弦和双曲正切 cosh(0.5) ⇒ 1.12763 sinh(0.5) ⇒ 0.521095 tanh(0.5) ⇒ 0.462117传递给cosh、sinh和tanh函数的实参必须以弧度表示而不能以角度表示。 23.3.4 指数函数和对数函数 double exp(double x); double frexp(double value, int *exp); double ldexp(double x, int exp); double log(double x); double log10(double x); double modf(double value, double *iptr);exp函数返回e的幂 exp(3.0) ⇒ 20.0855 log函数是exp函数的逆运算它计算以e为底的对数。log10计算“常用”以10为底对数 log(20.0855) ⇒ 3.0 log10(1000) ⇒ 3.0对于不以e或10为底的对数计算起来也不复杂。例如下面的函数对任意的x和b计算以b为底x的对数 double log_base(double x, double b) { return log(x) / log(b); } modf函数和frexp函数将一个double型的值拆解为两部分。modf将它的第一个参数分为整数部分和小数部分返回其中的小数部分并将整数部分存入第二个参数所指向的对象中 modf(3.14159, int_part) ⇒ 0.14159 //int_part被赋值为3.0虽然int_part的类型必须为double但我们始终可以随后将它强制转换成int或long int。 frexp函数将浮点数拆成小数部分ƒ和指数部分n使得原始值等于ƒ×2^n其中0.5≤ƒ≤1或ƒ0。函数返回ƒ并将n存入第二个参数所指向的整数对象中 frexp(12.0, exp) ⇒ 0.75 //exp被赋值为 4 frexp(0.25, exp) ⇒ 0.5 //exp被赋值为-1ldexp函数会抵消frexp产生的结果将小数部分和指数部分组合成一个数 ldexp(.75, 4) ⇒ 12.0 ldexp(0.5, -1) ⇒ 0.25一般而言调用ldexp(x, exp)将返回x × 2^exp。 modf、frexp和ldexp函数主要供math.h中的其他函数使用很少在程序中直接调用。 23.3.5 幂函数 double pow(double x, double y); double sqrt(double x);pow函数计算第一个参数的幂幂的次数由第二个参数指定 pow(3.0, 2.0) ⇒ 9.0 pow(3.0, 0.5) ⇒ 1.73205 pow(3.0, -3.0) ⇒ 0.037037sqrt函数计算平方根 sqrt(3.0) ⇒ 1.73205 由于通常sqrt函数比pow函数的运行速度快得多因此使用sqrt计算平方根更好。 23.3.6 就近舍入、绝对值函数和取余函数 double ceil(double x); double fabs(double x); double floor(double x); double fmod(double x, double y); ceil函数返回一个double类型的值这个值是大于或等于其参数的最小整数。floor函数则返回小于或等于其参数的最大整数 ceil(7.1) ⇒ 8.0 ceil(7.9) ⇒ 8.0 ceil(-7.1) ⇒ -7.0 ceil(-7.9) ⇒ -7.0 floor(7.1) ⇒ 7.0 floor(7.9) ⇒ 7.0 floor(-7.1) ⇒ -8.0 floor(-7.9) ⇒ -8.0 换言之ceil“向上舍入”到最近的整数floor“向下舍入”到最近的整数。C89没有标准库函数可以用来舍入到最近的整数但我们可以简单地使用ceil函数和floor函数来实现一个这样的函数 double round_nearest(double x) { return x 0.0 ? ceil(x - 0.5) : floor(x 0.5); } fabs函数计算参数的绝对值 fabs(7.1) ⇒ 7.1 fabs(-7.1) ⇒ 7.1 fmod函数返回第一个参数除以第二个参数所得的余数 fmod(5.5, 2.2) ⇒ 1.1 注意C语言不允许对%运算符使用浮点操作数不过fmod函数足以用来替代%运算符。 23.4 math.h: 数学计算(C99) C99的math.h包含了所有C89版本的内容同时增加了许多的类型、宏和函数。相关的改动很多我们将分别介绍。标准委员会为math.h增加这么多内容有以下几个原因: 更好地支持IEEE浮点标准。C99不强制使用IEEE标准其他表示浮点数的方法也是允许的。但是大多数C程序运行于支持IEEE标准的系统上。更好地控制浮点运算。对浮点运算加以更好的控制可以使程序达到更高的精度和速度。使C对Fortran程序员更具吸引力。增加了许多数学函数并在C99中做了一些增强例如加入了对复数的支持可以增强C语言对曾经使用过其他编程语言的程序员主要是Fortran程序员的吸引力。 小补充普通的C程序员可能对这一节并不很感兴趣。把C语言用于传统应用程序包括系统编程和嵌入式系统的人可能不需要用到C99提供的新函数。但是开发工程、数学或科学应用程序的程序员可能会觉得这些函数非常有用。 23.4.1 IEEE浮点标准 改动math.h头的动机之一是为了更好地支持IEEE 754标准这是应用最广的浮点数表示方法。这个标准完整的名称为“IEEE Standard for Binary Floating-Point Arithmetic”ANSI/IEEE 标准754-1985也叫作3IEC 60599这是C99标准中的叫法。 7.2节描述了IEEE标准的一些基本性质。该标准提供了两种主要的浮点数格式单精度32位和双精度64位。数值按科学记数法存储每个数包括三个部分符号、指数和小数。对IEEE标准的这一有限了解足以有效地使用C89的math.h了。但是要了解C99的math.h则需要更详细地了解IEEE标准。下面是一些我们需要了解的信息。 正零/负零。在浮点数的IEEE表示中有一位代表数的符号。因此根据该位的不同取值零既可以是正数也可以是负数。零具有两种表示这一事实有时要求我们把它与其他浮点数区别对待。 非规范化的数。进行浮点运算的时候结果可能会太小以至于不能表示这种情况称为下溢出。考虑使用计算器反复除以一个数的情况结果最终为零这是因为数值会变得太小以至于计算器无法显示。IEEE标准提供了一种方法来减弱这种现象的影响。通常浮点数按“规范”格式存储二进制小数点的左边恰好只有一位数字。当数变得足够小时就按另一种非规范化的形式来存储。这些非规范化的数subnormal number也叫作denormalized number或denormal可以比规范化的数小很多代价是当数变得越来越小时精度会逐渐降低。 特殊值。每个浮点格式允许表示三种特殊值正无穷数、负无穷数和NaN非数。正数除以零产生正无穷数负数除以零产生负无穷数数学上没有定义的运算如零除以零产生的结果是NaN更准确的说法是“结果是一种NaN”而不是“结果是NaN”因为IEEE标准有多种表示NaN的方式。NaN的指数部分全为1但小数部分可以是任意的非零位序列。后续的运算中可以用特殊值作为操作数。对无穷数的运算与通常的数学运算是一样的。例如正数除以正无穷数结果为零需要注意算术表达式的中间结果可能会是无穷数但最终结果不是无穷数。对NaN进行任何运算结果都为NaN。 舍入方向。当不能使用浮点表示法精确地存储一个数时当前的舍入方向或者叫舍入模式可以确定选择哪个浮点值来表示该数。一共有4种舍入方向 向最近的数舍入向最接近的可表示的值舍入如果一个数正好在两个数值的中间就向“偶”值最低有效位为0舍入趋零截尾向正无穷方向舍入向负无穷方向舍入。 默认的舍入方向是向最近的数舍入。 异常。有5种类型的浮点异常上溢出、下溢出、除零、无效运算算术运算的结果是NaN和不精确需要对算术运算的结果舍入。当检查到其中任何一个条件时我们称抛出异常。 23.4.2 类型 C99在math.h中加入了两种类型float_t和double_t。float_t类型至少和float型一样“宽”意思是说有可能是float型也可能是double等更宽的类型。同样地double_t要求宽度至少是double类型的至少和float_t一样宽。这些类型提供给程序员以最大限度地提高浮点运算的性能。float_t应该是宽度至少为float的最有效的浮点类型double_t应该是宽度至少为double的最有效的浮点类型。 float_t和double_t类型与宏FLT_EVAL_METHOD23.1节相关如表23-8所示。 表23-8 float_t和double_t类型与FLT_EVAL_METHOD宏的关系 FLT_EVAL_METHOD的值float_t的含义double_t的含义0floatdouble1doubledouble2long doublelong double其他由实现定义由实现定义 23.4.3 宏 C99给math.h增加了许多宏这里只介绍其中的两个INFINITY表示正无穷数和无符号无穷数的float版本如果实现不支持无穷数那么INFINITY表示编译时会导致上溢出的float类型值NAN宏表示“非数”的float版本更具体地说它表示“安静的”NaN用于算术表达式时不会抛出异常。如果不支持安静的NaNNAN宏不会被定义。 本节后面将介绍math.h中类似于函数的宏以及普通的函数。只和具体函数相关的宏与该函数一起讨论。 23.4.4 错误 在大多数情况下C99版本的math.h在处理错误时和C89版本的相同但有几点需要讨论。 首先C99提供的一些宏允许在实现时选择如何提示出错消息通过存储在errno中的值、通过浮点异常或者两者都有。宏MATH_ERRNO和MATH_ERREXCEPT分别表示整型常量1和2。另一个宏math_errhandling表示一个int表达式其值可以是MATH_ERRNO、MATH_ERREXCEPT或者两者按位或运算的结果math_errhandling也可能不是一个真正的宏它可能是一个具有外部链接的标识符。在程序内math_errhandling的值不会改变。 其次我们来看看在调用math.h的函数时出现定义域错误的情形。C89会把EDOM存放在errno中。在C99标准中如果表达式math_errhandlingMATH_ERRNO非零即设置了MATH_ERRNO位那么会把EDOM存放在errno中如果表达式math_errhandlingMATH_ERREXCEPT非零会抛出无效运算浮点异常。根据math_errhandling取值的不同这两种情况都有可能出现。 最后讨论一下在函数调用过程中出现取值范围错误的处理方式。根据返回值的大小有2种情形。 上溢出overflow。如果返回的值太大C89标准要求函数根据正确结果的符号返回正的或负的HUGE_VAL。另外把ERANGE存储在errno中。C99标准在发生上溢出时会有更复杂的处理方式。 如果采用默认的舍入方向或返回值是“精确的无穷数”如log(0.0)根据返回类型的不同函数会返回HUGE_VAL、HUGE_VALF或者HUGE_VALLHUGE_VALF和HUGE_VALL是C99新增的分别表示HUGE_VAL的float和long double版本。与HUGE_VAL一样它们可以表示正无穷数。返回值与正确结果的符号相同。如果math_errhandlingMATH_ERRNO的值非零把ERANGE存于errno中。如果math_errhandlingMATH_ERREXCEPT的值非零当数学计算的结果是精确的无穷数时抛出除零浮点异常否则抛出上溢出异常。 下溢出underflow。如果返回的值太小而无法表示C89要求函数返回0一些实现可能也会将ERANGE存入errno。C99中的处理有点不同。 函数返回值小于或等于相应返回类型的最小规范化正数。这个值可以是0或者非规范化的数。如果math_errhandlingMATH_ERRNO的值非零实现中有可能把ERANGE存于errno中。如果math_errhandlingMATH_ERREXCEPT的值非零实现中有可能抛出下溢出浮点异常。 注意后两种情况中的“有可能”为了执行的效率实现不要求修改errno或抛出下溢出异常。 23.4.5 函数 现在可以讨论C99在math.h中新增的函数了。本节将使用C99标准中的分类方法把函数分组讨论这种分类和23.3节中来自C89的分类有些不一致。 在C99版本中对math.h的最大改动是大部分函数都新增了两个或两个以上的版本。在C89中每个数学函数只有一种版本通常至少有一个double类型的参数或返回值是double类型。C99另外新增了两个版本float类型和long double类型。这些函数名和原本的函数名相同只不过增加了后缀f或l。例如原来的sqrt函数对double类型的值求平方根现在就有了sqrtffloat版本和sqrtllong double版本。本节将列出新版本的原型但不会深入讨论相应的函数因为它们本质上与C89中的对应函数一样。 C99版本的math.h中也有许多全新的函数以及类似函数的宏。将会对每一个函数进行简要的介绍。与23.3节一样本节不会讨论这些函数的错误条件但是在附录D按字母序列出了所有的标准库函数中会给出相关信息。本节没有对所有新函数进行详细描述而只是描述主要的函数。例如有三个函数可以计算反双曲余弦即acosh、acoshf和acoshl将只描述acosh。 一定要记住很多新的函数是非常特别的。因此描述看起来可能会很粗略暂时不讨论对这些函数具体用法。 23.4.6 分类宏 int fpclassify(实浮点 x); int isfinite(实浮点 x); int isinf(实浮点 x); int isnan(实浮点 x); int isnormal(实浮点 x); int signbit(实浮点 x); 我们介绍的第一类包括类似函数的宏它们用于确定浮点数的值是“规范化”的数还是无穷数或NaN之类的特殊值。这组宏的参数都是任意的实浮点类型float、double或者long double。 fpclassify宏对参数分类返回表23-9中的某个数值分类宏。具体的实现可以通过定义以FP_和大写字母开头的其他宏来支持其他分类。 表23-9 数值分类宏 名称含义FP_INFINITE无穷数正或负FP_PAN非数FP_NORMAL规范化的数不是0、非规范化的数、无穷数或 NaNFP_SUBNORMAL非规范化的数FP_ZERO0正或负 如果isfinite宏的参数具有有限值0、非规范化的数或是除无穷数与NaN之外的规范化的数该宏返回非零值。如果isinf的参数值为无穷数正或负该宏返回非零值。如果isnan的参数值是NaN该宏返回非零值。如果isnormal的参数是一个正常值不是0、非规范化的数、无穷数或NaN该宏返回非零值。(非零值真) 最后一个宏与其他几个有点区别。如果参数的符号为负signbit返回非零值。参数不一定是有限数signbit也可以用于无穷数和NaN。 23.4.7 三角函数 float acosf(float x); 见 acos long double acosl(long double x); 见 acos float asinf(float x); 见 asin long double asinl(long double x); 见 asin float atanf(float x); 见 atan long double atanl(long double x); 见 atan float atan2f(float y float x); 见 atan2 long double atan2l(long double y, long double x); 见 atan2 float cosf(float x); 见 cos long double cosl(long double x); 见 cos float sinf(float x); 见 sin long double sinl(long double x); 见 sin float tanf(float x); 见 tan long double tanl(long double x); 见 tanC99中的新三角函数与C89中的函数相似具体描述见23.3节的对应函数。 23.4.8 双曲函数 double acosh(double x); float acoshf(float x); long double acosh1(long double x); double asinh(double x); float asinhf(float x); long double asinhl(long double x);double atanh(double x); float atanhf(float x); long double atanhl(long double x);float coshf(float x); 见 cosh long double coshl(long double x); 见 cosh float sinhf(float x); 见 sinh long double sinhl(long double x); 见 sinh float tanhf(float x); 见 tanh long double tanhl(long double x); 见 tanh这一组的6个函数与C89函数中的cosh、sinh和tanh相对应。新的函数acosh计算双曲余弦asinh计算双曲正弦atanh计算双曲正切。 23.4.9 指数函数和对数函数 float expf(float x); 见 exp long double expl(long double x); 见 exp double exp2(double x); float exp2f(float x); long double exp21(long double x);double expm1(double x); float expm1f(float x); long double expm1l(long double x);float frexpf(float value, int *exp); 见 frexp long double frexpl(long double value, int *exp); 见 frexp int ilogb(double x); int ilogbf(float x) ; int ilogbl(long double x);float ldexpf(float x, int exp); 见 ldexp long double ldexpl(long double x, int exp); 见 ldexp float logf(float x); 见 log long double logl(long double x); 见 log float log10f(float x); 见 log10 long double log10l(long double x); 见 log10 double log1p(double x); float log1pf(float x); long double log1pl(long double x);double log2(double x); float log2f(float x); long double log2l(long double x);double logb(double x); float logbf(float x); long double logbl(long double x);float modff(float value, float *iptr); 见 modf long double modfl(long double value, long double *iptr); 见 modf double scalbn(double x, int n); float scalbnf(float x, int n); long double scalbnl(long double x, int n);double scalbln(double x, long int n); float scalblnf(float x, long int n); long double scalblnl(long double x, long int n);除了exp、frexp、ldexp、log、log10和modf的新版本以外这一类中还有一些全新的函数。其中exp2和expm1是exp函数的变体。当应用于参数x时exp2函数返回 2 x {2^x} 2xexpm1返回 e x − 1 {e^x-1} ex−1。 logb函数返回参数的指数。更准确地说调用logb(x)返回log(r为底(|x|)其中r是浮点算术的基数由宏FLT_RADIX定义通常值为2。ilogb函数把logb的值强制转换为int类型并返回。loglp函数返回ln(1x)其中x是参数。log2函数以2为底计算参数的对数。 函数scalbn返回x乘FLT_RADIX^n这个函数能有效地进行计算不会显式地计算FLT_RADIX的n次幂。scalbln除第二个参数是long int类型之外其他和scalbn函数相同。 23.4.10 幂函数和绝对值函数 double cbrt(double x); float cbrtf(float x); long double cbrtl(long double x);float fabsf(float x); 见 fabs long double fabsl(long double x); 见 fabs double hypot(double x, double y); float hypotf(float x, float y); long double hypotl(long double x, long double y);float powf(float x, float y); 见 pow long double powl(long double x, long double y); 见 pow float sqrtf(float x); 见 sqrt long double sqrtl(long double x); 见 sqrt这一组中的大部分函数是已有函数fabs、pow和sqrt的新版只有cbrt和hypot以及它们的变体是全新的。 cbrt函数计算参数的立方根。pow函数同样可用于这个目的但pow不能处理负参数负参数会导致定义域错误。cbrt既可以用于正参数也可以用于负参数当参数为负时返回负值。 hypot函数应用于参数x和y时返回 x 2 y 2 \sqrt{x^2y^2} x2y2 ​。换句话说这个函数计算的是边长为x和y的直角三角形的斜边。 23.4.11 误差函数和伽马函数 double erf(double x); float erff(float x); long double erfl(long double x);double erfc(double x); float erfcf(float x); long double erfcl(long double x);double lgamma(double x); float lgammaf(float x); long double lgammal(long double x);double tgamma(double x); float tyammaf(float x); long double tgammal(long double x);函数erf计算误差函数erf通常也叫高斯误差函数常用于概率、统计和偏微分方程。erf的数学定义如下 e r f ( x ) 2 π ∫ 0 x e − t 2 d t erf(x) \frac{2}{\sqrt{\pi}}\int_0^x{e^{-t^2}}dt erf(x)π ​2​∫0x​e−t2dt erfc计算余误差函数complementary error function e r f c ( x ) 1 − e r f ( x ) erfc(x)1-erf(x) erfc(x)1−erf(x)。 伽马函数gammafunction Γ \Gamma Γ是阶乘函数的扩展不仅可以应用于整数还可以应用于实数。当应用于整数n时 Γ ( n ) ( n − 1 ) ! {\Gamma(n)(n-1)!} Γ(n)(n−1)!。用于非整数的 Γ \Gamma Γ函数定义更为复杂。tgamma函数计算 Γ \Gamma Γ。lgamma函数计算 l n ( ∣ Γ ( x ) ∣ ) {ln(|\Gamma(x)|)} ln(∣Γ(x)∣)它是伽马函数绝对值的自然对数。lgamma有些时候会比伽马函数本身更有用因为伽马函数增长太快计算时容易导致溢出。 23.4.12 就近舍入函数 float ceilf(float x); 见 ceil long double ceill(long double x); 见 ceil float floorf(float x); 见 floor long double floorl(long double x); 见 floor double nearbyint(double x); float nearbyintf(float x); long double nearbyintl(long double x);double rint(double x); float rintf(float x); long double rintl(long double x);long int lrint (double x); long int lrintf(float x); long int lrintl(long double x); long long int llrint(double x); long long int llrintf(float x); long long int llrintl(long double x);double round(double x); float roundf(float x); long double roundl(long double x); long int lround (double x); long int lroundf(float x); long int lroundl(long double x); long long int llround(double x); long long int llroundf(float x); long long int llroundl(long double x); double trunc(double x); float truncf(float x); long double truncl(long double x);除了ceil和floor的新增版本C99还新增了许多函数用于把浮点值转换为最接近的整数。在使用这些函数时需要注意尽管它们都返回整数但一些函数按浮点格式如float、double或long double值返回一些函数按整数格式如long int或long long int值返回。 nearbyint函数对参数舍入并以浮点数的形式返回。nearbyint使用当前的舍入方向且不会抛出不精确浮点异常。rint与nearbyint相似但当返回值与参数不相同时有可能抛出不精确浮点异常。 lrint函数根据当前的舍入方向对参数向最近的整数舍入。lrint返回long int类型的值。llrint与lrint相似但返回long long int类型的值。 round函数对参数向最近的整数舍入并以浮点数的形式返回。round函数总是向远离零的方向舍入如3.5舍入为4.0。 lround函数对参数向最近的整数舍入并以long int类型值的形式返回。和round函数一样它总是向远离零的方向舍入。llround与lround相似但返回long long int类型的值。 trunc函数对参数向不超过参数的最近的整数舍入。换句话说它把参数趋零截尾。trunc以浮点数的形式返回结果。 23.4.13 取余函数 float fmodf(float x, float y); 见 fmod long double fmodl(long double x, long double y); 见 fmod double remainder(double x, double y); float remainderf(float x, float y); long double remainderl(long double x, long double y);double remquo(double x, double y, int *quo); float remquof(float x, float y, int *quo); long double remquol(long double x, long double y, int *quo);除了fmod的新版本之外这一类还包含两种新增的函数remainder和remquo。 remainder返回的是xREMy的值其中REM是IEEE标准定义的函数。当y不等于0时xREMy的值为rx-ny其中n是与x/y的准确值最接近的整数。如果x/y的值恰好位于两个整数的中间n取偶数。如果r0则与x的符号相一致。 remquo函数的前两个参数值与remainder的相等时其返回值也与remainder的相等。另外remquo函数会修改参数quo指向的对象使其包含整数商|x/y|的n个低位字节其中n依赖于具体的实现但至少为3。如果x/y0存储在该对象中的值为负。 23.4.14 操作函数 double copysign(double x, double y); float copysignf(float x, float y); long double copysignl(long double x, long double y);double nan(const char *tagp); float nanf(const char *tagp); long double nanl(const char *tagp);double nextafter(double x, double y); float nextafterf(float x, float y); long double nextafterl(long double x, long double y);double nexttoward(double x, long double y); float nexttowardf(float x, long double y); long double nexttowardl(long double x, long double y);这些神秘的“操作函数”都是C99新增的。它们提供了对浮点数底层细节的访问。 copysign函数复制一个数的符号到另一个数。函数调用copysign(x,y)返回的值大小与x相等符号与y一样。 nan函数将字符串转换为NaN值。调用nan(n个字符的序列)等价于strtodNAN(n个字符的序列),(char**)NULL。讨论strtod函数26.2节时描述了n个字符的序列的格式。调用nan()等价于strtodNAN(),(char**)NULL。如果nan的参数既不是n个字符的序列又不是那么该调用等价于strtodNAN,(char**)NULL。如果系统不支持安静的NaN那么nan返回0。对nanf和nanl的调用分别等价于对strtof和strtold调用。这个函数用于构造包含特定二进制模式的NaN值。回忆一下本节前面的论述NaN值的小数部分是任意的。 nextafter函数用于确定数值x之后的可表示的值如果x类型的所有值都按序排列这个值将恰好在x之前或x之后。y的值确定方向如果yx则函数返回恰好在x之前的那个值如果xy则返回恰好在x之后的那个值如果x和y相等则返回y。 nexttoward函数和nextafter函数相似区别在于参数y的类型为long double而不是double。如果x和y相等nexttoward将返回被转换为函数的返回类型的y。nexttoward函数的优势在于任意实浮点类型都可以作为第二个参数而不用担心会错误地将其转换为较窄的类型。 23.4.15 最大值函数、最小值函数和正差函数 double fdim(double x, double y); float fdimf(float x, float y); long double fdiml(long double x, long double y);double fmax(double x, double y); float fmaxf(float x, float y); long double fmaxl(long double x, long double y);double fmin(double x, double y); float fminf(float x, float y); long double fmainl(long double x, long double y);函数fdim计算x和y的正差 f ( x ) { x − y , x y 0 , x ≤ y f(x) \begin{cases} x-y,\,\,xy\\ 0,\,\,x\le{y}\\ \end{cases} f(x){x−y,xy0,x≤y​ fmax函数返回两个参数中较大的一个fmin返回较小的一个。 23.4.16 浮点乘加 double fma(double x, double y, double z); float fmaf(float x, float y, float z); long double fmal(long double x, long double y, long double z);fma函数是将它的前两个参数相乘再加上第三个参数。换句话说我们可以将语句 a b * c d;替换为 a fma(b, c, d);在C99中增加这个函数是因为一些新的CPU具有“融合乘加”fused multiply-add指令该指令既执行乘法也执行加法。调用fma告诉编译器使用这个指令如果可以的话这样比分别执行乘法指令和加法指令要快。而且融合乘加指令只进行一次舍入而不是两次所以可以产生更加精确的结果。融合乘加指令特别适用于需要执行一系列乘法和加法运算的算法如计算两个向量点积的算法或两个矩阵相乘的算法。 为了确定是否可以调用fma函数C99程序可以测试FP_FAST_FMA宏是否有定义。如果有定义那么调用fma应该会比分别进行乘法运算和加法运算要快至少一样快。对于fmaf函数和fmal函数FP_FAST_FMAF和FP_FAST_FMAL宏分别扮演着同样的角色。 把乘法和加法合并成一条指令来执行是C99标准中所说的“紧缩”contraction的一个例子。紧缩把两个或多个数学运算合并起来当成一条指令来执行。从fma函数可以看出紧缩通常可以获得更快的速度和更高的精度。但是因为紧缩可能会导致结果发生细微的变化所以程序员希望能控制紧缩是否自动进行上面的fma是显式要求进行紧缩的。极端情况下紧缩可以避免抛出浮点异常。 C99中可以用包含FP_CONTRACT的#pragma指令来实现对紧缩的控制用法如下 #pragma STDC FP_CONTRACT 开关开关的值可以是ON、OFF或DEFAULT。如果选择ON编译器允许对表达式进行紧缩如果选择OFF编译器禁止对表达式进行紧缩DEFAULT用于恢复默认设置ON或OFF。如果在程序的外层所有函数定义的外部使用该指令该指令将持续有效直到在同一个文件中遇到另一条包含FP_CONTRACT的#pragma指令或者到达文件末尾。如果在复合语句包括函数体中使用该指令必须将其放在所有声明和语句之前在到达复合语句的末尾之前该指令都是有效的除非被另一条#pragma覆盖。即便用FP_CONTRACT禁止了对表达式的自动紧缩程序仍然可以调用fma执行显式的紧缩。 23.4.17 比较宏 int isgreater(实浮点 x, 实浮点 y); int isgreaterequal(实浮点 x, 实浮点 y); int isless(实浮点 x, 实浮点 y); int islessequal(实浮点 x, 实浮点 y); int islessgreater(实浮点 x, 实浮点 y); int isunordered(实浮点 x, 实浮点 y);最后一类类似函数的宏对两个数进行比较它们的参数可以是任意实浮点类型。 增加比较宏是因为使用普通的关系运算符如和比较浮点数时会出现问题。如果任一操作数或两个是NaN那么这样的比较就可能导致抛出无效运算浮点异常因为NaN的值不同于其他浮点数的值被认为是无序的。比较宏可以用来避免这种异常。这些宏可以称作关系运算符的“安静”版本因为它们在执行时不会抛出异常。 isgreater、isgreaterequal、isless和islessequal宏分别执行与、、和相同的运算区别在于当参数无序时它们不会抛出无效运算浮点异常。 调用islessgreater(x,y)等价于(x)(y)||(x)(y)唯一的区别在于前者不会对x和y求两次值而且与之前提到的宏一样当x和y无序时不会导致抛出无效运算浮点异常。 isunordered宏在参数无序其中至少一个是NaN时返回1否则返回0。 23.5 ctype.h: 字符处理 ctype.h提供了两类函数字符分类函数如isdigit函数用来检测一个字符是否是数字和字符大小写映射函数如toupper函数用来将一个小写字母转换成大写字母。 虽然C语言并不要求必须使用ctype.h中的函数来测试字符或进行大小写转换但我们仍建议使用ctype.h中定义的函数来进行这类操作: 第一这些函数已经针对运行速度进行过优化实际上大多数都是用宏实现的第二使用这些函数会使程序的可移植性更好因为这些函数可以在任何字符集上运行第三当地区locale 25.1节改变时ctype.h中的函数会相应地调整其行为使我们编写的程序可以正确地运行在世界上不同的地点。 ctype.h中定义的函数都具有int类型的参数并返回int类型的值。许多情况下参数事先存放在一个int型的变量中通常是调用fgetc、getc或getchar读取的结果。当参数类型为char时需要小心。C语言可以自动将char类型的参数转换为int类型如果char是无符号类型或者使用ASCII之类的7位字符集转换不会出问题但如果char是有符号类型且有些字符需要用8位来表示那么把这样的字符从char转换为int就会得到负值。当参数为负时ctype.h中的函数行为是未定义的EOF除外这样可能会造成一些严重的问题。这种情况下应把参数强制转换为unsigned char类型以确保安全。为了最大化可移植性一些程序员在使用ctype.h中的函数之前总是把char类型的参数强制转换为unsigned char类型。 23.5.1 字符分类函数 int isalnum(int c); int isalpha(int c); int isblank(int c); int iscntrl(int c); int isdigit(int c); int isgraph(int c); int islower(int c); int isprint(int c); int ispunct(int c); int isspace(int c); int isupper(int c); int isxdigit(int c); 如果参数具有某种特定的性质字符分类函数会返回非零值。表23-10列出了每个函数所测试的性质。 表23-10 字符分类函数 取值取值对应的舍入模式isalnum©c是否是字母或数字isalpha©c是否是字母isblank©c是否是标准空白字符①iscntrl©c是否是控制字符②isdigit©c是否是十进制数字isgraph©c是否是可显示字符除空格外islower©c是否是小写字母isprint©c是否是可打印字符包括空格ispunct©c是否是标点符号③isspace©c是否是空白字符④isupper©c是否是大写字母isxdigit©c是否是十六进制数字 ①标准空白字符是空格和水平制表符\t。这是C99中的新函数。 ②在ASCII字符集中控制字符包括\x00至\x1f以及\x7f。 ③标点符号包括所有可打印字符但要除掉使isspace或isalnum为真的字符。 ④空白字符包括空格、换页符\f、换行符\n、回车符\r、水平制表符\t和垂直制表符\v。 ispunct在C99中的定义与在C89中的定义略有不同。在C89中ispunct(c)测试c是否为除空格符和使isalnum(c)为真的字符以外的可打印字符。在C99中ispunct(c)测试c是否为除了使isspace(c)或isalnum(c)为真的字符以外的可打印字符。 23.5.2 字符大小写映射函数 int tolower(int c); int toupper(int c); tolower函数返回与作为参数传递的字母相对应的小写字母而toupper函数返回与作为参数传递的字母相对应的大写字母。对于这两个函数如果所传参数不是字母那么将返回原始字符不加任何改变。 下面的程序对字符串aA0!中的字符进行大小写转换: /* tcasemap.c --Tests the case-mapping functio */ #include ctype.h #include stdio.h int main(void) { char *p; for (p aA0!; *p ! \0; p) { printf(tolower(%c) is %c; , *p, tolower(*p)); printf(toupper(%c) is %c\n, *p, toupper(*p)); } return 0; } /* 这段程序产生的输出如下: tolower(a) is a; toupper(a) is A tolower(A) is a; toupper(A) is A tolower(0) is 0; toupper(0) is 0 tolower(!) is !; toupper(!) is ! */23.6 string.h: 字符串处理 我们第一次见到string.h是在13.5节那一节中讨论了最基本的字符串操作字符串复制、字符串拼接、字符串比较以及字符串长度计算。接下来我们将看到除了用于字符数组不需要以空字符结尾的字符串处理函数之外string.h中还有许多其他字符串处理函数。前一类函数的名字以mem开头以表明它们处理的是内存块而不是字符串。这些内存块可以包含任何类型的数据因此mem函数的参数类型为void *而不是char *。 string.h提供了5种函数 复制函数将字符从内存中的一处复制到另一处。拼接函数向字符串末尾追加字符。比较函数用于比较字符数组。搜索函数在字符数组中搜索一个特定字符、一组字符或一个字符串。其他函数初始化字符数组或计算字符串的长度。 23.6.1 复制函数 void *memcpy(void * restrict s1, const void * restrict s2, size_t n); void *memmove(void * s1, const void * s2, size_t n); char *strcpy(char * restrict s1, const char * restrict s2); char *strncpy(char * restrict s1, const char * restrict s2, size_t n);这一类函数将字符字节从内存的一处源移动到另一处目的地。每个函数都要求第一个参数指向目的地第二个参数指向源。所有的复制函数都会返回第一个参数即指向目的地的指针。 memcpy函数从源向目的地复制n个字符其中n是函数的第三个参数。如果源和目的地之间有重叠memcpy函数的行为是未定义的。memmove函数与memcpy函数类似只是在源和目的地重叠时它也可以正常工作。 strcpy函数将一个以空字符结尾的字符串从源复制到目的地。strncpy与strcpy类似只是它不会复制多于n个字符其中n是函数的第三个参数。如果n太小strncpy可能无法复制结尾的空字符。如果strncpy遇到源字符串中的空字符它会向目的字符串不断追加空字符直到写满n个字符为止。与memcpy类似strcpy和strncpy不保证当源和目的地相重叠时可以正常工作。 下面的例子展示了所有的复制函数注释中给出了哪些字符会被复制: char source[] {h, o, t, \0, t, e, a}; char dest[7]; memcpy(dest, source, 3); /* h, o, t */ memcpy(dest, source, 4); /* h, o, t, \0 */ memcpy(dest, source, 7); /* h, o, t, \0, t, e, a */ memmove(dest, source, 3); /* h, o, t */ memmove(dest, source, 4); /* h, o, t, \0 */ memmove(dest, source, 7); /* h, o, t, \0, t, e, a */ strcpy(dest, source); /* h, o, t, \0 */ strncpy(dest, source, 3); /* h, o, t */ strncpy(dest, source, 4); /* h, o, t, \0 */ strncpy(dest, source, 7); /* h, o, t, \0, \0, \0, \0 */ 注意!!memcpy、memmove和strncpy都不要求使用空字符结尾的字符串它们对任意内存块都可以正常工作。而strcpy函数则会持续复制字符直到遇到一个空字符为止因此strcpy仅适用于以空字符结尾的字符串。 13.5节给出了strcpy和strncpy的常见用法示例。这两个函数都不完全安全但至少strncpy提供了一种方法来限制所复制字符的个数。 23.6.2 拼接函数 char *strcat(char * restrict s1, const char * restrict s2); char *strncat(char * restrict s1, const char * restrict s2, size_t n); strcat函数将它的第二个参数追加到第一个参数的末尾。两个参数都必须是以空字符结尾的字符串。strcat函数会在拼接后的字符串末尾添加空字符。考虑下面的例子 char str[7] tea; strcat(str, bag); /* adds b, a, g, \0 to end of str */ 字母b会覆盖tea中字符a后面的空字符因此现在str包含字符串teabag。strcat函数会返回它的第一个参数指针。 strncat函数与strcat函数基本一致只是它的第三个参数会限制所复制字符的个数 char str[7] tea; strncat(str, bag, 2); /* adds b, a, \0 to str */ strncat(str, bag, 3); /* adds b, a, g, \0 to str */ strncat(str, bag, 4); /* adds b, a, g, \0 to str */正如上面的例子所示strnact函数会保证其结果字符串始终以空字符结尾。 在13.5节中我们发现strncat的调用通常具有如下形式 strncat(str1, str2, sizeof(str1) – strlen(str1) – 1); 第三个参数计算str1中剩余的空间大小由表达式sizeof(str1) – strlen(str1)给定然后减1以确保给空字符留出空间。 23.6.3 比较函数 int memcmp(const void *s1, const void *s2, size_t n); int strcmp(const char *s1, const char *s2); int strcoll(const char *s1, const char *s2); int strncmp(const char *s1, const char *s2, size_t n); size_t strxfrm(char * restrict s1, const char * restrict s2, size_t n); 比较函数分为2组。第一组中的函数memcmp、strcmp和strncmp比较两个字符数组的内容第二组中的函数strcoll函数和strxfrm函数在需要考虑地区25.1节时使用。 memcmp、strcmp和strncmp函数有许多共性。这三个函数都需要以指向字符数组的指针作为参数然后用第一个字符数组中的字符逐一地与第二个字符数组中的字符进行比较。这三个函数都是在遇到第一个不匹配的字符时返回。另外这三个函数都根据比较结束时第一个字符数组中的字符是小于、等于还是大于第二个字符数组中的字符而相应地返回负整数、0或正整数。 这三个函数之间的差异在于如果数组相同则何时停止比较。memcmp函数包含第三个参数nn会用来限制参与比较的字符个数但memcmp函数不会关心空字符。strcmp函数没有对字符数设定限制因此会在其中任意一个字符数组中遇到空字符时停止比较。因此strcmp函数只能用于以空字符结尾的字符串。strncmp结合了memcmp和strcmp当比较的字符数达到n个或在其中任意一个字符数组中遇到空字符时停止比较。 下面的例子展示了memcmp、strcmp和strncmp的用法 char s1[] {b, i, g, \0, c, a, r}; char s2[] {b, i, g, \0, c, a, t}; if (memcmp(s1, s2, 3) 0) ... /* true */ if (memcmp(s1, s2, 4) 0) ... /* true */ if (memcmp(s1, s2, 7) 0) ... /* false */ if (strcmp(s1, s2) 0)... /* true */ if (strncmp(s1, s2, 3) 0) ... /* true */ if (strncmp(s1, s2, 4) 0) ... /* true */ if (strncmp(s1, s2, 7) 0) ... /* true */ strcoll函数与strcmp函数类似但比较的结果依赖于当前的地区。 大多数情况下strcoll都足够用来处理依赖于地区的字符串比较。但有些时候我们可能需要多次进行比较strcoll的一个潜在问题是它不是很快或者需要改变地区而不影响比较的结果。在这些情况下strxfrm函数“字符串变换”可以用来代替strcoll使用。 strxfrm函数会对它的第二个参数一个字符串进行变换将变换的结果放在第一个参数所指向的字符串中。第三个参数用来限制向数组输出的字符个数包括最后的空字符。用两个变换后的字符串作为参数调用strcmp函数所产生的结果应该与用原始字符串作为参数调用strcoll函数所产生的结果相同负、0或正。 strxfrm函数返回变换后字符串的长度因此strxfm函数通常会被调用两次一次用于判断变换后字符串的长度一次用来进行变换。下面是一个例子: size_t len; char *transformed; len strxfrm(NULL, original, 0); transformed malloc(len 1); strxfrm(transformed, original, len);23.6.4 搜索函数 void *memchr(const void *s, int c, size_t n); char *strchr(const char *s, int c); size_t strcspn(const char *s1, const char *s2); char *strpbrk(const char *s1, const char *s2); char *strrchr(const char *s, int c); size_t strspn(const char *s1, const char *s2); char *strstr(const char *s1, const char *s2); char *strtok(char * restrict s1, const char * restrict s2); strchr函数在字符串中搜索特定字符。下面的例子说明了如何使用strchr函数在字符串中搜索字母f char *p, str[] Form follows function.; p strchr(str, f); /* finds first f */ strchr函数会返回一个指针这个指针指向str中出现的第一个f即单词follows中的f。如果需要多次搜索字符也很简单例如可以使用下面的调用搜索str中的第二个f即单词function中的f p strchr(p 1, f); /* finds next f */ //如果不能定位所需的字符strchr返回空指针。memchr函数与strchr函数类似但memchr函数会在搜索了指定数量的字符后停止搜索而不是当遇到首个空字符时才停止。memchr函数的第三个参数用来限制搜索时需要检测的字符总数。当不希望对整个字符串进行搜索或搜索的内存块不是以空字符结尾时memchr函数会十分有用。下面的例子用memchr函数在一个没有以空字符结尾的字符数组中进行搜索 char *p, str[22] Form follows function.; p memchr(str, f, sizeof(str));与strchr函数类似memchr函数也会返回一个指针指向该字符第一次出现的位置。如果找不到所需的字符memchr函数返回空指针。 strrchr函数与strchr类似但它会反向搜索字符 char *p, str[] Form follows function.; p strrchr(str, f); /* finds last f */ 在此例中strrchr函数会首先找到字符串末尾的空字符然后反向搜索字母f单词function中的f。与strchr和memchr一样如果找不到指定的字符strrchr函数也返回空指针。 strpbrk函数比strchr函数更通用它返回一个指针该指针指向第一个参数中与第二个参数中任意一个字符匹配的最左边一个字符 char *p, str[] Form follows function.; p strpbrk(str, mn); /* finds first m or n */ /* 在此例中p最终会指向单词Form中的字母m。 当找不到匹配的字符时strpbrk函数返回空指针。 */ strspn函数和strcspn函数与其他的搜索函数不同它们会返回一个表示字符串中特定位置的整数size_t类型。当给定一个需要搜索的字符串以及一组需要搜索的字符时strspn函数返回字符串中第一个不属于该组字符的字符的下标。对于同样的参数strcspn函数返回第一个属于该组字符的字符的下标。下面是使用这两个函数的例子 size_t n; char str[] Form follows function.; n strspn(str, morF); /* n 4 */ n strspn(str, \t\n); /* n 0 */ n strcspn(str, morF); /* n 0 */ n strcspn(str, \t\n); /* n 4 */strstr函数在第一个参数字符串中搜索第二个参数也是字符串。在下面的例子中strstr函数搜索单词fun char *p, str[] Form follows function.; p strstr(str, fun); /* locates fun in str */strstr函数返回一个指向待搜索字符串第一次出现的地方的指针。如果找不到则返回空指针。在上例的调用后p会指向function中的字母f。 strtok函数是最复杂的搜索函数。它的目的是在字符串中搜索一个“记号”——就是一系列不包含特定分隔字符的字符。调用strtok(s1,s2)会在s1中搜索不包含在s2中的非空字符序列。strtok函数会在记号末尾的字符后面存储一个空字符作为标记然后返回一个指针指向记号的首字符。 strtok函数最有用的特点是以后可以调用strtok函数在同一字符串中搜索更多的记号。调用strtok(NULL,s2)就可以继续上一次的strtok函数调用。和上一次调用一样strtok函数会用一个空字符来标记新的记号的末尾然后返回一个指向新记号的首字符的指针。这个过程可以持续进行直到strtok函数返回空指针这表明找不到符合要求的记号。 这里就不讨论strtok函数的工作原理了要明白strtok有几个众所周知的问题这些问题限制了它的使用。这里只说以下两个问题。首先strtok每次只能处理一个字符串不能同时搜索两个不同的字符串。其次strtok把一组分隔符与一个分隔符同等看待因此如果字符串中有些字段用分隔符例如逗号分开有些字段为空那么strtok就不适用了。 23.6.5 其他函数 void *memset(void *s, int c, size_t n); size_t strlen(const char *s); memset函数会将一个字符的多个副本存储到指定的内存区域。假设p指向一块N字节的内存调用 memset(p, , N);会在这块内存的每个字节中存储一个空格。memset函数的一个用途是将数组全部初始化为0 memset(a, 0, sizeof(a));memset函数会返回它的第一个参数指针。 strlen函数返回字符串的长度字符串末尾的空字符不计算在内。strlen函数的调用示例见13.5节。 此外还有一个字符串函数——strerror函数24.2节会和errno.h一起讨论。 问与答 问1expml函数的作用仅仅是从exp函数的返回值里减去1为什么需要这个函数呢 答把exp函数应用于接近0的数时其返回结果非常接近1。因为舍入误差的存在从exp的返回值里减去1可能不精确。这种情况下expml可以用来获得更精确的结果。 loglp函数的作用也是类似的。对于接近0的x值loglp(x)比log(1x)更精确。 问2计算伽马函数的函数为什么命名为tgamma而不是gamma呢 答起草C99标准的时候有些编译器已提供了名为gamma的函数但计算的是伽马函数的对数。这个函数后来重命名为lgamma。把伽马函数的名字选为gamma可能会和已有的程序相冲突所以C99委员会决定改用tgamma意为“truegamma”。 问3描述nextafter函数时为什么说当x和y相等时返回y呢如果x和y相等返回x与返回y有区别吗 答考虑调用nextafter(-0.0,0.0)从数学上讲两个参数是相等的。如果返回y而不是x函数的返回值为0.0而不是-0.0那样有违直觉。类似地调用nextafter(0.0,-0.0)返回-0.0。 问4为什么string.h中提供了那么多方法来做同一件事呢真的需要4个复制函数memcpy、memmove、strcpy和strncpy吗 答我们先看memcpy函数和strcpy函数使用这两个函数的目的是不同的strcpy函数只会复制一个以空字符结尾的字符数组也就是字符串memcpy函数可以复制没有这一终止字符的内存块如整数数组。 另外两个函数可以使我们在安全性和运行速度之间做出选择。strncpy函数比strcpy函数更安全因为它限制了复制字符的个数。当然安全也是有代价的因为strncpy函数比strcpy函数慢一点。使用memmove函数也需要做出类似的抉择。memmove函数可以将字符从一块内存区域复制到另一块可能会与之相重叠的内存区域中。在同样的情况下memcpy函数无法保证能够正常工作然而如果可以确保没有重叠memcpy函数很可能会比memmove函数要快一些。 问5为什么strspn函数有这么一个奇怪的名字 答不要将strspn函数的返回值理解为不属于指定字符集合的第一个字符的下标而要将它的返回值理解为属于指定字符集合的字符的最长“跨度”span。 写在最后 本文是博主阅读《C语言程序设计现代方法第2版·修订版》时所作笔记日后会持续更新后续章节笔记。欢迎各位大佬阅读学习如有疑问请及时联系指正希望对各位有所帮助Thank you very much!
http://www.zqtcl.cn/news/156686/

相关文章:

  • 平顶山市哪里有做网站的wordpress应用教程
  • 制作企业网站的实训报告医院网站设计模板
  • 要做网站照片怎么处理广东外发加工网
  • 做国际网站每年要多少钱厦门 外贸商城网站
  • 城乡建设学校官方网站程序外包网站
  • 深圳 网站设计师 招聘西数网站管理助手 伪静态
  • 广州网站备案要求国外工装设计网站大全
  • php+mysql 2012也买酒商城网站源码怎么用net123做网站
  • 西充移动网站建设如何设计一个简洁的logo
  • 济宁做网站自媒体新手入门
  • 重庆网站开发哪家专业网站布局图
  • 网站设计原则的历史网站开发 模块
  • 做企业网站收费自己的网站怎么做排名
  • 做网站网站软件开发经费预算
  • 优化网站图片网站图片布局
  • 有效的网站需要做到什么意思商业网站是什么
  • 网站设计开发网站用c 建网站时怎么做导航菜单栏
  • 哪些网站做推广比较有效果厦门网站建设公司名单
  • 街头小吃加盟网站建设网站专题制作
  • 网站论坛推广方案加强思政部网站建设
  • 查看WordPress网站插件北京西站附近的景点有哪些
  • 网站建设技术合同模板下载怎么用phpstudy做网站
  • 青岛网站建设找二维码生成器怎么弄
  • 百度突然搜不到我的网站网络安全软件有哪些
  • 江阴做网站的地方网站维护需要的知识
  • 做网站是域名怎么申请网页设计跟做网站一样吗
  • 叮当快药网站谁做的网站开发遇到的最大困难
  • 一个域名可以建几个网站毕业设计可以做哪些简单网站
  • 知名商城网站建设报价wordpress 后台 logo
  • 单位网站建设框架yellow网站推广联盟