0
#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's size is only one, but cout can print right result. Why?

Is it safe to do? Or I had to consider set one big size for buffer when using char * related methods?

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
jiafu
  • 6,338
  • 12
  • 49
  • 73
  • refer http://stackoverflow.com/questions/3919995/determining-sprintf-buffer-size-whats-the-standard – Taj Nov 29 '13 at 06:18
  • You are allowed to shoot yourself in the foot in C++. You are overrunning the `buffer` array, but apparently this is not causing a severe enough issue at run-time to cause abnormal program operation. As far as `cout` is concerned, `buffer` is just a pointer to a null-terminated character string. – Andon M. Coleman Nov 29 '13 at 06:18
  • It isn't right; It's undefined behavior, which is just that: [undefined](http://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior/4105123#4105123). – WhozCraig Nov 29 '13 at 06:20

3 Answers3

0

No, it's not safe.

The C-style strings need to be null terminated, but there's not enough space in buffer. Undefined behavior doesn't mean guaranteed working or not working. When I tested your program, I got a segmentation fault.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
0

As Yu Hao stated: It Is not safe! But why is it working sometimes?

char buffer[1]

is not a managed array. It just gives the compiler the hint that he should reserve space for one char. the variable buffer is used as a pointer to that space and looses all information about the original size. so the above statement is the same as writing:

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

buffer just contains the address of a character but no other information at all! your sprintf expects such an address an happy writes its string beginning at buffer.

The segmentation fault is a message from the Operating System. Your process allocates space for one byte. The OS manages your memory in pages (segments). When you cross a border of these segments a segmentation fault is raised. As far as I know it depends on the compiler whether variable are allocated on the beginning or at the end of a segment.

Yu Hao's compiler obviously puts them at the end - yours at the front. So your sprintf doesn't write over the boundary of a segment.

Hope it helps.

Joachim Weiß
  • 407
  • 2
  • 12
  • "The OS manages your memory in pages (segments). When you cross a border of these segments a segmentation fault is raised." This part is plain wrong. – Siyuan Ren Nov 29 '13 at 07:29
  • Its simplified - I agree! Plain wrong? http://en.wikipedia.org/wiki/Segmentation_fault – Joachim Weiß Nov 29 '13 at 07:53
  • According to that webpage you would be right if it were still 1970s. Segmentation fault indeed originally refers to what is now called page fault, but today's meaning is completely different. – Siyuan Ren Nov 29 '13 at 07:58
  • Page fault is something different! "Segmentation" is a historical term for the approach to memory management nowadays known as paging (see e.g. Lions' Commentary on UNIX 6th Edition, with Source Code), but the term is still used in the context of a "segmentation fault" error; page fault has a different meaning (though a page fault can lead to a segmentation fault). – Joachim Weiß Nov 29 '13 at 08:32
  • "The OS manages your memory in pages (segments). When you cross a border of these segments a segmentation fault is raised." This is what you said. You are referring to page fault. – Siyuan Ren Nov 29 '13 at 09:35
  • Segmentation fault happens when you have an invalid memory acess. Crossing page border itself speaks nothing of the validity of memory. The next page may already been allocated to you, in which case it is perfectly legal; it may also be nonexistent or in the kernel space, in which case a segfault is raised. Segfault that happens when crossing page boundary is neither the most common nor the most representative one. Null pointer dereferencing, uninitialized pointer, and double free are. So one can hardly imagine why you choose this example as the "simplified" explanation of segfault. – Siyuan Ren Nov 29 '13 at 09:45
  • Now I see our misunderstanding. You are right if the OS reserves you more than one page then you may cross the borders. I was implying that for one char not more than one page is reserved. – Joachim Weiß Nov 29 '13 at 10:15
0

As for considering the size needed to store a char * string, many of the C stdlib string functions will tell you the length they require if you pass them NULL. You can call this before allocating storage for the string to know how much storage you need:

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;

Another solution is to use something like snprintf (...), which guarantees that it will truncate the output so that it will not overrun your buffer:

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

In your case, the buffer is only 1 character long so it only has enough space to store the null terminator; not particularly useful.

Andon M. Coleman
  • 42,359
  • 2
  • 81
  • 106