4

据我了解,正确的编程风格告诉如果你想从另一个函数获取字符串(char [])最好由调用者创建 char * 并将其与创建的字符串长度一起传递给字符串格式化函数。在我的情况下,字符串格式化函数是“getss”。

void getss(char *ss, int& l)
{

    sprintf (ss,"aaaaaaaaaa%d",1);
    l=11;
}


int _tmain(int argc, _TCHAR* argv[])
{

    char *f = new char [1];
    int l =0;
    getss(f,l);

    cout<<f;
    char d[50] ;
    cin>> d;
    return 0;
}

"getss" 格式化字符串并将其返回给 ss*。我认为 gets 不允许超出调用者创建的字符串长度。据我了解,调用者通过变量“l”告诉长度,“getcc”返回长度,以防缓冲区未完全填充但不允许超出调用者定义的数组范围。

但现实告诉我,调用者创建的缓冲区大小并不那么重要。没关系,如果您创建大小为 1,并填充 11 个字符长。在输出中,我将获得“getss”已填充的所有字符。

那么传递长度变量的原因是什么 - 你总是会得到零终止的字符串,你会根据它找到结尾。

如果getss可以扩展它,创建具有指定长度的缓冲区的原因是什么?

它是如何在现实世界中完成的——从另一个函数中获取字符串?

4

7 回答 7

2

实际上,调用者是分配缓冲区并知道可以容纳在其中的字符串的最大大小的那个。它将那个大小传递给函数,函数必须使用它来避免溢出传递的缓冲区。

在您的示例中,这意味着调用snprintf()而不是sprintf()

void getss(char *ss, int& l)
{
    l = snprintf(ss, l, "aaaaaaaaaa%d", 1);
}

当然,在 C++ 中,您只需要返回std::string的一个实例,所以这主要是一个 C 范式。由于 C 不支持引用,因此该函数通常返回字符串的长度:

int getss(char *buffer, size_t bufsize)
{
    return snprintf(buffer, bufsize, "aaaaaaaaaa%d", 1);
}
于 2012-07-20T10:32:43.827 回答
1

你只是幸运。Sprintf() 无法扩展(静态分配的)存储,除非您传入至少 length + 1 个元素的 char 数组,否则您的程序会崩溃。

于 2012-07-20T10:30:35.787 回答
1

在现实世界中,C++ 最好使用std::string对象和std::stringstream

char *f = new char [1];

sprintf (ss,"aaaaaaaaaa%d",1);

你好,缓冲区溢出!在 C 中使用snprintf而不是sprintf在 C++ 中使用 C++ 功能。

于 2012-07-20T10:31:16.883 回答
1

据我了解,调用者通过变量“l”告诉长度,“getcc”返回长度,以防缓冲区未完全填充但不允许超出调用者定义的数组范围。

这是现场!

但现实告诉我,调用者创建的缓冲区大小并不那么重要。没关系,如果您创建大小为 1,并填充 11 个字符长。在输出中,我将获得“getss”已填充的所有字符。

这是绝对错误的:您调用了未定义的行为,并且没有崩溃。像 valgrind 这样的内存检查器会将此行为报告为错误。

那么传递长度变量的原因是什么。

长度是为了避免这种未定义的行为。我知道当您不知道要返回的字符串的长度时,这是相当令人沮丧的,但这是唯一不会产生字符串所有权问题的安全方法。

一种替代方法是动态分配返回值。这使您可以返回任意长度的字符串,但调用者现在负责释放返回的值。这对读者来说不是很直观,因为mallocfree发生在不同的地方。

C++ 中的答案完全不同,而且要好得多:您使用std::string标准库中的一个类,它表示任意长度的字符串。此类对象管理为字符串分配的内存,无需free手动调用。

于 2012-07-20T10:34:30.763 回答
1

在这种情况下,您很幸运,内存中的“char *”之后没有“重要的”其他数据。C 运行时并不总是能可靠地检测到这些违规行为。尽管如此,您在这里弄乱了内存,并且您的程序随时容易崩溃。

除此之外,在“现代”C++ 代码中使用原始“char*”指针确实是你不应该再做的事情。

请改用 STL 类(std::string、std::wstring)。这样您就不必担心这样的内存问题。

于 2012-07-20T10:35:13.423 回答
1

对于 cpp 考虑智能指针在你的情况下可能是 a shared_ptr,这将负责释放内存,目前你的程序正在泄漏内存,因为你永远不会释放你分配的内存new。分配的空间new必须用 delete 重新分配,否则它将一直分配到您的程序退出,这很糟糕,想象一下您的浏览器在关闭它们时没有释放它用于选项卡的内存。

在字符串的特殊情况下,我会推荐 OP 所说的,使用字符串。使用 Cpp11,它将被移动(而不是复制),您无需使用new,也无需担心delete.

std::string myFunc() {
    std::string str
    //work with str
    return str
}
于 2012-07-20T10:43:58.227 回答
1

在 C++中,您不必构建字符串。只需单独输出零件

std::cout << "aaaaaaaaaa" << 1;

或者,如果您想将其保存为字符串

std::string f = "aaaaaaaaaa" + std::to_string(1);

(事件虽然调用to_string对于一个常量值来说有点傻)。

于 2012-07-20T11:00:44.700 回答