C Primer Plus (第五版)中文版——第 11 章 字符串和字符串函数

11.1  字符串表示和字符串 I/O

11.1  在程序中定义字符串

一、字符串常量

字符串常量(string constant)又称字符串文字(string literal),是指位于一对双引号中的任何字符。字符串常量属于静态存储类。

可以用 #define 来定义字符串常量,也可以直接作为函数 printf() 或 puts() 的参数。

#define HMG "Hello,Mr.Gold!"
printf("Hello,Mr.Gold!");
puts("Hello,Mr.Gold!");
  • 如果字符串文字中间没有间隔或间隔的是空格符,ANSI C 将会将其串联起来。以下两条语句等效:
char greeting[20] = "Hello," "Mr"".Gold!";
char greeting[20] = "Hello, Mr.Gold!";
  • 如果想在字符串中使用双引号,可以在双引号前加一个反斜线符号(转义序列)。

整个引号中的内容作为指向该字符串存储位置的指针。

printf("%s, %p, %c", "How", "are", *"you?");    //输出为 How, 0x0040c010, y 

二、字符数组及其初始化

const char try[20] = "Just have a try!";    //const表示这个字符串不可修改

双引号里的字符加上编译器自动提供的结束标志 \0 字符,作为一个字符串存储在内存里。字符数组名也是数组首元素的地址:

try == &try[0];    *try == try[0] == 'J';    *(try + 1) == try[1] == 'u';    //不考虑语法问题,三个关系式成立

指定数组大小时,确保数组元素比字符串长度至少多1,用于存放空字符 \0。未被初始化的元素全都被自动初始化为空字符 \0。

初始化字符数组时也可以省略数组大小,由编译器决定数组大小。

const char try[] = "Just have a try!";

也可以使用指针符号建立字符串:

const char *try = "Just have a try!";

 三、数组与指针

数组初始化是从静态存储区把一个字符串复制给数组,指针初始化只是复制字符串的地址。

四、数组和指针的差别

char heart[] = "Just have a try!";    //数组名heart是常量,但数组的元素是变量
char *head = "Just Have A Try!";      //指针head是变量,可以改变其指向的地址
putchar(heart[1]);     //都可以使用数组符号
putchat(head[1]);
putchar(*(heart + 1)); //都可以使用指针加法
putchat(*(head + 1));
putchar(*(head++));    //只有指针可以使用增量运算符
head = heart;          //可以让指针指向数组,这样指针就不再指向原来的字符串
heart[5] = 'H';        //可以访问单个的数组元素
*(heart+5) = 'H';
const char * pt = "KingJames!";       //建议初始化一个指向字符串常量的指针时使用const修饰符

五、字符串数组

const char *title[3] = {"Hello!","Mr.Gold","Just have a try!"};    //一个字符串数组

title 是由3个指向 char 的指针组成的数组,即 title 是一维数组, 包含3个元素,每个元素是一个 char 类型的地址。实际上,title 数组并不存放字符串,只存放字符串的地址(字符串存放在程序用来存储常量的那部分内存中)。因此数组的第一个元素 title[0] 指向第一个字符串的第一个字符,即 *title[0] == 'H' 。由于数组符号和指针的关系,也可以用 title[0][0] 表示第一个字符串的第一个字符。这种方式不浪费任何存储空间。

11.1.2  指针和字符串

事实上,绝大多数的 C 字符串操作使用的都是指针。

char * mesg = "Sunshine!";
char * copy;
cope = mesg;        //字符串本身没有被复制,而是将mesg的值(字符串的地址)赋给copy,之后两者指向同一地址
printf("%p, &p", mesg, copy);    //输出两个指针的值(即所指向的地址),输出是一样的,因为两者指向同一个字符串

11.2  字符串输入

11.2.1  创建存储空间

最简单的方法就是在声明中明确指出数组大小。另一种方法就是使用 C 库里分配存储空间的函数。

11.2.2  gets() 函数

gets() 读取字符串直到遇到一个换行字符(\n),按回车键可以产生这个字符。它读取换行符之前(不包括换行符)的所有字符,在这些字符后添加一个空字符(\0),然后把这个字符串交给调用它的程序。

char name[81];
char * ptr;
ptr = gets(name);    //把字符串放入name数组中,并把字符串的地址分配给ptr

如果一切顺利,get() 返回读入的字符串的地址;如果出错或遇到文件结尾,它返回一个空地址,这个空地址称为空指针 NULL。

while(gets(name) != NULL)    //既可检查是否到了文件尾,也可读取一个值

11.2.3  fgets() 函数

gets() 函数的不足是它不检查预留存储区是否能够容纳实际输入的数据。多出来的字符简单地溢出到相邻的内存区。fgets() 函数改进了这个问题,它让您指定最大读入字符数。fgets() 函数是为文件 I/O 设计的,在处理键盘输入时不如 gets() 方便。fgets() 与gets() 有三方面不同:

  • fgets() 需要第二个参数来说明最大读入字符数。如果这个参数值为 n,fgets() 就会读取最多 n-1 个字符或读完一个换行符为止,以两个条件中最先满足的那个来结束输入。
  • fgets() 读到换行符,就会把它存到字符串里,而不是像 gets() 那样丢弃它。
  • fgets() 还需要第三个参数来说明读那个文件。从键盘上读数据时,可以使用 stdin 作为参数,这个标识符在 stdio.h 中定义。

