前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >第八节(字符和字符串)

第八节(字符和字符串)

作者头像
冷影玺
发布2023-10-12 14:11:51
3100
发布2023-10-12 14:11:51
举报
文章被收录于专栏:冷影玺

字符是单个的字母、数字、标点符号或其他类似的符号。

字符串是任意的字符序列。字符串用于储存由字母、数字、标点符号或其他符号组成的文本数据。

在许多程序中,字符和字符串都相当有用。

●如何用C语言的char数据类型储存单个字符

●如何创建char类型的数组储存多个字符串

●如何初始化字符和字符串

●字符串和指针的关系

●如何输入字符和字符串,并将其打印出来

一.char数据类型:

C语言使用char数据类型来储存字符。

char是C语言中的一种整型数值数据类型。既然char是一种数值类型,那它怎能储存字符?

这要归功于C语言储存字符的方式。计算机在内存中以数值方式储存所有的数据,没有直接的方式储存字符。

但是,每个字符都有对应的数值代码,列于ASCI I码或ASCI I字符集中(ASCII是 AmericanStandard Code for Informat ion Interchange (美国信息交换标准码的缩写))。

该字符集中所有的大小写字母、数字(0~9) 、标点符号和其他字符都对应一个0~255的值。

注意:

ASCII1码或ASCII字符集是为使用单字节字符集的系统设计的。在多字节字符集的系统中,应使用不同的字符集。

例如,字母a的ASCII码是97。在char类型变量里储存字符a时,实际上储存的是97。由于char类型允许的数值范围与标准ASCII字符集的范围匹配,因此char非常适合储存字符。

现在,你可能有些困惑。如果C语言以数字的形式储存字符,那么程序如何知道给定的char类型变量是字符还是数字?

稍后会介绍,只将变量声明为char类型是不够的,还需要处理一下变量:

●如果char类型的变量在C程序中用作字符,该变量就被解译成字符;

●如果char类型的变量在C程序中用作数字,该变量就被解译成数字。

以上初步介绍了C语言如何使用数值数据类型来储存字符数据,接下来详细介绍相关内容。

二.使用字 符变量:

与其他变量类似,在使用char 类型变量之前必须先声明,可以在声明变量的同时初始化它。下面是一些范例:

代码语言:javascript
复制
char a, b, c;      /*声明3个未初始化的char类型变量 */

char code = 'x';  /*声明一个char类型的变量code,并为其储存x字符*/

code = '!';        /*在变量code中储存!字符*/

要创建字面字符常量,用单引号将单个字符括起来即可。

编译器会把字面字符常量自动翻译成相应的ASCII码,然后把相应的数值代码值赋值给变量。

要创建符号字符常量,可以使用#define指令或const关键字:

代码语言:javascript
复制
#define EX 'x'

char code = EX;   /*将code设置为'x' */

const char A = 'Z';

知道如何声明并初始化字符变量后,来看一个示例。

printf()函数用于打印字符和数字。格式字符串中的转换说明%c告诉printf()以字符形式打印变量,而%d则告诉printf()以十进制整数形式打印变量。

程序清单初始化了两个char类型的变量,并将其分别打印出来,先打印字符再打印数字。

输入:

代码语言:javascript
复制
// char类型变量的数值性质

#include <stdio.h>

// 声明并初始化两个char变量

char c1 = 'a';
char c2 = 90;

int main(void)
{
  // 以字符形式打印c1,然后以数字形式打印c1
  
  printf("\nAs a character, variable c1 is %c", c1);
  printf("\nAs a number, variable c1 is %d", c1);
  
  // 以字符形式打印c2,然后以数字形式打印c2
  
  printf("\nAs a character, variable c2 is %c", c2);
  printf("\nAs a number, varable c2 is %d\n", c2);
  
  return 0;
}

输出:

解析:

