sprintf()将字符串打印到(m)分配的数组,尽管它应该很小

时间:2015-10-22 18:57:03

标签: c

我一直在网上搜索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)。但是当我再次尝试在该声明之后打印字符串时 - >打印好像什么也没发生!怎么可能?

4 个答案:

答案 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()