我一直在网上搜索stackoverflow几个小时,并没有找到任何适合我的问题的答案 - 也许是因为它不是一个真正的问题,因为程序工作......但它不应该。听起来很奇怪?它至少对我而言。
这是大学任务的一部分。任务是为char数组分配内存,然后使用sprintf()将字符串打印到数组,最后使用printf()打印数组。对于内存分配,要使用malloc()(我知道有更好的方法,但我们必须使用这些函数)。
这就是我所拥有的:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
// Declare char array
char *string;
/* Allocate memory for string of certain length
The 1 is only to show what's wrong. I'm aware of the actual size needed */
if( (string = malloc( 1 * sizeof(char) ) ) == NULL )
{
perror("malloc failed to allocate n chars!");
exit(1);
}
/* Print string to previously allocated memory. Now I would expect an error due to too few bytes allocated */
sprintf(string, "Too many characters here...");
// Print string to command line
printf("%s\n", string);
return 0;
}
到目前为止它的工作原理:在Mac OSX上使用gcc -Wall -std = c99和Ubuntu进行编译时没有任何通知。
BUT
问题在于它不应该。您可能已经注意到我为字符串分配了几个字节,我正在写入数组。无论字符串有多长(尝试多达1000个字符)或我分配了多少字节,它仍然可以工作。 如果大学的自动化测试部门不会将其标记为错误,那就不关心它了。它说程序没有从分配的数组中读取。这就是为什么我假设,sprintf将字符串放在任何位置,但在分配的数组中。但我无法解释这是如何实现的。
如果你们知道我做错了什么,我将深表感激。
提前致谢!
------更新------
正如迈克指出我在这个片段中没有使用免费(字符串)(感谢提示!)。在实际程序中,我在printf()之后放置了free(string)。但是当我再次尝试在该声明之后打印字符串时 - >打印好像什么也没发生!怎么可能?
答案 0 :(得分:2)
覆盖malloc数组的结尾可能会搞砸,但究竟是什么搞砸是偶然的。在一个简单的测试中发生这种情况并不会失败并不令人惊讶,特别是因为你的程序在提交后不久就退出了。写的字符串本身是完整且有效的 - 它只是使用可能遭受的内存区域的其他事情。这并不意味着它将在更复杂的环境中发挥作用。
答案 1 :(得分:2)
问题在于断言“问题在于它不应该”。或“预计会出错”。
/* Now I would expect an error due to too few bytes allocated */
sprintf(string, "Too many characters here...");
当代码执行某些操作时,不应该像写入超出分配的内存空间一样,C不会定义应该发生的事情。因此,它是未定义的行为(UB)。要预期错误,需要在C的部分上定义行为。
UB意味着可能发生任何事情。代码不需要检查并抱怨尝试访问外部分配的内存。
C为您提供了大量的代码绳索,以便快速完成各种事情 - 包括足够的绳索让代码自行挂起。
鉴于sprintf()
易于写出界限,代码可能已使用snprintf()
并检查其结果。 snprintf()
不会覆盖缓冲区的给定size
。
char *string;
size_t size = 1; // or whatever
string = malloc(size);
...
int n = snprintf(string, size, "Too many characters here...");
if (n < 0 || n >= size) return Error_code;
...
printf("%s\n", string);
答案 2 :(得分:1)
我刚刚再次测试了大学服务器上的代码 - 以前的SAME代码 - 现在它可以工作了。我完全不知道为什么,测试单元肯定有错误。
所以我的代码中没有错误。但至少用错误的参数测试它现在教会了我一些重要的东西(你们指出了什么): 未定义的行为也可能是一切看起来都很好;虽然它不应该。
所以从这个角度看你是对的。这与发布的主题非常相似。是我用错误的期望来解决这个问题。
谢谢!
答案 3 :(得分:0)
问题在于你假设应该出现问题并且编译器应该告诉你这是错误的。
语法是正确的,但语义不是 - 编译器只能告诉你这么多。 sprint()
将打印您想要的内容,但它在内存中写入的内容会有所不同。
考虑使用snprintf()