字符串在程序中很常见,和整数、小数、字符其他数据类型一样,是代码中必不可少的一部分。可是字符串却又和其他类型不完全一样,还有自己的个性。

  下面直接通过一段代码来看。


定义了一个字符1.一个字符串1,然后将他们打印出来,打印结果如下:

从打印的结果来看,二者并没有差别。

下面接着打印一下这两个的长度,使用sizeof()函数,分别计算s1和s2的长度并打印出来。


可以看到字符s1的长度是1,字符串s2的长度是2, 在内存中查看s1和s2的存储地址

从内存存储位置可以看出字符s1占了一个字节,字符串s2占了两个字节,后面的一个字节是空的。所以通过sizeof()函数计算出来s2所占空间的大小是2。

在这里要顺便说一下计算长度的函数sizeof()strlen(),这两个都可以计算字符串的长度,但是 sizeof() 函数计算出来的是实际占据空间的大小,而strlen()计算出来的是有效字符的长度。所以对于字符串而言sizeof()函数计算的结果会比strlen()计算出来的结果大1。

比如这里定义一个字符串“abc”,然后分别使用这两个函数计算它的长度。

char s2[]="123";
printf( " %d   %d\r\n\r\n\r\n", sizeof(s2),strlen(s2));

从打印的结果可以看出,字符串有效长度是3,但是字符串所占空间大小是4。

接下来看看对字符的操作和字符串的操作是否一样。

对字符s1和字符串重新赋值,此时编译器报错,不允许直接字符串s2赋值,这是由于字符串在内存中是按照字符数组来存储的,也就是存储在一系列连续的存储空间内,每一个字符占一个字节。所以不能对字符串整体进行操作,要改变字符串的值,只能像修改数组的值一样,每一位单独操作。

所以这里要改变字符串中存储的字符,就直接给数组的第0位赋值。

可以看到对s1和s2的第0位重新赋值后,内存中存储的数据也发生了变化,和打印出来的数据一样。

注意内存中存储的字符是以ASCII码的方式存储的,而串口打印出来的直接就是字符。ASCII码 0x31 对应的字符就是1,ASCII码 0x32 对应的字符就是2。

同样将一个字符赋值给另一个字符时可以正常赋值,但是不能将一个字符串直接赋值给另一个字符串。

要将字符串赋值给另一个字符串时,也需要向数组一样,一位一位的赋值。


打印结果如下

在内存中查看

内存中的结果和打印的结果一致。接下来在看一个例子,将s1和s2传递到其他函数中进行操作。

char s1='1';
char s2[]="1";void change1(char s3)
{s3 = s3 + 1;  printf( "s3 -> %c \r\n", s3 );
}
void change2(char s4[])
{s4[0] = s4[0] + 1;printf( "s4 -> %s \r\n", s4 );
}void main( void )
{//省略无关代码 while( 1 ){     change1(s1);change2(s2);printf( "s1 -> %c s2 -> %s\r\n\r\n\r\n", s1,s2 );   delay_ms( 5000 );}
}

在将s1和s2的值传递到外部函数之后,在外部函数里面对字符加1,然后打印出来,从外部函数退出之后,接着打印s1和s2的值。

打印结果如下

s1的值是字符1,然后将s1传递给s3,然后s3加1之后,打印出字符2,符合代码逻辑。

s2的值是字符串1,然后将s2传递给s4,然后s4加1之后,打印出字符2,符合代码逻辑。

接下来从子函数退出后,分别打印s1和s2的值,可以发现s1的值依然是1,但是s2的值却变成的2。

如果程序一直执行的话,会发现s1和s3的值一直没有变,但是s2和s4的值却一直在增大。

这是什么原因呢?字符串传递给子函数后,字符串本身也会被子函数改变?

为了一探究竟,下面开始单步调试,同时查看内存中数据的变化情况。


当代码执行到 s3 = s3 + 1;这一行时,系统中s3的存储位置为A,数值为字符’1’,此时s1的存储位置为0x00000C。下面对s3执行加1操作。

执行完加1操作之后,s3的值变成了字符’2’,此时s1的值依然是字符’1’,未发生变化。

接下来执行第二个函数,对字符串s4进行操作。

可以看出当执行到 s4[0] = s4[0] + 1; 这一行时,此时s4在内存中的地址是0x00000D,而s2的内存地址也是0x00000D,难道s4和s2是一个地址吗?继续执行程序观察。

当对s4中第0位的字符执行完加1操作之后,s4中的字符变成了’2’,而此时s2中的字符值也变成了’2’,说明s4和s2在内存中的确是同一个地址。

两个函数执行完成之后,继续打印s1和s2的值,由于在子函数执行的时候,s1的地址上值未发生改变,s3的值是s1的值加1,s2和s4指向的是同一个地址,s4每次循环都要加1,所以s2的值每次也会加1。

为什么对于字符没有发生变化,而字符串发生了变化?这是因为在C语言中字符串属于引用类型,而字符属于值类型?

值类型包括:byte,short,int,long,float,double,decimal,char,bool 和 struct。

