C strcpy和strncpy组合中出现意外结果
在我高中的期末考试练习中,我们遇到了以下问题: 执行代码后查找字符串s1、s2和s3的值:C strcpy和strncpy组合中出现意外结果,c,pointers,strcpy,string.h,C,Pointers,Strcpy,String.h,在我高中的期末考试练习中,我们遇到了以下问题: 执行代码后查找字符串s1、s2和s3的值: char s1[] = "Short Message Service", *s2, *s3; s2 = strchr(s1, 'M'); s3 = strrchr(s2,'S'); strncpy(s1 + 1, s2, 1); strcpy(s1 + 2, s3); 全班预期成绩为: s1 = SMService s2 = Message Service s3 = Service 当我们通过执行代码
char s1[] = "Short Message Service", *s2, *s3;
s2 = strchr(s1, 'M');
s3 = strrchr(s2,'S');
strncpy(s1 + 1, s2, 1);
strcpy(s1 + 2, s3);
全班预期成绩为:
s1 = SMService
s2 = Message Service
s3 = Service
当我们通过执行代码对其进行测试时,我们惊讶地看到结果是:
s1 = SMService
s2 = ice
s3 = Service
问题是没人能弄明白为什么s2缩短了。在试图弄清楚它的时候,我发现s2仍然是“消息服务”,直到执行“strcpy”函数的最后一行代码。我假设问题可能出在指针地址上,但我无法理解strcpy是如何影响s2的
所以我的问题是为什么s2不是我们所期望的,为什么它被缩短了 在您的代码中
s2
指向s1
中的M
,然后在上一次strcpy中被s3
覆盖:
char s1[] = "Short Message Service", *s2, *s3;
s2 = strchr(s1, 'M'); // s2 is pointing to s1 + 6 = Message Service
s3 = strrchr(s2, 'S'); // s3 is pointing to s1 + 14 = Service
strncpy(s1 + 1, s2, 1); // Write M in to s1[1], s1 = SMort Message Service
strcpy(s1 + 2, s3); // Write Service into s1 + 2
// s1 = SMService but s2 is pointing to s1 + 6 = ice
它似乎缩短了,因为最后的strcpy
插入了终止符。这一切都发生在同一个缓冲区中(s1[]
),调试器将使这一点变得显而易见。查看s2
点的位置:s1+6
。现在看看最后一个strcpy之后的s1+6
是什么:SMService
的尾部字符,这就是ice
和终止符。@WhozCraig谢谢你的解释。但如果是这样的话(即s2
指向:s1+6
)是否s3
指向s2+7
或直接指向s1+13
?在这两种情况下,s3
最终如何等于“服务”
?在分配strrchr
结果后,s3
中存储的地址从未改变,即s1+14
没有任何内容通过缓冲区的末端重写或更改该地址的数据,因此,当呈现时,s3
的呈现显示为简单的Service
。@WhozCraig谢谢,您的解释真的很有帮助<代码>strcpy(s1+2,s3)代码>是UB,因为源和目标重叠。违反char*strcpy的restrict
(char*restrict s1,const char*restrict s2)代码>。这使得测试用例失败了。@chux:我不相信这是真的<代码>s3
具有值s1+14
,strcpy
将通过s1+9将8个字符(包括终止NUL)复制到位置s1+2
。没有重叠。通过strcpy
参数s2
访问的对象都不会通过参数s1
修改(甚至读取)。restrict
施加的限制适用于指针引用的对象;对于char*
类型的指针,所有这些对象都具有char
类型。换句话说,restrict
与指针引用的值的范围无关;仅适用于实际值。见6.7.3.1第8和9段中的示例。对f(50,d+50,d)
的调用是有效的,因为该调用中两个指针参数引用的范围不重叠。在第二次调用中,f(50,d+1,d)
,有一个重叠,调用是UB。@rici同意-对我来说太晚了。靠近边缘不超过边缘。