为什么它适合缓冲区的大小在C++中使用 sprintf 时很小

Why it is right for buffer's size is small when using sprintf in C++

本文关键字:sprintf C++ 缓冲区 为什么      更新时间:2023-10-16
#include <cstdio> 
#include <iostream> 
using namespace std;
int main () 
{
      char buffer [1];     
      sprintf (buffer, "%d is one number", 1); 
      cout<<buffer<<endl;
      return 0; 
 }

buffer的尺寸只有一个,但cout可以打印正确的结果。为什么?

这样做安全吗?或者我不得不考虑在使用相关方法时为缓冲区设置一个大大小char *

不,这不安全。

C 样式字符串需要以 null 结尾,但 buffer 中没有足够的空间。未定义的行为并不意味着保证工作或不工作。当我测试您的程序时,我遇到了分段错误。

正如余浩所说:不安全!但是为什么它有时会起作用?

char buffer[1]

不是托管阵列。它只是给编译器一个提示,他应该为一个字符保留空间。 变量缓冲区用作指向该空间的指针,并丢失有关原始大小的所有信息。所以上面的陈述和写作是一样的:

char bufferVar = ''; /* a single character */
char *buffer = &bufferVar; /* a pointer to bufferVar */

缓冲区只包含一个字符的地址,但根本没有其他信息!你的 sprintf 期望这样的地址,一个快乐的写入它的字符串从缓冲区开始。

分段错误是来自操作系统的消息。您的进程为一个字节分配空间。操作系统以页(段(为单位管理内存。当您越过这些段的边界时,将引发分段错误。据我所知,变量是在段的开头还是结尾分配取决于编译器。

余浩的编译器显然把它们放在最后——你的在前面。因此,您的冲刺不会覆盖段的边界。

希望对您有所帮助。

至于考虑存储char *字符串所需的大小,许多 C stdlib 字符串函数会告诉您如果将它们传递NULL它们所需的长度。您可以在为字符串分配存储之前调用它,以了解您需要多少存储空间:

std::cout << "You need a buffer that can store "
          << sprintf (NULL, "%d is one number", 1) + 1
          << " characters to safely store your string."
          << std::endl;

另一种解决方案是使用 snprintf (...) ,这保证它会截断输出,使其不会溢出缓冲区:

 snprintf (buffer, 1, "%d is one number", 1);
               // ~~~
               // Length of buffer

在您的情况下,缓冲区只有 1 个字符长,因此它只有足够的空间来存储 null 终止符;不是特别有用。