2014-09-21 30 views
0

这里是我的功能:的sprintf本身削减输出字符串

char *HexCastName(UINT Address) { 
    char Name[100] = ""; 
    UINT Offset; 
    for (int i = 0; i < HardNames.size(); i++) { 
     if (HardNames[i].Array == Hex.CurrentRegion.Array && 
      HardNames[i].Start <= Address && 
      HardNames[i].Start + HardNames[i].Size > Address) { 
      Offset = Address - HardNames[i].Start; 
      sprintf(Name, " : %s[%d]", HardNames[i].Name, Offset); 
     } 
    } 
    return Name; 
} 

我这样做:

char name[100]; 
sprintf(name, HexCastName(SELECTION_START)); 

结果字符串name只有4位数,虽然HexCastName()回报更多。我试图追踪它,并且它似乎将整个字符串传递给sprintf(),并且在其中的某个位置,它获取到_output_l(outfile,format,NULL,arglist)函数。在里面,format变量最初包含我的整个字符串,然后在读取一些变量后,执行从output.c中的973跳转到978,并且我的format已被截断。我完全被这种行为困惑......为什么4个字母?也许一些指针和字符失败?

编辑:

这里,似乎工作的版本:

void HexCastName(char *buff, UINT size, UINT Address) { 
    sprintf(buff, ""); 
    UINT Offset; 
    for (int i = 0; i < HardNames.size(); i++) { 
     if (HardNames[i].Array == Hex.CurrentRegion.Array && 
      HardNames[i].Start <= Address && 
      HardNames[i].Start + HardNames[i].Size > Address) { 
      Offset = Address - HardNames[i].Start; 
      _snprintf(buff, size, " : %s[%d]",HardNames[i].Name, Offset); 
     } 
    } 
} 

char *name = (char *)malloc(100); 
HexCastName(name, 100, SELECTION_START); 
sprintf(str, "%s: $%06X%s", area, 
    Hex.AddressSelectedFirst + Hex.CurrentRegion.Offset, name); 
free(name); 
+0

您正在返回一个自动存储VAR的地址 - UB。 – 2014-09-21 08:26:08

回答

3

我的C编程语言数组与其他变量具有相同的作用域规则。在您的代码char name[100]将被推送到堆栈,但将返回时将被删除。

char *HexCastName(UINT Address) { 
    char Name[100] = ""; // Here `Name` gets pushed to the stack. 
    UINT Offset; 
    for (int i = 0; i < HardNames.size(); i++) { 
     if (HardNames[i].Array == Hex.CurrentRegion.Array && 
      HardNames[i].Start <= Address && 
      HardNames[i].Start + HardNames[i].Size > Address) { 
      Offset = Address - HardNames[i].Start; 
      sprintf(Name, " : %s[%d]", HardNames[i].Name, Offset); 
     } 
    } 
    return Name; 
    // Here will `Name` be "deleted" as it exits scope, the pointer that is returned will point to garbage memory. 
} 

你有3种选择:

首先是在功能堆中分配的内存Name

char *Name = malloc(100); 

这是不推荐,因为你可以很容易忘记释放返回的指针:

void function() 
{ 
    char *Name = HexCastName(0xDEADBEEF); 
    free(Name); // If you forget to write this you will have a memory leak. Uugh. 
} 

第二种方法:

你可以声明Name静态的。

static char name[100]; 

如果你不知道什么static意味着Name总是会在内存中(如全局变量)。这非常好,因为现在我们不必担心释放它的内存。

但是这种方法也有大缺陷。多个函数调用将修改相同的变量Name。例如:

void function() 
{ 
    char *Name1 = HexCastName(0xDEADBEEF); 
    char *Name2 = HexCastName(0xDEAFCAEF); 
    printf("Name1 = %s\n", Name1); 
    printf("Name2 = %s\n", Name2); 
    // Because we declared `Name` static will both pointers point to the same memory and point to the same string. Not very good. 
} 

这变得更糟,因为函数未声明返回一个const char *但修改char *

第三种解决方案:

第三个解决方案是一个我建议。这是声明HexCastName这样的:

// The user chooses were to write the result. 
void HexCastName(char *NameOut, size_t BufSize, UINT Address) { 
    char NameOut[0] = ""; 
    UINT Offset; 
    for (int i = 0; i < HardNames.size(); i++) { 
     if (HardNames[i].Array == Hex.CurrentRegion.Array && 
      HardNames[i].Start <= Address && 
      HardNames[i].Start + HardNames[i].Size > Address) { 
      Offset = Address - HardNames[i].Start; 
      snprintf(NameOut, " : %s[%d]", BufSize, HardNames[i].Name, Offset); 
     } 
    } 
} 

请注意,我用snprintf而不是常规sprintf。这是因为sprintf容易受到“缓冲区溢出”的影响。如果您想了解更多关于它,你可以检查接受这个问题的答案:sprintf function's buffer overflow?

这个版本被使用这样的:

void function(void) 
{ 
    char Name[100]; 
    HexCastName(Name, sizeof(Name)); 
} 
+0

+1。第三个解决方案是另一个不错的选择,但它也有其缺点:在使用之后,不能像第一个解决方案那样释放Name。 – 2014-09-21 09:33:00

+0

看起来我只需要malloc在主区域,而不是'HexCastName()',所以malloc和free会非常接近,非常明显。 – feos 2014-09-21 09:37:48

+0

@YHHao你也可以调用这样的函数:'char * Name = malloc(100); HexCastName(Name,100);免费(名称);'。 @feos是的,这是这个版本的优点。 – wefwefa3 2014-09-21 09:41:14

3

您在功能HexCastName,这是一个本地数组变量返回Name。函数退出后,它不再指向有效的地方。

相反,使用动态分配:

char *Name = malloc(100); 

记得释放内存当它不使用。

+0

我应该在什么时候释放它? – feos 2014-09-21 08:32:46

+0

@feos当你不再需要它了。 – 2014-09-21 08:33:50

+0

好吧,我想在返回后不需要它,但它在返回后立即退出。它必须存在一段时间才能到达另一个函数的空间,但是之后不再有'Name'变量,要释放什么? – feos 2014-09-21 08:37:32

1

不,这不是sprintf的问题。

原因是,你的Name有其局部范围和存储在HexCastName里面,并且将指针传递给函数外部是未定义的行为。

要解决这个问题,可以通过动态分配存储空间来使用@YooHao的方法,或者在函数外部使用@OyuHao的方法,或者将其指针传递给该函数。

1

HexCastName返回一个指向局部变量的指针。当HexCastName返回时,它指向的内存不再有效,因此您将垃圾传递给sprintf

您可以使HexCastName分配与malloc内存并返回,或者你可以让调用者负责传入缓冲区HexCastName写入。

+0

第二个解决方案听起来很有趣。你能提供一些例子吗?我试过了,并没有弄清楚正确的方法。 – feos 2014-09-21 09:02:36