sprintf自己剪切输出字符串

时间:2014-09-21 08:20:19

标签: c

这是我的功能:

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);

4 个答案:

答案 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的问题。

原因是,NameHexCastName内有其本地范围和存储空间,并且将指针传递到函数外部是未定义的行为。

要解决这个问题,你可以通过动态分配存储来使用@YuHao的方法,或者在functino Name之外使用HexCastName并将其指针传递给函数。

答案 3 :(得分:1)

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

你可以让HexCastNamemalloc分配内存并返回,或者你可以让调用者负责传入HexCastName的缓冲区来写入。