我遇到了一个问题的一部分,我得到了一个输出,但是我需要解释为什么它是真的并且有效?
char arr[4];
strcpy(arr,"This is a link");
printf("%s",arr);
当我编译并执行时,我得到以下输出。 的输出:
This is a link
答案 0 :(得分:0)
您的代码存在一些内存问题(缓冲区溢出)。函数strcpy
将字节复制到空字符。函数printf
将打印,直到空字符。
答案 1 :(得分:0)
无法保证这段代码的行为。 它就像是:你告诉我"我会在下午5点接你。"当你来的时候我会在那里(保证)。但我不能保证我是否曾经抓过你一杯咖啡,因为你并没有告诉我你想要一杯咖啡。也许我非常好,买了两杯咖啡,或者我是一个小偷,只为自己买了一杯。
答案 2 :(得分:0)
它可能有用。它可能不会。它可能会立即失败并且很明显。它可能在某个未来的任意时间失败,并以微妙的方式使你疯狂。
这是未定义行为的常常隐蔽性质。不要这样做。
如果它起作用,那完全是偶然的,绝不保证。您可以可能覆盖堆栈或其他内存中的内容(取决于实现以及实际变量str
的定义方式/位置 (a))但是在该点之后没有使用被覆盖的存储器(考虑到代码的简单性质)。
它以 no 方式意外工作的可能性使它成为一个好主意。
对于我们中的语言律师,J.2
的{{1}}部分(未定义行为的实例)明确指出:
数组下标超出范围,即使某个对象显然可以使用给定的下标访问(如声明
C11
中的左值表达式a[1][7]
)。
信息性部分引用int a[4][5]
,这是规范性的,并在讨论指针/整数添加时说明(其中6.5.6
是一个示例):
如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出; 否则,行为未定义。如果结果指向数组对象的最后一个元素之后的一个,则不应将其用作评估的一元*运算符的操作数。
(a)例如,在我的系统上,声明a[b]
内的变量会导致程序崩溃,因为缓冲区溢出会破坏堆栈上的返回地址。
但是,如果我将声明置于文件级别(main
之外),它似乎运行正常,打印消息然后退出程序。
但我向你们保证,这只是因为在这种情况下,你所破坏的记忆对于程序的延续并不重要。几乎肯定在任何事情都很重要比这个例子更重要。
答案 3 :(得分:0)
简短的答案为何它起作用(那个时间)是 - 你很幸运。超出数组末尾的写入是未定义的行为。 未定义行为只是未定义,它可能只是容易导致分段错误,因为它产生输出。 (尽管通常会导致堆栈损坏)
在C中处理字符数组时, 负责确保您已分配足够的存储空间。当您打算将数组用作字符串时,您还必须为 nul-terminatedating 字符的每个字符 +1
分配足够的存储空间(这是C)中 nul-terminated 字符串的定义。
为什么会这样?通常,当您请求说char arr[4];
时,编译器只保证为arr
分配4个字节。但是,根据编译器,对齐等,编译器实际上可以将它用作最小分配单元的任何内容分配给arr
。这意味着虽然您只请求了4-bytes
并且只保证4-usable-bytes
,但编译器实际上可能已经预留了8, 16, 32, 64, or 128, etc-bytes
。
或者,你很幸运,arr
是最后一次请求的分配,还没有任何请求或写入内存地址,从内存byte-5
后的arr
开始。< / p>
关键是,您已请求4-bytes
并且仅保证4-bytes
可用。是的,它可以在你的代码中发生任何其他事件printf
之前发挥作用,但是你的代码完全不可靠,你正在玩堆栈损坏的俄罗斯轮盘(如果它还没有发生)。
在C中,您有责任确保您的代码,存储和内存使用都是定义明确的,并且您不会徘徊到 undefined ,因为如果你这样做,所有的赌注都会关闭,你的代码不值得存储它的字节。
你怎么能让你的代码明确定义?适当地限制并验证代码中的每个必需步骤。对于您的代码段,您可以使用strncpy
代替strcpy
,然后在致电arr
之前肯定地 nul-terminate printf
,例如
char arr[4] = ""; /* initialize all values */
strncpy(arr,"This is a link", sizeof arr); /* limit copy to bytes available */
arr[sizeof arr - 1] = 0; /* affirmatively nul-terminate */
printf ("%s\n",arr);
现在,您可以在代码的其余部分依赖arr
的内容。
答案 4 :(得分:-1)
只要在strcpy之后放置printf,代码就会一直有效。但这是错误的编码
尝试以下,它将无法正常工作
int j;
char arr[4];
int i;
strcpy(arr,"This is a link");
i=0;
j=0;
printf("%s",arr);
要理解为什么会这样,你必须理解堆栈的想法。所有局部变量都在堆栈上分配。因此,在您的代码中,程序控制为“arr”分配了4个字节,当您复制大于4个字节的字符串时,您将覆盖/损坏其他一些内存。但是当你在strcpy之后访问“arr”因此你覆盖的区域可能属于其他一些仍然没有被程序更新的变量,这就是你的printf工作正常的原因。但正如我在示例代码中建议更新其他变量落入您已覆盖的内存区域时,您将无法获得正确的结果(或者需要更合适)
你的代码也在工作,因为如果它以其他方式向下扩展,那么你也没有获得所需的输出