爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      第八节(字符和字符串)

      首页 知识中心 数据库 文章详情页

      第八节(字符和字符串)

      2023-07-17 07:45:43 阅读次数:424

      C,字符串,数组

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

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

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

      ●如何用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 类型变量之前必须先声明,可以在声明变量的同时初始化它。下面是一些范例:

      char a, b, c;      /*声明3个未初始化的char类型变量 */
      
      char code = 'x';  /*声明一个char类型的变量code,并为其储存x字符*/
      
      code = '!';        /*在变量code中储存!字符*/

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

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

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

      #define EX 'x'
      
      char code = EX;   /*将code设置为'x' */
      
      const char A = 'Z';

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

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

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

      输入:

      // 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;
      }

      输出:

      第八节(字符和字符串)

      解析:

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

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

      输入:

      // 打印扩展的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;
      }

      输出:

      第八节(字符和字符串)

      解析:

      该程序清单中
      第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类型的数组和声明其他数据类型的数组一样。

      例如,下面的声明:

      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语言的其他数据类型一样,可以在声明字符数组时初始化它。

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

      char string[10] = { 'A', '1','a', 'b', 'a', 'm', 'a', '\0' };

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

      char string[10] = "Alabama";

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

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

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

      char string[] = "Alabama";

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

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

      四.字符串和指针:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      有两种方法:

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

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

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

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

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

      char *message;

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

      char *message = "Great Caesar\'s Ghost!";

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

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

      char message[] = "Great Caesar\'s Ghost!";

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

      5.2:malloc ()函数

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

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

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

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

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

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

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

      语法:malloc()函数

      #include <stdlib.h>
      
      void *malloc(size_t size);

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

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

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

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

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

      示例1:

      #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:

      // 为一个包含50个整数的数组分配内存
      
      int *numbers = (int *) malloc(50 * sizeof(int));

      示例3:

      // 为一个包含10个浮点值的数组分配内存
      
      float *numbers = (float *) malloc(10 * sizeof(float));

      5.3:malloc ()函数的用法

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

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

      char *ptr;

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

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

      ptr = malloc(1);

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

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

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

      *ptr = 'x';

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

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

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

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

      char *ptr;
      
      ptr = malloc(100);

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

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

      char ptr[100];

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

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

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

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

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

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

      提示:

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

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

      ptr = ma1loc (100);

      实际上应声明为:

      ptr = malloc( 100 * sizeof (char));

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

      //使用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;
      }

      输出:

      第八节(字符和字符串)

      解析:

      该程序以简单的方式来使用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函数将这些内存归还系统。

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

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

      例如,在下面的声明中:

      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()函数的用法。

      输入:

      // 用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;
      }

      输出:

      第八节(字符和字符串)

      解析:

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

      6.2 printf()函数:

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

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

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

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

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

      例如:

      char *str = "A message to display";
      printf ("&s", str);

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

      char *bank = "First Federal";
      
      char * name = "John Doe";
      
      int balance = 1000;
      
      printf ("The balance at %s for %s is %d.", bank, name, balance);

      输出的结果是:

      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()函数的用法。

      输入:

      // 使用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;
      }

      输出:

      第八节(字符和字符串)

      解析:

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

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

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

      如下面程序清单所示。

      /* 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()或其他函数通过指针储存数据时,要确保指针指向已分配的空间。很容易犯这样的错误:

      char *ptr;
      gets(ptr);

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

      语法:gets()函数

      #include <stdio.h>
      
      char *gets(char *str);

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

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

      示例:

      // 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对应的字符串,

      例如:

      scanf ("%s&s8s",s1, s2, s3);

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

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

      如果执行下面的语句:

      scanf ("%3s%3s%3s", s1, s2, s3);

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

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

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

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

      scanf ("&siss", s1, s2, s3);

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

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

      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()输入数值变量,必须在变量名前加上取址运算符(& )。

      // 用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;
      }

      输出

      第八节(字符和字符串)

      解析:

      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()函数将其返回给系统。

      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://blog.51cto.com/lyx888/6244896,作者:冷影玺,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:Mysql启动失败,报Can‘t start server: can‘t create PID file: No such file or directory解决方案

      下一篇:JDBC getColumnLabel和getColumnName区别及自动解析查询字段

      相关文章

      2025-05-19 09:04:14

      C语言字符函数和字符串函数--(超全超详细)

      C语言字符函数和字符串函数--(超全超详细)

      2025-05-19 09:04:14
      函数 , 字符 , 字符串
      2025-05-19 09:04:14

      复杂度的OJ练习

      复杂度的OJ练习

      2025-05-19 09:04:14
      代码 , 复杂度 , 思路 , 数组 , 算法
      2025-05-16 09:15:24

      如何将一串数字用函数的方法倒过来(C语言)

      如何将一串数字用函数的方法倒过来(C语言)

      2025-05-16 09:15:24
      函数 , 数字 , 数组
      2025-05-16 09:15:24

      jQuery遍历对象、数组、集合

      jQuery遍历对象、数组、集合

      2025-05-16 09:15:24
      jQuery , 对象 , 数组 , 遍历 , 集合
      2025-05-16 09:15:17

      递归,搜索,回溯算法(3)之穷举,暴搜,深搜,回溯,剪枝

      递归,搜索,回溯算法(3)之穷举,暴搜,深搜,回溯,剪枝

      2025-05-16 09:15:17
      回溯 , 子集 , 数组 , 算法 , 递归
      2025-05-14 10:33:31

      计算机小白的成长历程——习题演练(函数篇)

      计算机小白的成长历程——习题演练(函数篇)

      2025-05-14 10:33:31
      函数 , 字符串 , 数组 , 知识点 , 编写 , 迭代 , 递归
      2025-05-14 10:33:31

      计算机小白的成长历程——数组(1)

      计算机小白的成长历程——数组(1)

      2025-05-14 10:33:31
      strlen , 个数 , 元素 , 内存 , 十六进制 , 地址 , 数组
      2025-05-14 10:33:16

      30天拿下Rust之字符串

      在Rust中,字符串是一种非常重要的数据类型,用于处理文本数据。Rust的字符串是以UTF-8编码的字节序列,主要有两种类型:&str和String。其中,&str是一个对字符数据的不可变引用,更像是对现有字符串数据的“视图”,而String则是一个独立、可变更的字符串实体。

      2025-05-14 10:33:16
      amp , Rust , str , String , 使用 , 字符串 , 方法
      2025-05-14 10:33:16

      30天拿下Rust之切片

      在Rust中,切片是一种非常重要的引用类型。它允许你安全地引用一段连续内存中的数据,而不需要拥有这些数据的所有权。切片不包含分配的内存空间,它仅仅是一个指向数据开始位置和长度的数据结构。

      2025-05-14 10:33:16
      amp , end , 切片 , 字符串 , 引用 , 索引 , 迭代
      2025-05-14 10:33:16

      30天拿下Python之使用Json

      Json的英文全称为JavaScript Object Notation,中文为JavaScript对象表示法,是一种存储和交换文本信息的语法,类似XML。Json作为轻量级的文本数据交换格式,比XML更小、更快,更易解析,也更易于阅读和编写。

      2025-05-14 10:33:16
      json , Json , Python , 字符串 , 对象 , 序列化 , 转换
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5255580

      查看更多

      最新文章

      30天拿下Rust之切片

      2025-05-14 10:33:16

      30天拿下Rust之字符串

      2025-05-14 10:33:16

      java String 去掉特殊字符之前的内容

      2025-05-14 09:51:15

      java中判断String类型为空和null的方法

      2025-05-13 09:53:23

      java实现3. 无重复字符的最长子串

      2025-05-13 09:50:17

      java实现-13. 罗马数字转整数

      2025-05-13 09:50:17

      查看更多

      热门文章

      groovy replace字符串替换

      2023-03-24 10:30:38

      c++primer plus 6 读书笔记 第五章 循环和关系表达式

      2023-02-13 07:38:09

      oracle字符串处理函数(部分)

      2022-12-29 09:29:46

      python学习——【第一弹】

      2023-02-28 07:38:41

      python字符串str与byte字节相等==判断

      2023-04-11 10:46:53

      切片用法——去空格

      2024-07-01 01:30:59

      查看更多

      热门标签

      数据库 mysql 字符串 数据结构 MySQL 算法 redis oracle java sql python 数据 索引 SQL 查询
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      考研数据结构之栈(2.1)——顺序栈的操作(C表示)

      给定两个字符串s1和s2,问s2最少删除多少字符可以成为s1的子串? 比如 s1 = “abcde“,s2 = “axbc“。

      stringstream 字符串的格式化数据提取

      python字符串和列表的不同

      python如何去掉readlines和readline中的换行符和字符串前面b

      1371. Find the Longest Substring Containing Vowels in Even Counts

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号