代码语言:javascript
复制
char类型的最大取值是127,而ASCII码的最大取值是255。
实际上,ASCII码被 分成了两部分。
标准的ASCII码最大值是127,其中包含所有的字母、数字、标点符号和键盘上的其他字符。
从128到255是扩展的ASCII码,用于表示特殊的字符,如外来字母和图形符号。
因此,对于标准的文本数据,可以使用char类型的变量。
如果要打印扩充的ASCII字符,则必须使用unsignedchar类型的变量。

下面程序清单打印了一些扩展的ASCII字符。

输入:

代码语言:javascript
复制
// 打印扩展的ASCII字符示例

#include <stdio.h>

unsigned char mychar;  //必须用unsigned char 类型的变量储存扩展的字符

int main(void)
{
  // 打印扩展的ASCII字符(180 ~ 203)
  
  for (mychar = 180; mychar < 124; mychar++)
  {
    printf("ASCII code %d is character %c\n", mychar, mychar);
  }
  
  return 0;
}

输出:

解析:

代码语言:javascript
复制
该程序清单中
第5行声明了一个unsigned char 类型的字符变量mychar,其值域是0~255。
与其他数值数据类型一样,不能给char类型的变量初始化超出值域的值,否则会出现无法预料的结果。
第11行,将180赋给mychar。
在for语句中,mychar 每次递增1,直至204。
每次递增mychar,第13行 都打印mychar的值和mychar的字符值。
记住,%c用于打印字符值(或ASCII值)。

用%c打印数字的字符值。
初始化字符类型变量时,要用单引号括起来。
初始化字符变量时,不要使用双引号。
不要把扩展的ASCII字符值储存在有符号的char类型变量中。

有些计算机系统可能使用不同的字符集,但是,大部分系统都使用相同的ASCII值(0~127)

三.使用字符串:

char类型的变量只能储存单个字符,用途有限。

字符串是简单的字符序列,应用广泛。人名和地址就要用到字符串。

虽然C语言中没有储存字符串的特殊数据类型,但是可以用字符数组来储存这种类型的信息。

3.1字符数组:

如果要储存一个含有6个字符的字符串,就要声明一个包含7个元素的char类型数组。

声明char类型的数组和声明其他数据类型的数组一样。

例如,下面的声明:

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

声明了一个包含10个元素的char类型数组。该数组可用于储存的字符个数不超过9的字符串。

你可能会质疑:包含10个元素的数组,为何只能储存9个字符?

在C语言中,字符串是以空字符结尾的字符序列。空字符是一个特殊的字符,用\0来表示。

虽然空字符由两个字符组成(反斜杠和零),但仍将其视为单个字符,其ASCII值是0。

空字符是C语言中的一个转义序列。

例如,C程序在储存字符串Alabama时,实际上储存了7个字符:A、1、a、b、a、m、a和一个空字符\0,总共8个字符。因此,字符数组可以储存字符个数比该数组大小少1的字符串。

3.2初始化字符数组:

与C语言的其他数据类型一样,可以在声明字符数组时初始化它。

可以逐个给字符数组的元素赋值,如:

代码语言:javascript
复制
char string[10] = { 'A', '1','a', 'b', 'a', 'm', 'a', '\0' };

然而,用字符串字面量赋值更方便,即用双引号把字符序列括起来:

代码语言:javascript
复制
char string[10] = "Alabama";

在程序中使用字符串字面量时,编译器会在字符串的末尾自动加上表示字符串末尾的空字符。

如果声明数组时未指定下标数,编译器.会自动计算数组大小。

因此,下面的语句将创建并初始化一个包含8个元素的字符数组: 

代码语言:javascript
复制
char string[] = "Alabama";

记住,字符串必须以空字符结尾。

处理字符串的C函数(在第18节中介绍)通过查找空字符来确定字符串的长度。这些函数没有其他方法识别字符串的末尾。如果遗漏了空字符,程序会认为该字符串一直延续到内存中下一个空字符。这类错误通常会导致许多烦人的bug。

四.字符串和指针:

上面介绍了储存在char类型数组中,并以空字符结尾的字符串。

