图片中隐藏字符串c语言实现,消失的字符串——c语言函数中的数据存储方式以及字符串实现...

事情是这样的,最近在学习翁老师的Mooc之C语言程序设计,插一句,真的是好老师,讲的真的太好了,在c里的字符串这里,翁老师演示了一个小程序,大概代码如下,无非就是想给我们说明c语言的scanf读入字符串是遇到空格、Tab和回车为止,并且会在结尾自动加上表示字符串结束的‘\0’,然后想给我们演示如果出现字符数组越界会怎样?!就出现了如下的示例:

#include 

int main()

{

char word[8];

char word2[8];

scanf("%s",word);

scanf("%s",word2);

printf("%s##%s\n",word,word2);

return 0;

}

4c577876e89b4a7f42fefa0cd5228f79.png

如上就是程序运行结果,有没有觉得很神奇,反正当时我是震惊了,WoW,太不可思议了,这究竟发生了什么,老师也留下了这个疑问给我们,留下我们苦苦思索,但是百思不得其解,天哪,还好老师给了一个小提示,这和c语言中的数据在计算机中的存放方式有关。

于是我开始思考,我仿照翁老师的做法,反正c语言提供了这样的工具——指针,我们就输出地址来看看,我也是知道的,函数在计算机中是通过堆栈的方式来实现的,数据就是通过堆栈来保存,堆栈是很重要的数据结构,其有一个很重要的特性,FILO,后进先出。我增加了输出字符数组每个元素的地址的代码,如下:

#include 

int main()

{

char word[8];

char word2[8];

scanf("%s",word);

scanf("%s",word2);

printf("%s##%s\n",word,word2);

printf("%p\n",word);

printf("%p\n",word2);

printf("\n");

int i;

for(i=0;i<8;i++){

printf("%p\n",&word[i]);

}

printf("\n");

for(i=0;i<8;i++){

printf("%p\n",&word2[i]);

}

return 0;

}

72d850c2a5f0baffed01e0031ad0cdb5.png

看到了输出地地址后,加上草图,一切都简单明了了,总结如下:

在32位的架构下(我是在32位下编译的,其实在64位下没有出现这个情况,那是因为64位下存储字大小又不同了,其实我还不太解释的明白,留一个问号???但是通过相同程序的运行,我们能够发现不同,word和word2之间的地址差为16个字节,当我将字符数组大小扩大为20时,地址差是按一个存储字增加的,那64位的存储字就应该为16字节,这也确实符合计算机组成里讲的对齐的方式存储),因为函数是通过堆栈来存储变量的,是高地址向低地址存储,我们可以把一个字符数组想成一个存储字,在字内是顺序存储的,就是从低地址向高地址,而存储字间是则是堆栈的顺序,是一种小端存放的方式,这里,word和word2看成指针是const的,是不变的,当scanf读入第一个12345678‘\0’字符串的时候是从word所指的位置向高地址依次写入,虽然越界到了规定的位置以外,但是c语言并没有提供有效的机制,即使这是不安全的,但是我们依然可以做,可以顺利的写入,然后读入第二个12345678‘\0’字符串的时候,同样的方式,从word2所指向的位置向高地址写入,很不幸的是,在定义字符数组的时候大小就决定了,并且是连续的分配的内存空间,所以写入到8的时候,其实就用完了定义的word2的数组大小,但是字符串末尾还有结束字符'\0',虽然是不安全的,但是c语言的编译器不会发现,因此'\0'被继续写到了接下来连续的地址中,就是word所指向的位置,写入就将原来的1所覆盖,读入就ok了,接下来是打印,首先先打印word所指向的字符串,第一个已经重新写入了,刚好是字符串结束字符,因此什么也不输出,然后是打印word2所指向的字符串,打印1.。。。一直要到'\0'才会认为是字符串的结束,所以就打印出了12345678‘\0',说到这里,我也就基本明白了字符串消失之谜的真相,用柯南的话,真相永远只有一个!

哦,原来是这样,果然不是我不明白,而是我并不知道,计算机的世界真的很精彩,而且很有意思,等着我,我一定要好好看看。

957f876afe86c502ad37ddf499e06e0f.png

e4d3589c017d36bdd28e70188f49b3bf.png

来源:oschina

链接:https://my.oschina.net/u/2692223/blog/664079

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值