为什么在这种情况下会导致内存访问异常?

时间:2015-11-19 04:04:48

标签: c exception memory

我有以下代码,我需要格式化输出。但是当我这样做时,一个内存异常导致无效的内存访问异常。我在这做错了什么?请指教。

char* strData = malloc(tag_operation_report->tag.epc.size / 2), 
char* strTemp= malloc(tag_operation_report->tag.epc.size / 2);
    do
    {
        for (int i = 0; i < tag_operation_report->tag.epc.size / 2; i++)
        {
            uint32_t num = tag_operation_report->tag.epc.bytes[i];
            strTemp=sprintf(L"%x ", num);
            strData+=strTemp;
        }

    } while (tag_operation_report->tag.epc.size != 0);
    data = (void *)strData;
    free(strTemp);
    free(strData);

以下所示为例外。

Unhandled exception at 0x00007FF83C3C3A5D (msvcr120d.dll) in RFIDTest.exe: 0xC0000005: Access violation reading location 0x00000000000000E2.

3 个答案:

答案 0 :(得分:4)

问题1

strTemp=sprintf(L"%x ", num);

您要将int分配给strTemp,即char*。我很惊讶你的编译器没有警告你。目前尚不清楚你的目标是什么。

问题2

strData+=strTemp;

再次,您的编译器应该告诉您这是一个错误。您无法将char*增加另一个char*

问题3

free(strTemp);
free(strData);

您正在调用与free返回的值不同的指针值malloc。这会导致未定义的行为。

建议的解决方案

也许这就是你打算做的事情:

// Don't need to use dynamic memory allocation for this.
// It's only going to be used in sprintf. 20 characters should
// be large enough for that.
char strTemp[20];

// Bootstrap strData.
int strDataSize = 0;

char* strData = malloc(1); 
// If memory allocation failed, deal with the problem
if ( strData == NULL )
{
   exit(EXIT_FAILURE);
}

strData[0] = '\0';

for (int i = 0; i < tag_operation_report->tag.epc.size / 2; i++)
{
   uint32_t num = tag_operation_report->tag.epc.bytes[i];
   sprintf(strTemp, "%x ", num);

   // Increase the size of strData
   strDataSize += strlen(strTemp);

   // Allocate more memory for strData.
   strData = realloc(strData, strDataSize + 1);

   // If memory allocation failed, deal with the problem
   if ( strData == NULL )
   {
      exit(EXIT_FAILURE);
   }

   // Add strTemp to strData.
   strcat(strData, strTemp);
}

data = (void *)strData;

// Don't free strData. If you do, data will be dangling pointer.
// free(strData);

答案 1 :(得分:3)

这是一个错误:sprintf(L"%x ", num);

sprintf的第一个参数是一个分配的缓冲区,输出将放入该缓冲区。第二个参数是格式字符串。

因此,您尝试覆盖字符串文字L"%x",并且num也不是有效的格式字符串。你的编译器应该警告你这个错误 - 注意编译器的输出。

执行strTemp =也是一个错误,strTemp += strData也是如此。你不能添加指针,编译器也应该对此发出警告。

另一个错误是data = (void *)strData; free(strData);,这使得data指向释放的内存。

如果你试图连接字符串,那么你将完全以错误的方式处理它。您需要了解指针不是字符串。指针指向指向可能包含字符串的内存区域。您必须考虑已分配的内存块以及指针指向的位置。

答案 2 :(得分:1)

sprintf只修改已分配的内存。您必须将目标缓冲区指针作为第一个参数传递。 http://man7.org/linux/man-pages/man3/sprintf.3.html

如果您不是100%确定输出适合您的缓冲区,最好使用snprintf再接受一个参数来判断缓冲区中剩余的空间。这可以防止sprintf写入错误导致的错误。