18

What is the proper way to initialize unsigned char*? I am currently doing this:

unsigned char* tempBuffer;
tempBuffer = "";

Or should I be using memset(tempBuffer, 0, sizeof(tempBuffer)); ?

54 69 6D
  • 674
  • 8
  • 17
Brian
  • 249
  • 1
  • 3
  • 9
  • 2
    The variable name is wrong. It is not a buffer, just a pointer. Create a buffer with unsigned char tempBuffer[666]; – Hans Passant Feb 02 '11 at 15:07

7 Answers7

26

To "properly" initialize a pointer (unsigned char * as in your example), you need to do just a simple

unsigned char *tempBuffer = NULL;

If you want to initialize an array of unsigned chars, you can do either of following things:

unsigned char *tempBuffer = new unsigned char[1024]();
// and do not forget to delete it later
delete[] tempBuffer;

or

unsigned char tempBuffer[1024] = {};

I would also recommend to take a look at std::vector<unsigned char>, which you can initialize like this:

std::vector<unsigned char> tempBuffer(1024, 0);
Ahmed Abobakr
  • 1,618
  • 18
  • 26
Dmitry
  • 6,590
  • 2
  • 26
  • 19
9

The second method will leave you with a null pointer. Note that you aren't declaring any space for a buffer here, you're declaring a pointer to a buffer that must be created elsewhere. If you initialize it to "", that will make the pointer point to a static buffer with exactly one byte—the null terminator. If you want a buffer you can write characters into later, use Fred's array suggestion or something like malloc.