因为已标记了字符串的末尾,所以要定义一个给定的字符串,只需指出该字符串的开始即可。

“意思是,指向字符串?”

的确如此。如果你能这样想,就领会到实质了。第9节介绍过,数组名是指向该数组首元素的指针。

因此,使用数组名便可访问储存在数组中的字符串。

实际上,使用数组名是C语言访问字符串的标准方法。

更准确地说,使用数组名访问字符串是C库函数的访问方式。C标准库包含了大量用于处理字符串的函数(将在第18节中介绍)。

要把字符串传递给这些函数,只需传递数组名即可。用于显示字符串的printf()和puts() 函数也是如此,本次稍后会详述。

你也许注意到前面提到的“储存在数组中的字符串”,这是否意味着有些字符串没有储存在数组中?

的确如此。下一节将解释其中的原因。

五.未储存在数组中的字符串:

前面介绍了通过数组名和空字符来定义一个字符串——数组名是char类型的指针,指向字符串的开始,而空字符则标记了字符串的末尾。其实,我们目前并不关心数组中的字符串具体储存在内存中的何处。实际上,数组的唯一用途就是为字符串提供已分配的空间。

除了声明数组是否还有其他储存字符串方法?

如果指向字符串第1个字符的指针可用来指定该字符串的开始,那么如何分配内存空间?

有两种方法:

第1种方法是,在编译程序时为字符串字面量分配空间;

第2种方法是,在执行程序时使用malloc()函数分配空间,这个过程称为动态分配。

5.1:在编译 期分配字符串的空间

前面提到过,指向char类型变量的指针可用于表示字符串的开始。

回顾一下如何声明这样的指针:

代码语言:javascript
复制
char *message;

以上声明了一个指向char类型变量的指针message。它现在尚未指向任何内容,但是如果改变指针的声明:

代码语言:javascript
复制
char *message = "Great Caesar\'s Ghost!";

当执行该声明时,字符串Great Caesar’s Ghost! (包含末尾的空字符)将被储存在内存中的某处,而且指针message被初始化为指向该字符串的第1个字符。不用关心字符串被储存到何处,编译器会自动处理这些事。一旦定义了message,它就是指向该字符串的指针,可以当作指向字符串的指针来用。

上面的声明与下面的声明等价。*message和message[]是等价的,两者都表示“指向某内容的指针”。

代码语言:javascript
复制
char message[] = "Great Caesar\'s Ghost!";

如果在编写程序时就知道要储存什么字符串,用这种方法分配空间很好。但是更普遍的情况是,在编写程序时并不知道待储存的字符串是什么(即,程序要根据用户的输入或其他未知因素来储存字符串)。在这种情况下,如何分配内存? C语言提供了malloc()函数来按需分配存储空间。

5.2:malloc ()函数

malloc()函数是C语言的一个内存分配函数。

在调用malloc()时,要为其传递所需内存的字节数。

malloc()函数找到并预留所需大小的内存块,并返回内存块第1个字节的地址。

编译器会自动分配合适的内存,我们不用关心在何处找到的内存。

虽然malloc()函数返回地址,但是它的返回类型是void。为何是void ?

因为指向void类型的指针可兼容所有的数据类型。

因为通过malloc()函数分配的内存可储存任意C语言的数据类型,所以用void作为该函数的返回类型非常合适。

语法:malloc()函数

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

void *malloc(size_t size);

malloc()分配size字节的的内存块。

与在程序开始时就立刻为所有的变量分配内存相比,在需要时才通过malloc()分配内存能更高效地使用计算机的内存。

使用malloc()的程序,要包含stdlib.h头文件。一些编译器可以包含其他头文件。然而,为兼容起见,最好包含stdlib.h。

malloc()函数返回一个指针,指向已分配的内存块。如果malloc()无法分配要求的内存数量,将返回NULL。

因此,在分配内存时,即使需要分配的内存数很小,也必须检查其返回值。

示例1:

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

#include <stdio.h>

