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

C语言中字符串的处理方式

http://www.cnblogs.com/robin-ty/archive/2010/09/03/1817294.html

 

交流纽带”

                              --《C语言程序设计 现代方法》

 

  写多了 Java 代码,对 String 类 很是喜爱,可惜经典的 C 语言没有。。。最近在做程序过程中,发现对C语言字符串的处理很模糊,一会儿用数组,一会儿用指针,一会儿又引入 string.h。。。于是决定总结一下C语言中字符串的处理,一则作为笔记,二则作为技术交流和大家分享。

    1. 字符串字面量(字符串常量,在C标准中称为,字符串字面量)
      如何存储字符串字面量
        从本质上而言,C语言把字符串字面量作为字符数组来处理。当C语言编译器在程序中遇到长度为n的字符串字面量时,它会为字符串字面量分配长度为n+1的内存空间,在末尾增加一个额外的字符——空字符(\0)。
      字符串字面量的操作
        通常情况下可以在任何C语言允许使用 char * 指针的地方使用字符串字面量。如:
      char * p; p = " abc " ;
      这个赋值操作不是复制 "abc" 中的字符,而仅仅是使 p 指向字符串的第一个字符。
    2. 字符串变量   一些编程语言为声明字符串提供了特殊的 string 类型。C语言采取了不同的方式:只要保证字符串是以空字符串结尾的,任何一维的字符数组都可以用来存储字符串。如果编写自己的字符串处理函数,请千万注意要正确地处理空字符。   假设需要变量用来存储最多80个字符的字符串。既然字符串会在末尾处需要空字符,那么要声明的变量是含有81个字符的数组。
      #define STR_LEN 80
      /* 惯用法 */ char str[STR_LEN + 1 ];
      对宏加一的这种方法是C程序员常用的方式。
      初始化字符串变量
      char date1[ 8 ] = " June 14 " ;
      date1: | J | u | n | e |   | 1 | 4 | \0 |
      char date2[ 9 ] = " June 14 " ;
      date2: | J | u | n | e |   | 1 | 4 | \0 | \0 | 大体上来说,这种行为与C语言处理数组初始化的方法一致。 字符串变量的声明可以忽略它的长度。这种情况下,编译器会自动计算长度:
      char date3[] = " June 14 " ;
      编译器为date3分配8个字符的空间。 字符数组与字符指针 一起来比较一下下面两个声明:
      char date[] = " June 14 " ;
      它声明date是个字符数组。和这个声明相似的是下面这个声明:
      char * date = " June 14 " ;
      它声明date是个指向字符串字面量的指针。 [注意],不能错误地认为上面两种date可以互换。两者之间有着显著的差异: (1) 在声明为数组时,就像任意数组元素一样,可以修改存储在date中的字符。在声明为指针时,date指向字符串字面量。(2) 在声明为数组时,date是数组名。在声明为指针时,date是变量,这个变量可以在程序执行期间指向其他字符串。   如果需要可以修改的字符串,那么就要建立字符数组来存储字符串。这时声明指针变量是不够的。下面的声明使编译器为指针变量分配了足够的内存空间:
      char * p;
      可惜的是,它不为字符串分配空间。在使用p作为字符串之前,必须把p指向字符串数组。一种可能是把p指向已经存在的字符串变量:
      char str[STR_LEN + 1 ], * p; p = str;
      现在p指向了str的第一个字符,所以可以把p作为字符串使用了。

 

3. 字符串的读写

 

  3.1 用 printf 函数和 puts 函数写字符串

  %s 允许 printf 函数写字符串。如:

char str[] = " Are we having fun yet? " ; printf( " Value of str: %s\n " , str);

如果只显示字符串的一部分,可以用 %.ps。这里的 p 是要显示的字符数量。语句

printf( " %.6s\n " , str);

会显示出

Are we

  C函数库还提供puts函数。

puts(str);

  

  3.2 用 scanf 函数和 gets 函数读字符串

  在 scanf 函数调用中,不需要在 str 前添加运算符 &。因为 str 是数组名,编译器会自动把它当作指针来处理。调用时,scanf 函数会跳过空白字符,然后读入字符,并且把读入的字符存储到 str 中,知道遇到空白字符为止。scanf 函数始终会在字符串末尾存储一个空字符。用 scanf 函数读入字符串永远不会包含空白字符。因此,scanf 函数通常不会读入一整行输入。换行符会使 scanf 函数停止读入,空格符或制表符也会产生同样的效果。可以参考下面的例子:

复制代码
#include < stdio.h >
#define STR_LEN 80
int main() { char str[STR_LEN + 1 ]; printf( " input a string: " ); scanf( " %s " , str); printf( " String inputed is:%s\n " , str); return 0 ; }
复制代码

 

运行结果如下:

Input a string : this is a string String is : this

为了每次读入一整行输入,可以使用 gets 函数。类似于 scanf 函数,gets 函数把读入的字符放到数组中,然后存储一个空字符。然而,在其他方面 gets 函数有些不同于 scanf 函数:

 

  (1) gets 函数不会在开始读字符串之前跳过空白字符( scanf 函数会跳过)。

  (2) gets 函数会持续读入直到找到换行符才停止(scanf 函数会在任意空白字符处停止)。

  此外,gets 函数会忽略掉换行符,而不会把它存储到数组中,用空字符代替换行符。

 

  3.3 逐个字符读字符串

  因为 scanf 函数和 gets 函数都有风险且不够灵活,C 程序员经常会编写自己的输入函数。通过每次一个字符的方式来读入字符串。下面是自己编写的读取字符串的函数 read_line():

复制代码
int read_line( char strp[], int n) { char ch; int i = 0 ;
while ((ch = getchar()) != ' \n ' ) if (i < n) str[i ++ ] = ch; str[i] = ' \0 ' ; /* terminates string */ return i; /* number of characters stored */ }
复制代码

返回之前,read_line 函数在字符串的末尾放置了一个空字符。就像 scanf 函数和 gets 函数一样,标准函数会自动在输入字符串的末尾放置一个空字符串。然而,如果自己写输入函数,必须要考虑到这一点。

相关文章:

  • 第六章 MVC之 FileResult和JS请求二进制流文件
  • AutoMapper在MVC中的运用04-string映射各种类型、一个属性映射多个属性等
  • linux 上做mysql备份数据的还原
  • ArcGIS帮助文档VS帮助文档不能复制图片的解决方法
  • 聊聊directory traversal attack
  • 如何使用C#关键字const,readonly,static
  • 零元学Expression Blend 4 - Chapter 10 用实例了解布局容器系列-「StackPanel」
  • 使用VS2013分析DMP文件
  • jsp 引用css/js文件返回html网页问题
  • 用户管理 之 Linux 用户管理工具介绍
  • 妙用this关键字
  • 南宁seo教程:巧用页面更新机制保障快照更新
  • JVM原理讲解和调优
  • Microsoft's Office - ATC Shanghai
  • memcached与redis区别
  • 时间复杂度分析经典问题——最大子序列和
  • android图片蒙层
  • JavaScript异步流程控制的前世今生
  • JS基础篇--通过JS生成由字母与数字组合的随机字符串
  • Python利用正则抓取网页内容保存到本地
  • vue-router 实现分析
  • windows下使用nginx调试简介
  • 前端
  • 如何学习JavaEE,项目又该如何做?
  • 一加3T解锁OEM、刷入TWRP、第三方ROM以及ROOT
  • #1014 : Trie树
  • (02)vite环境变量配置
  • (3)Dubbo启动时qos-server can not bind localhost22222错误解决
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (Repost) Getting Genode with TrustZone on the i.MX
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (附源码)ssm高校社团管理系统 毕业设计 234162
  • (三维重建学习)已有位姿放入colmap和3D Gaussian Splatting训练
  • (深度全面解析)ChatGPT的重大更新给创业者带来了哪些红利机会
  • (转) RFS+AutoItLibrary测试web对话框
  • (最简单,详细,直接上手)uniapp/vue中英文多语言切换
  • .apk 成为历史!
  • .java 指数平滑_转载:二次指数平滑法求预测值的Java代码
  • .Net 4.0并行库实用性演练
  • .NET Standard 支持的 .NET Framework 和 .NET Core
  • .Net的C#语言取月份数值对应的MonthName值
  • .Net各种迷惑命名解释
  • .NET建议使用的大小写命名原则
  • @Bean注解详解
  • @EnableConfigurationProperties注解使用
  • [ C++ ] STL---仿函数与priority_queue
  • [3300万人的聊天室] 作为产品的上游公司该如何?
  • [Android]Android P(9) WIFI学习笔记 - 扫描 (1)
  • [ANT] 项目中应用ANT
  • [Arduino学习] ESP8266读取DHT11数字温湿度传感器数据
  • [C#]winform部署yolov5-onnx模型
  • [codeforces]Levko and Permutation
  • [docker] Docker的私有仓库部署——Harbor
  • [leetcode]Flatten Binary Tree to Linked List