正确的无符号字符指针初始化方式

18

什么是初始化 unsigned char* 的正确方法?我目前正在这样做:

unsigned char* tempBuffer;
tempBuffer = "";

我应该使用 memset(tempBuffer, 0, sizeof(tempBuffer)); 吗?


2
变量名错误。它不是缓冲区,只是一个指针。创建一个带有无符号字符tempBuffer[666]的缓冲区。 - Hans Passant
7个回答

26

为了“正确地”初始化指针(如您的示例中的unsigned char *),您只需要执行简单的

unsigned char *tempBuffer = NULL;

如果你想要初始化一个由 unsigned char 组成的数组,你可以选择以下任意一种方法:

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

我建议您也可以看一下 std::vector<unsigned char>,您可以通过以下方式进行初始化:

std::vector<unsigned char> tempBuffer(1024, 0);

9
第二种方法会留下一个空指针。请注意,这里没有为缓冲区声明任何空间,而是声明了一个指向必须在其他地方创建的缓冲区的指针。如果将其初始化为“”,那么指针将指向一个仅有一个字节(空结束符)的静态缓冲区。如果你想要稍后写入字符的缓冲区,请使用Fred的数组建议或类似“malloc”的东西。

@Brian:我认为在不知道你想要实现什么的情况下很难回答。然而,看起来你确实需要分配一些内存。在这种情况下,当你不再需要它时,千万不要忘记使用 free() 释放它。 - ereOn
1
@Karl:我在这里使用SHA1实现:http://tamale.net/sha1/sha1-0.2/,并从`getDigest()`返回一个`unsigned char*。在调用getDigest()之前,我必须声明一个unsigned char*`。 - Brian
1
@Brian,如果是这样的话,你甚至不需要初始化它,尽管如果你要早期声明它,将其赋值为NULL是一个好习惯。我可能会在一行中完成所有操作:unsigned char* digest = sha1ObjectPtr->getDigest(); - Karl Bielefeldt
@Karl:可能只是我的编译器问题,但当我将所有内容放在一行上时,我的“digest”中存储的char结果不正确。然而,当我执行(unsigned char*)malloc(21);时,我得到了正确的结果。 - Brian
第二种方法可能会让你得到一个空指针。但并不是保证一定会得到空指针。仅仅因为一个值为零的常量整数表达式是一个空指针常量,并不意味着与空指针常量相等的指针具有所有零位值(这就是memset将产生的结果)。 - Martin Bonner supports Monica
显示剩余5条评论

6

由于它是一个指针,您需要首先将其初始化为NULL,如下所示:

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

或者分配一个变量的地址,像这样:
unsigned char c = 'c';

unsigned char* tempBuffer = &c;

编辑: 如果您希望分配一个字符串,可以按以下方式执行:

unsigned char myString [] = "This is my string";
unsigned char* tmpBuffer = &myString[0];

2
值得澄清的是,你的第二个示例将为你提供一个有效字符的有效指针,但由于字符串函数期望一个指向以空字符结尾的字符数组的指针,而不是单个字符的指针,所以它不能与标准字符串函数一起使用(即使类型相同)。我的猜测是OP对处理字符串感兴趣。 - Tim Martin
谢谢Tim。已做出相应编辑。 - Kerri Brown

4

如果您在编译时知道缓冲区的大小:

unsigned char buffer[SIZE] = {0};

对于动态分配的缓冲区(即在运行时或堆上分配的缓冲区):

1.优先使用new运算符:

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

2.许多解决方案可以“初始化”或填充简单值:

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. C语言方面提供了一次性分配和初始化的功能。
然而,该函数不会调用对象的构造函数:

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

注意,这也会将缓冲区中的所有位都设置为零。您不能选择初始值。

2

如果计划是作为缓冲区,并且您希望稍后将其移动以指向某些内容,则应将其初始化为NULL,直到它真正指向您想要写入的位置,而不是空字符串。

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

2

这取决于您想要实现什么(例如,您是否需要修改字符串)。有关更多详细信息,请参见http://c-faq.com/charstring/index.html

请注意,如果声明指向字符串字面值的指针,则应为const,即:

const unsigned char *tempBuffer = "";

如果我将其设置为 const,那么以后就无法添加了... 它应该总是 const 吗? - Brian
1
@Brian:如果它指向一个字符串字面值,那么它应该是const。 - Fred Nurk
1
@Brian:如果你打算“以后再添加”,你需要将tempBuffer指向一个实际的内存缓冲区,而不是一个字面字符串。 - KevenK
@Fred:我明白了。所以,如果我开始使用unsigned char *tempBuffer = "I am a beautiful banana",那么它是const的。否则,如果我稍后在程序中添加字节,那么非const就可以了,对吗? - Brian
@Brian:你不能“添加字节”到一个对象中,但如果它指向一个你可以修改的数组(或者像我的答案一样一个数组),那么非const就可以了。 - Fred Nurk
显示剩余2条评论

1
答案取决于您打算如何使用无符号字符。Char 就是一个小整数,99% 的实现都是 8 位大小。C 语言恰好具有一些与 char 配合良好的字符串支持,但这并不限制 char 的用途仅限于字符串。

初始化指针的正确方式取决于1)它的作用域和2)它的预期用途。

如果指针被声明为静态的,和/或者在文件作用域中声明,那么ISO C/C++保证它被初始化为NULL。编程风格纯粹主义者仍然会将其设置为NULL,以使其风格与局部作用域变量一致,但从理论上讲这样做是没有意义的。

至于要将其初始化为什么...将其设置为NULL。不要将其设置为指向“”,因为这将分配一个包含空终止符的静态虚拟字节,一旦指针被分配给其他内容,它就会成为一个微小的静态内存泄漏。

有人可能会问为什么你需要首先将其初始化为任何值。在使用之前只需将其设置为有效值即可。如果您担心在给指针赋予有效值之前使用它,您应该获得一个合适的静态分析器来查找这些简单的错误。即使大多数编译器也会捕捉到这个错误并给出警告。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接