int main(void)
{
  // 为一个包含100个字符的字符串分配内存
  
  char *str = (char *) malloc(100);;
  
  if (str == NULL)
    
  {
    
    printf("Not enough memory to allocate buffer\n");
    
    exit(1);
    
  }
  
  printf("String was allocated!\n");
  
  return 0;
  
}

示例2:

代码语言:javascript
复制
// 为一个包含50个整数的数组分配内存

int *numbers = (int *) malloc(50 * sizeof(int));

示例3:

代码语言:javascript
复制
// 为一个包含10个浮点值的数组分配内存

float *numbers = (float *) malloc(10 * sizeof(float));
5.3:malloc ()函数的用法

可以使用malloc()分配内存来储存单个char类型的变量。

首先,声明一个指向char类型变量的指针: 

代码语言:javascript
复制
char *ptr;

接下来,调用malloc() 并传递所需的内存块大小。

由于char类型通常只占用1字节,因此需要1字节的内存块。malloc()返回的值被赋给该指针:

代码语言:javascript
复制
ptr = malloc(1);

该语句分配了1字节的内存块,并将其地址赋值给ptr。

与在程序中声明变量不同,这1字节的内存没有名称。只有指针才能引用这个变量。

例如,要将字符'x'储存到此处,可以这样写:

代码语言:javascript
复制
*ptr = 'x';

用malloc()为字符串分配内存和为单个char类型变量分配内存几乎一样。

主要的区别是,要知道待分配的空间数量一字符串中最大的字符数量( 最大值取决于程序的需要)。

假设要为包含99个字符的字符串分配空间,加上末尾的空字符,总共的字符数量是100。

首先,要声明一个指向char类型变量的指针,然后调用malloc() :

代码语言:javascript
复制
char *ptr;

ptr = malloc(100);

现在,ptr指向预留的100字节的内存块,待处理的字符串将储存于此。

在程序中使用ptr,就相当于程序已按声明数组的方式显式分配了空间:

代码语言:javascript
复制
char ptr[100];

malloc()函数可以在需要时才分配存储空间。

当然,可获得的空间没有限制。这取决于计算机中的内存数量和程序的其他存储要求。

如果内存空间不足,malloc() 函数将返回NULL (即,0 )。

程序应该测试malloc()返回值的情况,以便确认要求分配的内存是否成功分配。

必须在程序中测试malloc()的返回值是否等于符号常量NULL,该常量定义在stdlib.h中。

任何使用malloc()函数的程序都必须包含头文件std1ib.h。

提示:

以上示例都假定1个字符占用1字节内存。如果1字符占用的内存大于1字节,那么按照上面示例的写法会擦写内存的其他区域。

另外,为字符分配存储空间时,应该用字面量值乘以数据类型的大小才能得出需要分配的空间数量。例如:

代码语言:javascript
复制
ptr = ma1loc (100);

实际上应声明为:

代码语言:javascript
复制
ptr = malloc( 100 * sizeof (char));

下面程序清单演示了malloc ()的用法。

代码语言:javascript
复制
//使用malloc()为字符串数据分配内存空间的示例


#include <stdio.h>
#include <stdlib.h>

char count, *ptr, *p;

int main(void)
{
  //分配一块35字节的内存。测试是否分配成功。
  //exit() 库函数用于终止程序
  
  ptr = malloc(35 * sizeof(char));
  
  if (ptr == NULL)
  {
    puts("Memory allocation ereor.");
    exit(1);
  }
  
  // 用A~Z对应ASCII码65~90
  //填充字符串
  
  //p是一个指针
  // 用于逐个处理字符串中的字符
  //ptr仍指向字符串的开始
  
  p = ptr;
  
  for (count = 65; count < 91; count++)
    *p++ = count;
  
  // 添加字符串末尾的空字符
  
  *p = '\0';
  
  // 在屏幕上显示字符串
  
  puts(ptr);
  
  free(ptr);
  
  return 0;
}

输出:

解析:

