《C语言36—不同数据类型的strcpy》

2019年4月9日星期二 中雨转小雨


在微信公众号里看见一个题目,自己来试了一下,于是将其做一个记录。
公众号的名称是“C语言与程序设计”,原文链接是:一道C语言面试题,真的不简单!


原程序是:

#include <stdio.h>
#include <string.h>

int main(void)
{
    char s[] = "abcdefghijklmnopqrstuvwxyz";
    char d[] = "123";
    strcpy(d, s);
    printf("%s %s", s, d);

    return 0;
}

我在vs2017里面将strcpy格式改成strcpy_s后变成:

#include <stdio.h>
#include <string.h>

int main(void)
{
    char s[] = "abcdefghijklmnopqrstuvwxyz";
    char d[] = "123";
    strcpy_s(d,100, s);
    printf("%s %s", s, d);

    return 0;
}

运行程序之后出现如下情况:


运行结果与报错信息

从显示的结果看,运行结果是:

mnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz

但是在运行结果出来后却报错了:

Run-Time Check Failure #2 - Stack around the variable 's' was corrupted.

s是错误的?


(我和这篇文章的作者的运行结果有所不同,据说是因为具体分配内存有可能不一样。)
以下是作者的说法:
请看题:

原题目

题目描述很简单,让你分析它的输出。

  • 小伙伴A说,这不就是把s复制到d嘛,所以输出自然是s不变,d变为s了啊。
  • 小伙伴B说,很明显复制到d时越界了啊,程序会报错然后停止运行啊。
  • 小伙伴C说,应该没有表面上越界这么简单,我得好好思考一下,肯定会有陷阱,等我调试一下再给出答案。

以上是3种说法,我们先不评论,直接给出程序运行结果:


运行结果

咦?很奇怪,输出d是正确的,s发生了截断!要说越界也应该是d错啊,这是什么情况?大家不要着急,我们一步步来分析调试找原因。

首先我们先来回顾一下strcpy函数的原理,把一个字符串复制到一个字符串上并在末尾追加空字符,但没有越界检验,安全性堪忧。但此题看运行结果是复制成功了,不应该是越界吗?

那再往下就不能靠分析了,得调试程序找错了,说白了现在问题就在越界这里,似乎得用我们的利器printf查看字符串存储的内存地址了,上图:

调试
调试结果

看到内存地址我们好像明白了点什么,d的起始地址为20,s起始地址为30,也就是说系统并不是跟我们想像的那样给数组d只分配了4字节的内存,而是分配了16字节(内存地址为16进制)!

到这里,基本就全明白了,应该是把s复制到d中时,26个字母占用26字节确实越界了,占用了s本身的一些存储空间,d原来的16字节空间存了到p的16个字母,从q开始剩下的10个字母把原先s中的前十一个字母覆盖了(因为strcpy还追加了空字符),当最后打印%s 时,直到空字符打印才停止,因此d打印正确,s只打印了从q开始的10个字母,我们把s改为10个字母来验证一下我们的推测:

结果正确!当然,具体给d分配多少空间可能取决于编译器和系统的具体实现,但可以肯定的是只要不够27字节,s肯定会发生截断,而且在d仅为字符串123的前提下,d的空间99%不会达到27字节,也就是s很大几率要截断。

此题还有一点没讲,如果把s和d的那两行代码交换一下位置会发生什么呢?这个就留给大家吧,提醒一下没那么简单哦!


以下是我的调试及后续调整的运行过程与结果:
调试的结果是:

004FFC54 004FFC48
mnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz

在结果出来后,也还是报错了。

后面的过程我还没怎么看懂,先搁置吧。


2019年4月9日

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容

  • 在C语言中,五种基本数据类型存储空间长度的排列顺序是: A)char B)char=int<=float C)ch...
    夏天再来阅读 3,325评论 0 2
  • __block和__weak修饰符的区别其实是挺明显的:1.__block不管是ARC还是MRC模式下都可以使用,...
    LZM轮回阅读 3,284评论 0 6
  • 最全的iOS面试题及答案 iOS面试小贴士 ———————————————回答好下面的足够了-----------...
    zweic阅读 2,689评论 0 73
  • 数组在程序设计中,为了处理方便, 把具有相同类型的若干变量按有序的形式组织起来。这些按序排列的同类数据元素的集合称...
    朱森阅读 3,895评论 2 13
  • 越是无知的,越是喜欢端,从扮相到举止;越是无信仰的,越看重信仰。或者信奉某个名人、某一偶像;或者信奉上帝与神灵……...
    凌宗伟阅读 335评论 0 1