将数据存储在char数组中导致变量

时间:2017-01-09 18:57:16

标签: c++

我正在开发一个C ++项目,我遇到了问题。

以下是我的代码

tempfingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_TYPE_RSA);
    char temp[48];
    memset(temp, 0, sizeof(temp));
    for (i = 0; i < 16; i++)
    {
        //fingerprintstream << (unsigned char)tempfingerprint[i] << ":";
        if (temp[0] == 0)
        {
            sprintf(temp, "%02X:", (unsigned char)tempfingerprint[i]);
        }
        else
        {
            //sprintf(temp, "%s:%02X", temp, (unsigned char)tempfingerprint[i]);
            char characters[3];
            memset(characters, 0, sizeof(characters));
            //If less than 16, then add the colon (:) to the end otherwise don't bother as we're at the end of the fingerprint
            sprintf(characters, "%02X:", (unsigned char)tempfingerprint[i]);
            strcat(temp, characters);
        }
    }
    //Remove the end colon as its not needed. 48 Will already be null terminated, so the previous will contain the last colon
    temp[47] = 0;
    return string(temp);

当我运行我的应用程序时,我从visual studio得到以下错误

Run-Time-Check Failure #2 - Stack around the variable 'temp' was corrupted. 

我通过Valgrind在Linux上运行了相同的代码并且没有显示任何错误,所以我不确定Windows的问题是什么。

2 个答案:

答案 0 :(得分:3)

这是一种使用Paul McKenzie谈论的方法(尽管他可能以不同的方式实现它),基于它看起来就像你试图用流

#include <iostream>
#include <sstream>
#include <iomanip> // output format modifiers
using namespace std;

int main()
{
    stringstream fingerprintstream;
    // set up the stream to print uppercase hex with 0 padding if required
    fingerprintstream << hex << uppercase << setfill('0');

    // print out the first value without a ':'
    fingerprintstream << setw(2) << 0;

    for (int i = 1; i < 16; i++) // starting at 1 because first has already been handled.
    {
        // print out the rest prepending the ':'
        fingerprintstream << ":" << setw(2) << i;
    }
    // print results
    std::cout << fingerprintstream.str();
    return 0;
}

输出:

00:01:02:03:04:05:06:07:08:09:0A:0B:0C:0D:0E:0F

刚刚意识到我认为OP遇到了垃圾输出。输出数字时,<<将使用适当的转换来获取文本,但如果输出字符<<则会输出字符。因此fingerprintstream << (unsigned char)tempfingerprint[i];获取tempfingerprint[i]处的二进制值,并且由于强制转换,尝试将其渲染为字符。而不是“97”,你将得到(假设ASCII)“a”。您尝试打印的大量内容会产生无意义的字符。

示例:如果我改变

fingerprintstream << ":" << setw(2) << i;

fingerprintstream << ":" << setw(2) << (unsigned char)i;

输出变为

0?:0?:0?:0?:0?:0?:0?:0?:0?:0?:0 :0
:0?:0?:0
:0?:0?

请注意标签和换行符。

我需要知道tempfingerprint的定义,但你可以通过删除强制转换来解决垃圾输出问题。

根据新信息,tempfingerprintconst char *,因此tempfingerprint[i]char,并将作为字符打印。

我们想要一个数字,所以我们必须强迫吸盘为整数。

static_cast<unsigned int>(tempfingerprint[i]&0xFF)

&0xFF屏蔽除了最后一个字节之外的所有内容,当显示无符号时,消除负数的符号扩展为巨大的正数。

答案 1 :(得分:0)

据我所知,代码中有两个导致超出数组边界的问题:

首先,使用char temp[48],您可以保留48个字符来存储结果;但是,当使用第16个值调用strcat(temp, characters)并且characters至少包含包含冒号的字符时,则temp将包含16 * 3个数字/冒号+一个终止'\0' - 字符,即49个字符(不是48个)。请注意,strcat会自动附加一个以字符结尾的字符串。

其次,您定义char characters[3],以便为两位数和冒号保留位置,但不为终止'\0' - 字符保留位置。因此,sprintf(characters, "%02X:",...)将超过characters的数组边界,因为sprintf也会附加字符串终止符。

因此,如果您不想一般地重写代码,将定义更改为char temp[49]char characters[4]将解决问题。