代码语言:javascript
复制
该程序以简单的方式来使用malloc()函数。
虽然程序看上去有点长,其实大部分是注释。
第1、2、11、 12、 22~27、34、 38行都是注释,详细说明了程序的用途。
程序中使用了malloc()函数和put () 函数,因此必须包含第5行的stdlib.h头文件和第4行的stdio.h头文件。
第7行声明了程序中要用到的两个指针变量和一个字符变量。这些变量都没有被初始化,现在还不能使用它们!
第14行调用malloc()函数,其参数是35乘以char类型的大小。是否可以用35?
如果能保证所有运行该程序的计算机都用1字节储存char类型变量,就能这样做。
前面介绍过,相同类型的变量在不同的编译器和系统中占用的内存大小可能不同。使用sizeof运算符可以保证代码的兼容性。
第29行,将ptr指针的值赋给p指针。因此,p和ptr中储存的值相同。
for循环通过p指针将各值放入已分配的内存中。
第31行的for语句中,把65赋给count,每次循环递增1,直至91。
每次循环都要把count的值赋值到p指针指向的地址上。
注意,每次递增count时,p指向的地址也递增1。这意味着每个值都被依次存放在内存中。
也许你还注意到count是char类型的变量,但是赋值给它的是数字。
是否记得ASCII字符和相应的数值等价?
数字65等价于A、数字66等价于B、数字67等价 于C,以此类推。
将字母赋值给指针指向的内存后,循环结束。
第36行,把空字符储存在p指向的最后一个地址上。加上了这个空字符,便能像字符串那样使用这些值。
记住,ptr仍指向第1个值一A。因此,如果将其作为一个字符串,在该指针未指向空字符之前,可以打印出所有的字符。
第40行使用puts()函数证明了这一点。
注意第42行使用的新函数——free() 函数。
如果在程序中动态地分配了内存,使用完毕后就必须将其释放或归还。
free()函数用于释放已分配的内存。系统之前分配了一部分内存,并把地址赋给ptr。
因此,第42行的free函数将这些内存归还系统。

分配的内存不要超过所需。并非每台计算机都有大量的内存,应该节约使用。

赋值给字符数组的字符串包含的字符数不能超过该数组可储存的最大字符数。

例如,在下面的声明中:

代码语言:javascript
复制
char a_ string[] = "NO";

a_string 指向”NO”。如果把"YES ”赋给这个数组,将导致严重的问题。 该数组最初只能储存3个字符一一'N' 、'o’和1个空字符

而"YEs ”有4个字符 Y   E   s  和1个空字符。如果这样做,你完全不知道第4个字符(空字符)会擦写什么内容。

六.显示字符串和字符:

如果在程序中使用了字符串数据,就很可能要在屏幕上显示这些数据。

在C语言中,通常用puts()函数或printf()函数来显示字符串。

6.1:puts()函数

前面的一些程序示例中使用过puts()库函数。

puts()函数因把字符串放在屏幕上而得名。

puts()函数唯一的参数是指向待显示字符串的指针。

由于字符串字面量相当于指向字符串的指针,因此puts()函数除了可以显示指针指向的字符串,还可用于显示字符串字面量。

puts() 函数会在它显示的字符串末尾自动插入换行符,因此用puts()显示的每个字符串都独占一行 。

下面程序清单演示了puts()函数的用法。

输入:

代码语言:javascript
复制
// 用puts()函数显示字符串

#include <stdio.h>

char *message1 = "c";
char *message2 = "is the";
char *message3 = "best";
char *message4 = "programming";
char *message5 = "language!!";

int main(void)
{
  puts(message1);
  puts(message2);
  puts(message3);
  puts(message4);
  puts(message5);
  
  return 0;
}

输出:

解析:

代码语言:javascript
复制
这个程序相当简单。
因为puts()是标准输出函数,所以要包含stdio.h头文件(第3行)。
第5~9行声明并初始化了5个不同的变量,每个变量都是一个字符指针。
第13~17行使用puts() 函数打印每个字符串。
6.2 printf()函数:

