字符串不是空终止错误

Posted

技术标签:

【中文标题】字符串不是空终止错误【英文标题】:String is not null terminated error 【发布时间】:2014-11-12 11:02:40 【问题描述】:

我有一个字符串不是空终止的错误,虽然我不完全确定为什么。在代码的第二部分中使用 std::string 是我尝试解决此问题的尝试之一,尽管它仍然不起作用。

我的初始代码只是使用缓冲区并将所有内容复制到 client_id[]。比发生的错误。如果错误是正确的,这意味着我有 client_id 或者 theBuffer 没有空终止符。我很确定 client_id 没问题,因为我可以在调试模式下看到它。奇怪的是缓冲区也有一个空终止符。不知道出了什么问题。

char * next_token1 = NULL;
char * theWholeMessage = &(inStream[3]);
theTarget = strtok_s(theWholeMessage, " ",&next_token1);
sendTalkPackets(next_token1, sizeof(next_token1) + 1, id_clientUse, (unsigned int)std::stoi(theTarget));

里面 sendTalkPackets 是。我得到一个字符串不是在最后一行终止的。

void ServerGame::sendTalkPackets(char * buffer, unsigned int buffersize, unsigned int theSender, unsigned int theReceiver)

std::string theMessage(buffer);
theMessage += "0";

const unsigned int packet_size = sizeof(Packet);
char packet_data[packet_size];
Packet packet;
packet.packet_type = TALK;

char client_id[MAX_MESSAGE_SIZE];


char theBuffer[MAX_MESSAGE_SIZE];
strcpy_s(theBuffer, theMessage.c_str());
//Quick hot fix for error "string not null terminated"

const char * test = theMessage.c_str();
sprintf_s(client_id, "User %s whispered: ", Usernames.find(theSender)->second.c_str());
printf("This is it %s ", buffer);
strcat_s(client_id, buffersize , theBuffer);

【问题讨论】:

theMessage += "0"; 您是否期望这会添加一个空终止符?如果是这样,它不会。 此外,在这种情况下,不需要对这个 char 数组和指针进行任何操作。您可以完全使用std::string,并且只有当函数调用const char* 时,您最终才会使用c_str() 成员函数来获取C 风格的字符串。 @PaulMcKenzie 是的,这实际上是我的一次尝试遗留下来的代码。现在我正在尝试使用字符串来操作它。 如果你真的想空终止字符串(无论如何都不需要),你会做theMessage.push_back(0); 【参考方案1】:

我认为问题出在这一行:

sendTalkPackets(next_token1, sizeof(next_token1) + 1, id_clientUse, (unsigned int)std::stoi(theTarget));

sizeof(next_token1)+1 将始终给出 5(在 32 位平台上),因为它返回指针的大小而不是 char 数组的大小。

【讨论】:

【参考方案2】:

可能导致此(或其他问题)的一件事:如 buffersize,你通过sizeof(next_token1) + 1next_token1 是 一个指针,它将具有(通常)4 或 8 的恒定大小。你 几乎可以肯定想要strlen(next_token1) + 1。 (或者也许没有 + 1;像这样传递尺寸的约定通常只包括 '\0' 如果它是一个输出缓冲区。还有其他几个 你使用sizeof的地方,可能有类似的问题。

但最好重做整个逻辑来使用 std::string 无处不在,而不是所有这些 C 例程。不 担心缓冲区大小和'\0' 终止符。 (对于协议 缓冲区,我还找到了 std::vector<char>std::vector<unsigned char> 很有用。这是在std::string 中的内存之前 保证是连续的,但即使在今天,它似乎也更多地对应 与我正在处理的抽象非常接近。)

【讨论】:

【参考方案3】:

你不能只做

std::string theMessage(buffer);
theMessage += "0";

这在两个方面都失败了:

std::string 构造函数不知道 buffer 在哪里结束,如果 buffer 不是 0 终止的。所以theMessage 可能是垃圾并包含随机内容,直到在缓冲区之外的内存中找到某个零字节。 将字符串“0”附加到theMessage 没有帮助。您想要的是在某处放置一个零字节,而不是值 0x30(这是用于显示零的 ascii 代码)。

解决这个问题的正确方法是在缓冲区的开头插入一个文字零字节buffersize 插槽。你不能在buffer 本身中这样做,因为buffer 可能不够大,无法容纳额外的零字节。一种可能是:

char *newbuffer = malloc(buffersize + 1);
strncpy(newbuffer, buffer, buffersize);
newbuffer[buffersize] = 0; // literal zero value

或者你可以构造一个std::string,随你喜欢。

【讨论】:

以上是关于字符串不是空终止错误的主要内容,如果未能解决你的问题,请参考以下文章

C 标准库 - string.h之strstr使用

为啥将字符串作为文件名而不是 char* 传递时出现错误?

为啥 C 中的字符串需要空终止?

为啥需要空终止符?

strstr() 用于非空终止的字符串

释放字符串直到空终止符