【问题标题】:C++ : Why I can't print a const char* with sprintf?C++:为什么我不能用 sprintf 打印 const char*?
【发布时间】:2012-05-27 05:17:49
【问题描述】:

我在这里缺少什么?快把我逼疯了!

我有一个返回 const char*

的函数
const char* Notation() const
{
    char s[10];
    int x=5;
    sprintf(s, "%d", x);
    return s;
}

现在在代码的另一部分我正在这样做:

.....
.....
char str[50];       
sprintf(str, "%s", Notation());
.....
.....

str 保持不变。

如果我这样做:

.....
.....
char str[50];
str[0]=0;
strcat(str, Notation());
.....
.....

str 设置正确。

我想知道为什么 sprintf 没有按预期工作......

【问题讨论】:

  • 也许一个想法是将函数更改为:void Notation(char* buffer) const 并在调用者提供的 char 缓冲区上工作。
  • 为什么投反对票?问题很明确,给出了一个“工作”示例,显示了努力,并给出了实际的问题示例。

标签: c++ string pointers constants printf


【解决方案1】:

您试图返回分配在堆栈上的数组,但其行为未定义。

const char* Notation() const
{
    char s[10];
    int x=5;
    sprintf(s, "%d", x);
    return s;
}

在您从函数Notation() 返回后,这里的s 将不会出现。如果您不关心线程安全,您可以将s 设为静态。

const char* Notation() const
{
    static char s[10];
    ....

【讨论】:

  • 我认为缓冲区是在编译时分配的,并在应用程序的整个生命周期内都保留在那里。如果这不是真的,那么这是否意味着每个返回非全局 const char* 的函数都是错误的? (和危险的)
  • 任何返回自动 const char* 的函数都是危险的。返回缓冲区还有许多其他方法 - 例如静态和使用 malloc 新分配的缓冲区。但是,如果您返回 malloc 的缓冲区,则必须正确管理清理。
  • @Wartin:我认为您正在考虑字符串文字。例如,如果您说:return "foobar"; -- 那将是安全的,因为字符串“foobar”会在应用程序的整个生命周期中持续存在。
  • @hawk :您认为将缓冲区设为静态会完成这项工作吗?我不关心线程安全(但我想知道为什么它很重要 ;-)
  • @Wartin - 粗略地说,函数内部的静态将变量的生命周期延长到程序结束。然而,可见性就像一个自动变量。它不是线程安全的原因仅仅是多个线程可能在函数中同时执行并相互踩踏。
【解决方案2】:

在这两种情况下,它都会调用未定义的行为,因为Notation() 返回一个本地数组,该数组在返回时被销毁。你不走运它在一种情况下有效,让你觉得它是正确的。

解决方法是使用std::string作为:

std::string Notation() const
{
    char s[10];
    int x=5;
    sprintf(s, "%d", x);
    return s; //it is okay now, s gets converted into std::string
}

或者使用 C++ 流作为:

std::string Notation() const
{
    int x=5;
    std::ostringstream oss;
    oss << x;
    return oss.str(); 
}

然后:

char str[50];       
sprintf(str, "%s", Notation().c_str());

std::ostringstream(和std::string)的好处(和美丽)是你不必事先知道输出的大小,这意味着你不必使用诸如@987654328之类的幻数@ 在数组声明中char s[10]。从这个意义上说,这些类是安全的。

【讨论】:

    【解决方案3】:

    Notation 中的char s[10] 被放置在堆栈上,因此在退出Notation 函数后它会被销毁。此类变量称为automatic。您需要使用new 将字符串保存在堆中:

    char *s = new char[10];
    

    但是你必须手动释放这个内存:

    char str[50];
    const char *nt = Notation();
    sprintf(str, "%s", nt);
    printf("%s", str);
    delete[] nt;
    

    如果您真的使用 C++,请使用内置的 string 类,如建议的 Nawaz。如果您以某种方式限制为原始指针,则在 Notation 之外分配缓冲区并将其作为 destination 参数传递,就像在 sprintfstrcat 中一样。

    【讨论】:

    • 虽然这可以解决问题,但这是一个糟糕的主意。如果他尝试以现在的方式使用该功能,那将是肯定的内存泄漏。
    • 是的,就是这样。既然问题是关于 C++ 的,那么string 是最好的选择。
    猜你喜欢
    • 2010-09-09
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2019-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多