printf()库函数也能显示字符串。

printf ()函数使用格式字符串和转换说明来控制输出。要显示字符串,必须使用%s转换说明。

在printf()函数的格式字符串中使用%s时,该函数会将%s与参数列表中相应的参数匹配。

对于字符串,该参数必须是一个指向待显示字符串的指针。

printf() 函数在屏幕上显示字符串,在遇到字符串末尾的空字符时停止

例如:

代码语言:javascript
复制
char *str = "A message to display";
printf ("&s", str);

printf()函数可以显示多个字符串,也可以将文本字面量和数值变量混合输出:

代码语言:javascript
复制
char *bank = "First Federal";

char * name = "John Doe";

int balance = 1000;

printf ("The balance at %s for %s is %d.", bank, name, balance);

输出的结果是:

代码语言:javascript
复制
The balance at First Federal for John Doe is 1000.

就现在而言,要在程序中显示字符串,了解上述内容足矣。

七.读取从键盘输入的字符串:

程序除了要显示字符串,还经常要接受用户通过键盘输入的字符串数据。

C语言库提供了两个函数可以完成这项工作: gets()和scanf()。

然而,在读取用户从键盘输入的字符串之前,必须先分配内存才能储存它们。

可以使用本次前面介绍的两种方法---声明数组或使用malloc()函数。

7.1:用gets()函数输入字符串

get()函数获取从键盘输入的字符串。

调用gets()函数时,它将读取第1个换行符(按下Enter键生成)前用户通过键盘输入的所有字符。

该函数会丢弃换行符,在末尾添加一个空字符,并将字符串返回给调用程序。

get()函数读取的字符串被储存在指针(指向char类型)指定的位置上,该指针是传递给gets()的参数。

使用gets()函数的程序必须包含stdio.h头文件。

下面程序清单演示了puts()函数的用法。

输入:

代码语言:javascript
复制
// 使用gets()库函数的示例

#include <stdio.h>

// 分配一个字符数组储存输入

char input[257];

int main(void)
{
  puts("Enter some text, then press Enter:");
  gets(input);
  printf("You entered: %s\n", input);
  
  return 0;
}

输出:

解析:

代码语言:javascript
复制
本例中,gets() 的参数是input ,它是char类型数组的名称,也是指向数组第1个元素的指针。
第7行声明了一个包含257个元素的数组。
由于大部分计算机屏幕一行最多能容纳256个字符,因此该数组足以储存一整行字符(加上gets()在末尾添加的空字符)。

上面的程序忽略了gets()函数的返回值。gets() 返回一个指向char类型的指针,其值是存放字符串的地址。

该值与传递给gets()函数的值相同,以这种方式返回调用程序能让程序检查输入的一行是否为空行(只按下Enter键)

如下面程序清单所示。

代码语言:javascript
复制
/* getback.c--使用gets()函数的返回值*/

#include <stdio.h>

/*声明一个字符数组储存输入的字符串,声明一个指向char类型的指针*/

char input[257], *ptr;

int main (void)
{
/* 显示输入说明 */

puts ("Enter text a line at a time, then press Enter.");
puts("Enter a blank line when done.");

/*只要未输入空行就执行循环*/

while (*(ptr = gets(input)) != '\0')
printf ("You entered %s\n",input);

puts ("Thank you and good-bye\n");
  
  return 0;
}

分析:

现在来分析一下程序。根据第18行的代码,如果输入一个空行(即,只按下Enter键),该字符串仍被储存,且末尾是空字符。

但是该字符串的长度是0,因此储存在第1个位置上的是空字符。gets()的返回值便指向该位置。因此,如果程序检测到该位置是一个空字符,便知道输入的这行一定是空行。

程序清单通过第18行的while语句执行测试。该语句稍复杂,请按顺序仔细阅读。

下列图解释了该语句的组成。

并非每次都知道gets()将读取多少字符。gets() 会不断储存字符,甚至超出缓冲区末尾,在使用时应特别小心。

