用于连接多个字符串的snprintf无法按预期工作

时间:2018-02-11 05:18:36

标签: c string printf

在很多地方已经指出,要连接多个字符串,使用snprintf而不是运行多个strcat运行会更容易也更优雅。但是因为这个原因我得到的结果不正确。在下面的小片段中,它是将12小时转换为24小时的程序的一部分,我首先将hr,min和sec部分分开,然后在转换时间之后,再次重新连接字符串。

这是片段

/*  
char *timestr = strcat(hr, min);
timestr = strcat(timestr, sec);
timestr = strcat(timestr, AMPM);
*/

///*    
char *timestr = (char *)malloc(20);
snprintf(timestr, sizeof(timestr), "%s:%s:%s", hr,min,sec);
//*/

第一个版本工作正常但底部版本没有。这是我用strcat看到的预期输出

(gdb) p timestr
$1 = 0x7fffffffe8cd "190545PM"

这是我用snprintf看到的

(gdb) p timestr
$1 = 0x801007040 "19:05:4"

我无法理解出了什么问题。是不是打印到应该处理尾随NULL字符的流?

3 个答案:

答案 0 :(得分:2)

如果snprintf,如果第二个参数是n,则说明

  

如果生成的字符串长度超过n-1个字符,则剩余的字符将被丢弃而不存储,但会计算该函数返回的值。

那么n的情况如何呢? sizeof(temp)sizeof(char*),与您分配的20个字节不同。您不能将sizeof应用于指针以获取它指向的内存大小。 (在典型系统sizeof(char*)上有所不同)。

解决方案:

snprintf(timestr, 20, "%s:%s:%s", hr,min,sec);

或者如果你把它保存在某个变量中(推荐)。

const int size = 20;
int ret = snprintf(timestr, size, "%s:%s:%s", hr,min,sec);
if( ret < 0){
    fprintf(stderr,"Error in snprintf operation\n");
    exit(1);
}
if( ret >= size){
   fprintf(stderr,"Error: more characters than expected\n");
   exit(1);
}

检查snprintf的返回值,以了解是否返回相同的错误。

答案 1 :(得分:1)

sizeof(timestr)不会返回您已分配的字节数, 它返回指向char的指针需要存储的字节数 在记忆中。正确的电话会是:

char *timestr = malloc(20);
snprintf(timestr, 20, "%s:%s:%s", hr,min,sec);

请注意,snprintf将尝试写入20个字符(包括 0-终止字节)。如果得到的长度不够大,timestr会 裁剪。因此,获得所需的字节数会更好 将NULL和大小0传递给snprintf。在这种情况下,它将返回多少 角色是必需的。所以

int len = snprintf(NULL, 0, "%s:%s:%s", hr, min, sec);
if(len < 0)
{
    fprintf(stderr, "could not execute snprintf\n");
    return; // or whatever, do not continue
}
char *timestr = malloc(len + 1);
if(timestr == NULL)
{
    // error handling
    return; // or whatever, do not continue
}

sprintf(timestr, "%s:%S:%s", hr, min, sec);

会给你字符串的确切字节数。

答案 2 :(得分:0)

您可以使用另一个同级函数asprintf(...)自动分配适当的内存:

char* timestr;
asprintf(&timestr, "%s:%s:%s", hr,min,sec);

原始解决方案不起作用,因为sizeof(char*) == 8(字节)而不是20,它是指针大小本身并且它不依赖于该指针或此指针所指向的内容。