引用类型包括:string 和 class。

  系统对于值类型操作时,如果将一个值类型赋值给另一个值类型,那么系统就会重新开辟一个空间,然后将值复制一份,然后再将值存入新开辟的空间中。这样当操作新数据的时候,不会影响以前的数据,因为两个值都在自己的存储空间中。

  系统对于引用类型操作时,如果将一个引用类型赋值给另一个引用类型,系统检测到这两个值如果全完一样的话,那么系统就不会重新开辟空间给新的引用类型,而是直接让新的引用类型地址指向旧的引用类型,让这两个值公用同一个内存空间,也就是相当于给一个地址空间起了两个名字,这样改变任意一个值时,地址空间内的值也会发生变化。

  所以在使用字符串的时候,一定要注意这一点,这是它和其他类型值的最大区别。
如果不加小心,在传递值的过程中,数据很容易出错。

C语言小知识---特殊的字符串相关推荐

  1. 纸上得来终觉浅(c语言小知识总结)

    纸上得来终觉浅(c语言小知识总结) 1.数组的初始定义 对于一个初始定义的数组,内部的值是随机的,若用{}(哪怕其中没有元素)也会让数组内元素初始化,默认为0. 若是用循环语句进行赋值,在一个长度为2 ...

  2. C语言基础知识-数组和字符串

    C语言基础知识-数组和字符串 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.数组概述 在程序设计中,为了方便处理数据把具有相同类型的若干变量按有序形式组织起来的方式我们称为数组 ...

  3. eem二级c语言题库哪种比较好,c语言小知识,供初学者参考

    1 用预处理指令 define 声明一个常数 用以表明 1 年中有多少秒 忽略闰年问题 define SECONDS PER YEAR 60 60 24 365 UL 2 写一个 标准 宏 MIN 这 ...

  4. Python每日小知识(2):字符串和编码

    了解:ASCII编码(是1个字节)仍然可以完美滴处理数字,因为最早的时候只有127个字符编入计算机,但是遇到处理中文1个字节就有点捉襟见肘了,这时候我们就脑壳疼了,所以中国制定了GB2312编码,用来 ...

  5. C语言小知识---递归函数的使用

      C语言允许函数自身调用自身,这种调用就被称为递归.好多人刚开始学习递归的时候,往往被一层层嵌套调用搞糊涂了,搞不清楚到底是怎么调用的?现在就通过一个小例子来演示一下,递归调用时,函数是如何运行的. ...

  6. C语言小知识---printf()函数

      说起printf()函数,写代码的同学肯定都很熟悉,这是C语言中标准的打印函数,在调试代码或者信息输出的时候会经常用到. 其中printf函数的转换说明如下: 转换说明修饰符 printf()中的 ...

  7. C语言小知识:typedef\函数模板\

    (1)typedef用法: typedef为C语言的关键字,作用是为一种数据类型定义一个新名字.这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等).在编程中使用t ...

  8. C语言小知识---为什么要使用指针

      刚开始学习C语言的时候,感觉最难理解的就是指针,什么指针变量,变量指针,指向指针的变量,指向变量的指针?一堆概念,搞得人云里雾里的,今天不讨论这些概念的问题,从最底层来分析C语言中为什么要使用指针 ...

  9. C语言小知识---奇葩的小数

      看到这个标题,好多人可能会想,小数有什么奇葩的,这不和整数一样,加减乘除计算起来也没啥区别呀?奇葩在哪里?   下面通过一个简单的例子来看一看,定义一个小数一个整数,然后打印出来. 核心代码其实只 ...

最新文章

  1. 【转载】推荐5款超实用的.NET性能分析工具
  2. 自定义注解完成数据库切库
  3. Java中常用的加密算法MD5,SHA,RSA
  4. 如何下载和安装SQL Server数据库实验助手(DEA)
  5. 第三讲:tapestry增删改查---查询数据
  6. matlab2c使用c++实现matlab函数系列教程-mean函数
  7. idea导入导出 settings 设置文件
  8. exchange 2010部署之一
  9. python如何循环sql语句_sql语句的for循环语句怎么写
  10. 该弱磁算法采用单电流控制策略,额定转速以下采用MTPA控制,额定转速以上采用单电流控制
  11. 重要知识:身份证复印件的正确使用方法
  12. 实现BIM的Revit软件学习资料
  13. 多元函数的泰勒展开(Taylor series expansion)
  14. win10可以上网,但显示小地球的情况(未连接到网络)
  15. 高德地图 hello world
  16. ZYNQ芯片AXI 协议和PL和PS接口互联
  17. C#,图像二值化(18)——全局阈值的模糊集理论算法(Huang Thresholding)与源程序
  18. K2“拍了拍”你,这里有你想要的医药行业整体解决方案_K2 BPM
  19. 汉诺塔求次数(用递归)
  20. Fastreid 代码

热门文章

  1. 【Eclipse】eclipse中设置tomcat启动时候的JVM参数
  2. 01-python进阶-拾遗
  3. GDI+ 中发生一般性错误(在 OutputStream 中保存 PNG 格式图像时遇到的问题)
  4. 【Java】使用springboot运行程序时出现的错误
  5. 【Hadoop】MapReduce的配置 ---配置历史服务器
  6. 传输层协议的UDP和TCP
  7. java时间戳格式_Java时间戳转化为今天、昨天、明天(字符串格式)
  8. centos mysql php tomcat_CentOS 6.x使用yum快速安装Apache+PHP+Tomcat(JSP)+MySQL
  9. epoll原理_Epoll源码阅读手札
  10. 计算机python指什么_Python是什么?