1.gets()函数在发现换行符之前,接受从键盘输入的数据。

2.从键盘输入的字符串(丢弃换行符,加上末尾的空字符)将被储存在input指向的内存位置。

3.字符串的地址被返回给ptr指针。

4.赋值表达式的值是赋值运算符左侧变量的值。因此,对整个表达式ptr = gets (input)求值得ptr的值。用圆括号将其括起来,并在前面写上间接运算符(*),可以获得储存在指针指向地址上的值。该值就是用户从键盘输入的第1个字符。

5.如果输入的第1个字符不是空字符,关系运算符则返回true,因此执行while循环。如果第1个字符是空字符(只按下Enter键),关系运算符则返回false,while 循环将终止。

在使用gets()或其他函数通过指针储存数据时,要确保指针指向已分配的空间。很容易犯这样的错误:

代码语言:javascript
复制
char *ptr;
gets(ptr);

上面的代码已声明了ptr指针,但并未初始化它,无法知道它指向何处。gets()函数不知道ptr未初始化指向某处,因此它将输入的字符串从ptr指向的位置开始储存。该字符串可能会擦写一些重要的数据,如程序或操作系统的代码。大部分编译器都无法捕捉这类错误,因此你你须提高警惕

语法:gets()函数

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

char *gets(char *str);

gets()获取从标准输入设备(通常是键盘)输入的字符串str。该字符串由换行符前面的所有字符组成,加上末尾的空字符。

gets()函数返回一个指针,指向已读取的字符串。如果读取字符串时出错,gets() 函数将返回null 。

示例:

代码语言:javascript
复制
// gets()示例

# include <stdio.h>

char line[256];

int main(void)
  
{
  printf("Enter a string:\n");
  
  gets(line);
  printf("\nYou entered the following string:\n");
  
  printf("%s\n", line);
}
7.2用scanf() 函数输入字符串

scanf()库函数接受用户从键盘输入的数值数据,该函数也能用于输入字符串。

scanf() 函数中的格式字符串告诉该函数如何读取用户输入的信息。

要读取字符串,必须在scanf()的格式字符串中使用%s转换说明。

与gets()类似,要给scanf ()传递一个指向字符串存储位置的指针。

scanf()如何确定字符串的开始和结束位置?

开始位置很好确定,就是它读取第1个非空白字符的位置。

结束位置分两种情况:在格式字符串中,如果使用%s,scanf()会在遇到空白字符(如空格、制表符、换行符)处停止(不包括空白字符) ;

如果使用%ns (n是一个整型常量,指定字段的长度),scanf()会读取n个字符或遇到新的空白字符处停止。

可以在scanf()中使用多个%s读取多个字符串,scanf() 根据结束位置的规则,在输入中查找每个%s对应的字符串,

例如:

代码语言:javascript
复制
scanf ("%s&s8s",s1, s2, s3);

假设为响应这条语句,输入January February March,那么January将被赋给s1、February将被赋给s2、March 将被赋给s3。

使用字段长度说明符会怎样?

如果执行下面的语句:

代码语言:javascript
复制
scanf ("%3s%3s%3s", s1, s2, s3);

假设为响应这条语句,输入September,那么Sep将被赋给s1tem将被赋给s2、ber将被赋给s3。

如果输入的字符串长度小于scanf()函数指定的长度会出现什么情况?

scanf()会等待用户输入剩下的字符串,在scanf()读取完字符串之前程序不会继续运行。

例如,为响应下面的语句:

代码语言:javascript
复制
scanf ("&siss", s1, s2, s3);

输入January February ,那么程序将等待用户输入scanf()格式字符串中指定的第3个字符串。如果输入的字符串长度大于指定的长度,则剩余未匹配的字符串(仍留在键盘缓冲区内未被处理)会被后续的scanf()函数或输入语句读取。

例如,为响应下面的语句:

代码语言:javascript
复制
scanf ("%s%s", s1, s2);
scanf ("%s", s3);