10.2.4  scanf() 函数

可以使用带有 %s 格式的 scanf() 函数来读入一个字符串。scanf() 和 gets() 主要的区别在于它们如何决定字符串合适结束。

  • scanf() 更倾向于获取单词(get word)而不是获取字符串(get string)。使用 %s 的scanf() 读到(但不包括)下一个空白字符。
  • 若指定了字段宽度,如 %10s,scanf() 就会读入10个字符或直到遇到第一个空白字符,以两个条件中最先满足的那个来结束输入。

11.3  字符串输出

11.3.1  puts() 函数

puts() 函数的使用很简单,只需给出字符串参数的地址。

char str1[20] = "You are my sunshine!";
consr char * str2 = "My only sunshine!";

puts(str1);
puts(str2);    //puts()显示字符串时自动在其后添加一个换行符

11.3.2  fputs() 函数

fputs() 函数是 puts() 函数的面向文件版本。两者之间的主要区别是:

  • fputs() 需要第二个参数来说明要写的文件。可以使用 stdout 作为参数来进行输出显示,stdout 在 stdio.h 中定义。
  • fputs() 并不为输出自动添加换行符。

11.3.3  printf() 函数

printf() 不会自动在新行上输出每一个字符串。但 printf() 使在一行上输出多个字符串变得更为简单。

11.4  自定义字符串输入 / 输出函数

/*一个自定义字符串处理函数——不添加换行符打印一个字符串*/
#include <stdio.h>
void put1(const char * string)
{
        while(*string)
        {
                put1(*string++);    //先输出string指向的值,再增加string本身
        }
}

11.5  字符串函数

11.5.1  strlen() 函数

strlen() 函数以字符为单位给出字符串的长度(不包括空字符)。

11.5.2  strcat() 函数

strcat() 函数接受两个字符串参数,它将第二个字符串的一份拷贝添加到第一个字符串的结尾(第二个字符串的第一个字符会覆盖第一个字符串结尾处的空字符),从而使第一个字符串成为一个新的组合字符串,而第二个字符串没有改变。strcat() 函数是 char * 类型,它返回第一个参数的值。

11.5.3  strncat() 函数

strcat() 函数并不检查第一个数组能否容纳第二个字符串,如果没有为第一个数组分配足够大的空间,多出来的字符溢出到相邻存储单元时就会出现问题。strncat() 函数需要另一个参数来指明最多允许添加的字符的数目。例如:

strncat(try, answer, 10);    
//把addon字符串中的内容添加到bugs的结尾,直到加上10个字符或遇到空字符为止,以两个条件中最先满足的那个来终止添加过程

11.5.4  strcmp() 函数

strcmp() 函数比较两个字符串的内容 ,如果两个字符串参数相同,它就返回0。

while(strcmp(try, answer);    //比较两个字符串(只看try的第一个空白符之前的部分)

11.5.5  strncmp() 变种

strcmp() 函数比较两个字符串时,一直比较到找到不同的相应字符,搜索可能要进行到字符串结尾处。

strncmp() 函数比较两个字符串时,可以比较到字符串不同处,也可以比较完由第三个参数指定的字符数。

strncmp(try, answer, 3);    //限定比较两个字符串的前3个字符

11.5.6  strcpy() 和 strncpy() 函数

strcpy() 函数可复制字符串,它在字符串运算中的作用等价于赋值运算符。strcpy() 函数接受两个字符串指针参数,指向源字符串的第二个指针可以是一个已声明的指针,数组名或字符串常量,指向目标字符串的第一个指针应指向空间足够容纳该字符串的数据对象,比如一个数组。

strcpy(try, answer);

一、strcpy() 的高级属性

  • strcpy() 是 char * 类型,它返回的是第一个参数的值。
  • strcpy() 的第一个参数不必指向数组的开始,这样就可以只复制数组的一部分。
  • strcpy() 从源字符串复制空字符。

二、较为谨慎的选择:strncpy()

strncpy() 需要第三个参数来指明最大可复制的字符数。

strcpy(try, answer, n);    //从answer把n个字符(或空字符之前的字符,由最先满足的条件决定何时终止)复制到try

11.5.7  sprintf() 函数

sprintf() 函数作用和 printf() 一样,但是它写到字符串里而不是写到输出显示。sprintf() 函数的第一个参数是目标字符串的地址,其余的参数和 printf() 函数一样:一个转换说明符,接着是要写的项目的列表。

sprintf(try, "%s, %s\n", answer1, answer2);    //将两个字符串组合成一个单一的字符串后存放在字符串try中

11.7  ctype.h 字符函数和字符串

ctype.h 字符函数不能被应用于整个字符串,但可以应用于字符串中的个别字符。例如将 toupper() 函数应用于一个字符串的每个字符,就可以将整个字符串转换为大写。

11.9  把字符串转换为数字

C 有一些函数专门用于把字符串形式转换为数字形式。

猜你喜欢

转载自blog.csdn.net/Mr__Gold/article/details/84238444
今日推荐