这是我的功能:
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 :(得分:3)
您正在函数Name
中返回HexCastName
,这是一个本地数组变量。函数退出后,它不再指向有效位置。
相反,请使用动态分配:
char *Name = malloc(100);
请记住在未使用时释放内存。
答案 1 :(得分: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
容易受到&#34;缓冲区溢出&#34;的影响。如果您想了解更多相关信息,可以查看此问题的接受答案:sprintf function's buffer overflow?
此版本的使用方式如下:
void function(void)
{
char Name[100];
HexCastName(Name, sizeof(Name));
}
答案 2 :(得分:1)
不,这不是sprintf
的问题。
原因是,Name
在HexCastName
内有其本地范围和存储空间,并且将指针传递到函数外部是未定义的行为。
要解决这个问题,你可以通过动态分配存储来使用@YuHao的方法,或者在functino Name
之外使用HexCastName
并将其指针传递给函数。
答案 3 :(得分:1)
HexCastName
返回指向局部变量的指针。当HexCastName
返回时,它指向的内存不再有效,因此您将垃圾传递给sprintf
。
你可以让HexCastName
用malloc
分配内存并返回,或者你可以让调用者负责传入HexCastName
的缓冲区来写入。