输入January February March ,结果是:调用第1个scanf()时,January被赋给sl、February 被赋给s2 ;调用第2个scanf()时,March会将自动赋给s3。

scanf()函数有一个返回值(整型),返回成功输入的字符数。该返回值经常被省略。如果只读取文本,gets()函数通常比scanf()函数更好用。scanf ()函数通常用于读取文本和数值混合的数据。

下面程序清单解释了这一点。

如果用scanf()输入数值变量,必须在变量名前加上取址运算符(& )。

代码语言:javascript
复制
// 用scanf()函数输入数值和文本数据

#include <stdio.h>

char lname[257], fname[257];
int count, id_num;

int main(void)
{
  // 提示用户输入
  
  puts("Enter last name, first name, ID number separated");
  puts("by spaces, the press Enter.");
  
  //输入3个数据项
  
  count = scanf("%s%s%d", lname, fname, &id_num);
  
  //显示数据
  
  printf("%d items entered: %s %s %d \n", count, fname, lname, id_num);
  
  return 0;
}

输出

解析:

代码语言:javascript
复制
scanf()要求传递给它的参数是变量的地址。
程序清单中,lname和fname都是指针(指针中储存的是地址),因此无需在前面添加取址运算符(&);而id__num是普通的变量名,因此需要在它前面加上& (第17行)。
提示:
该程序演示了scanf()函数的一个使用限制。
假设你要输入的名是Mary Ellen (国外的名可能有多个部分),怎么办?
由于两个单词之间有空格,虽然“Mary Ellen” 是一个完整的字符串,但scanf()函数只会把Mary存入fname变量中。
因此,还需要创建两个变量储存名中的两个部分,或者要求用户在输入时不要添加空格。
正因如此,gets()函数在读取用户输入的字符串方面比scanf()更方便,特别是字符串中包含空格的情况。
一些程序员认为用scanf() 读取输入的数据很容易出错。
他们更喜欢用gets()来读取所有的数据(数值数据和字符串),然后在程序中把数字分离出来,并将其转换为数值变量。
这些技术超出了本次讲解的范围,但是不错的编程练习。
要完成这些任务,需要用之后18节介绍的用于操控字符串的函数。

八.小结:

本次涵盖了C语言的char数据类型。

char类型变量的用途之一是储存单个字符。字符还通常以数字形式储存: ASCII码将数值码赋给每个字符。

因此,也可以使用char类型(signed char和unsigned char )储存数值较小的整数。

字符串是以空字符结尾的字符序列。

字符串可用于储存文本数据。

C语言将字符串储存在char类型的数组中。要创建一个包含n+1和元素的char类型数组,才能储存一个长度为n的字符串。

使用内存分配函数(如,malloc() )可以在程序中动态地分配内存。

用malloc()函数分配的内存数量正好是程序需要的数量。如果估计过高,就会分配多余的内存。

没有这些函数,你不得不猜测程序需要多少内存。在使用完分配的内存后,要用free()函数将其返回给系统。

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.char数据类型:
  • 二.使用字 符变量:
  • 三.使用字符串:
    • 3.1字符数组:
      • 3.2初始化字符数组:
      • 四.字符串和指针:
      • 五.未储存在数组中的字符串:
        • 5.1:在编译 期分配字符串的空间
          • 5.2:malloc ()函数
            • 5.3:malloc ()函数的用法
            • 六.显示字符串和字符:
              • 6.1:puts()函数
                • 6.2 printf()函数:
                • 七.读取从键盘输入的字符串:
                  • 7.1:用gets()函数输入字符串
                    • 7.2用scanf() 函数输入字符串
                    • 八.小结:
                    相关产品与服务
                    机器翻译
                    机器翻译(Tencent Machine Translation,TMT)结合了神经机器翻译和统计机器翻译的优点,从大规模双语语料库自动学习翻译知识,实现从源语言文本到目标语言文本的自动翻译,目前可支持十余种语言的互译。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档