Karl Bielefeldt
  • 47,314
  • 10
  • 60
  • 94
  • so `malloc(24);` (or some number) would be preferred over setting it to `""` or `0` or `NULL`, in your opinion? – Brian Feb 02 '11 at 15:18
  • @Brian: I doubt one can answer without knowing what you want to achieve. However, it seems that you indeed need to allocate some memory. In this case, never forget to `free()` it when you no longer need it. – ereOn Feb 02 '11 at 15:24
  • @Brian: Generally one uses `malloc` when the maximum size you will need is unknown at compile time, so you would set it to `NULL` at first, then `malloc` as much as you need when you know the size. Allocating an array is preferable when the size is relatively small and fixed, as you don't have to worry about freeing the memory, but causes problems if you try to return it out of your function. Like @ereOn said, we really need more details about what you're trying to do if you want precise advice. – Karl Bielefeldt Feb 02 '11 at 15:34
  • 1
    @Karl: I am using the SHA1 implementation here: http://tamale.net/sha1/sha1-0.2/ and I am returning an `unsigned char*` from `getDigest()`. Prior to calling `getDigest()`, I have to declare an `unsigned char*`. – Brian Feb 02 '11 at 15:41
  • 1
    @Brian, in that case, you don't even really have to initialize it at all, although it's good practice to assign it to `NULL` if you're going to declare it early. I would probably just do it all in one line: `unsigned char* digest = sha1ObjectPtr->getDigest();` – Karl Bielefeldt Feb 02 '11 at 15:46
  • Also note @Brian, that APIs differ on if they want you to `free()` pointers returned like this or not. In this case it is your responsibility to call `free(digest)` after you're done with it. – Karl Bielefeldt Feb 02 '11 at 15:53
  • @Karl: Could just be my compiler, but when I include it all on one line, I do not get the correct `char` result stored in my `digest`. However, when I perform `(unsigned char*)malloc(21);` I do get the correct result. – Brian Feb 02 '11 at 15:54
  • @Brian, have you tried the example program in the [README](http://tamale.net/sha1/sha1-0.2/README)? `getDigest()` calls `malloc` internally so you shouldn't need to. If you changed anything from that example program, can you edit your original post to include all that code? – Karl Bielefeldt Feb 02 '11 at 16:02
  • @Karl: Nothing changed. Just every once and a while the last one or two bytes is wrong – Brian Feb 02 '11 at 16:48
  • The second method *may* leave you with a NULL pointer. It is *not* guaranteed to. Just because a constant integer expression with a value of zero is a *null pointer constant* does not mean that a pointer which compares equal to a *null pointer constant* has a bit value of all zeros (which is what the memset will produce). – Martin Bonner supports Monica Apr 24 '17 at 10:19
6

As it's a pointer, you either want to initialize it to NULL first like this:

unsigned char* tempBuffer = NULL;
unsigned char* tempBuffer = 0;

or assign an address of a variable, like so:

unsigned char c = 'c';

unsigned char* tempBuffer = &c;

EDIT: If you wish to assign a string, this can be done as follows:

unsigned char myString [] = "This is my string";
unsigned char* tmpBuffer = &myString[0];
Kerri Brown
  • 1,157
  • 1
  • 8
  • 18
  • 2
    It's worth clarifying that your second example will give you a valid pointer to a valid character, but it is not usable with standard string functions (even though the type is the same) since string functions expect a pointer to a nul-terminated array of characters, and not a pointer to a single character. My guess is that the OP is interested in working with strings. – Tim Martin Feb 02 '11 at 15:22
  • Thanks Tim. Edited accordingly. – Kerri Brown Feb 02 '11 at 15:29
4

If you know the size of the buffer at compile time:

unsigned char buffer[SIZE] = {0};

For dynamically allocated buffers (buffers allocated during run-time or on the heap):

1.Prefer the new operator:

unsigned char * buffer = 0;  // Pointer to a buffer, buffer not allocated.
buffer = new unsigned char [runtime_size];

2.Many solutions to "initialize" or fill with a simple value:

std::fill(buffer, buffer + runtime_size, 0); // Prefer to use STL
memset(buffer, 0, runtime_size);
for (i = 0; i < runtime_size; ++i) *buffer++ = 0;  // Using a loop

3.The C language side provides allocation and initialization with one call.
However, the function does not call the object's constructors:

buffer = calloc(runtime_size, sizeof(unsigned char))

Note that this also sets all bits in the buffer to zero; you don't get a choice in the initial value.

Ziezi
  • 6,375
  • 3
  • 39
  • 49
Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
2

It depends on what you want to achieve (e.g. do you ever want to modify the string). See e.g. http://c-faq.com/charstring/index.html for more details.

Note that if you declare a pointer to a string literal, it should be const, i.e.:

const unsigned char *tempBuffer = "";
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • If I make it `const`, I can't add to it later though... Should it always be `const`? – Brian Feb 02 '11 at 15:03
  • 1
    @Brian: If it points to a string literal, it should be const. – Fred Nurk Feb 02 '11 at 15:04
  • 1
    @Brian: If you intend to "add to it later", you need to be pointing your `tempBuffer` to an actually memory buffer, and not to a literal string. – KevenK Feb 02 '11 at 15:04
  • @Fred: I see. So if I start off with `unsigned char *tempBuffer = "I am a beautiful banana"`, then it is const. Otherwise, if I will be adding bytes to it in a later routine, then non-const is ok, correct? – Brian Feb 02 '11 at 15:05
  • @Brian: Declaring a pointer does not allocate any space to write into via that pointer, unless you initialise it with a literal string, in which case it has exactly that many bytes (+ 1 to hold the terminating 0-byte) allocated that should be treated as read-only. That means you can't add to the end of a string declared as a pointer anyway, unless you have first pointed it at a valid region of memory (either an array, or memory dynamically allocated with `malloc()`). – j_random_hacker Feb 02 '11 at 15:10
  • @Brian: An all-encompassing "right answer" is far too long-winded to put here, which is why I provided that link, which hopefully will provide most of the insight. – Oliver Charlesworth Feb 02 '11 at 15:12
  • @Brian: You cannot "add bytes" to an object, but if it points into an array which you can modify (or *is* an array as in my answer), then non-const is okay. – Fred Nurk Feb 02 '11 at 15:32
2

If the plan is for it to be a buffer and you want to move it later to point to something, then initialise it to NULL until it really points somewhere to which you want to write, not an empty string.

unsigned char * tempBuffer = NULL;
std::vector< unsigned char > realBuffer( 1024 );
tempBuffer = &realBuffer[0]; // now it really points to writable memory
memcpy( tempBuffer, someStuff, someSizeThatFits );
CashCow
  • 30,981
  • 5
  • 61
  • 92
1

The answer depends on what you inted to use the unsigned char for. A char is nothing else but a small integer, which is of size 8 bits on 99% of all implementations.

C happens to have some string support that fits well with char, but that doesn't limit the usage of char to strings.


The proper way to initialize a pointer depends on 1) its scope and 2) its intended use.

If the pointer is declared static, and/or declared at file scope, then ISO C/C++ guarantees that it is initialized to NULL. Programming style purists would still set it to NULL to keep their style consistent with local scope variables, but theoretically it is pointless to do so.

As for what to initialize it to... set it to NULL. Don't set it to point at "", because that will allocate a static dummy byte containing a null termination, which will become a tiny little static memory leak as soon as the pointer is assigned to something else.

One may question why you need to initialize it to anything at all in the first place. Just set it to something valid before using it. If you worry about using a pointer before giving it a valid value, you should get a proper static analyzer to find such simple bugs. Even most compilers will catch that bug and give you a warning.

Lundin
  • 195,001
  • 40
  • 254
  • 396