This isn't about "saving memory", this is about dynamic allocation versus a fixed-length buffer.
In your example you're assuming that your data will be no more than 19 characters. This could be a huge mistake. The difference between char* x
and char x[20]
is not really relevant until you want to use that data outside the scope it was declared in.
A char* x
allocated using malloc
will persist outside the function's scope. A char[20]
will not, you need to copy it before it gets recycled.
So in comparison, a buffer like char x[20]
:
- effectively zero cost to create
- must be conservatively sized to avoid consuming too much stack space
- will need to be NUL terminated when declared, like
char x[20] = { 0 }
- cannot be used once they fall out of function scope
Whereas char* x
:
- has a small initialization cost
- must be released with
free
when no longer used or program will leak memory
- can be used outside of function scope
- must be initialized before use, may contain junk data
You're 100% responsible for:
- properly initializing your character buffers
- ensuring that the buffers are the correct size for the data you intend to store in them
- informing any functions manipulating this buffer what the buffer's size is, or in some cases, what the remaining size is
- NUL terminating any buffers you manipulate where you may overwrite the terminator
- releasing any memory allocated dynamically
Typically you'll see fixed-length buffers used for things like reading in and parsing a file where you do so carefully and with awareness of your buffer's size limits. Reading functions that take a length argument are the ones you want to use even though there are some like gets()
which are commonly shown. Those can and will create huge buffer-overflow bugs.
In C++ it's easy to avoid this mess and just use std::string
which deals with all of this for you automatically.